package com.greenaddress.greenbits.ui;
import com.blockstream.libwally.Wally;
import com.google.common.base.Charsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MnemonicHelper {
private static int levenshteinDistance(final String sA, final String sB) {
final int s1 = sA.length() + 1;
final int s2 = sB.length() + 1;
int[] c = new int[s1];
int[] nc = new int[s1];
for (int j = 0; j < s1; ++j) c[j] = j;
for (int j = 1; j < s2; ++j) {
nc[0] = j;
for(int k = 1; k < s1; ++k)
nc[k] = Math.min(Math.min(c[k] + 1, nc[k - 1] + 1), c[k - 1]
+ ((sA.charAt(k - 1) == sB.charAt(j - 1)) ? 0 : 1));
final int[] swap = c; c = nc; nc = swap;
}
return c[s1 - 1];
}
static boolean isInvalidWord(final ArrayList<String> words, final String word, final boolean equals) {
for (final String w : words) {
if ((!equals && w.startsWith(word)) ||
(equals && w.equals(word))) {
return false;
}
}
return true;
}
public static byte[] decryptMnemonic(final byte[] entropy, final String normalizedPassphrase) {
final byte[] salt = Arrays.copyOfRange(entropy, 32, 36);
final byte[] encrypted = Arrays.copyOf(entropy, 32);
final byte[] derived = new byte[64];
Wally.scrypt(normalizedPassphrase.getBytes(Charsets.UTF_8), salt, 16384, 8, 8, derived);
final byte[] key = Arrays.copyOfRange(derived, 32, 64);
final byte[] decrypted = new byte[32];
Wally.aes(key, encrypted, Wally.AES_FLAG_DECRYPT, decrypted);
for (int i = 0; i < 32; ++i)
decrypted[i] ^= derived[i];
if (!Arrays.equals(Arrays.copyOf(Wally.sha256d(decrypted, null), 4), salt))
throw new RuntimeException("Invalid checksum");
return decrypted;
}
static String getClosestWord(final ArrayList<String> words, final String word) {
final List<Integer> scores = new ArrayList<>(words.size());
for (final String w : words) {
scores.add(levenshteinDistance(word, w));
}
Integer min = Integer.MAX_VALUE;
final List<Integer> matches = new ArrayList<>();
for (int i = 0; i < words.size(); ++i) {
final Integer score = scores.get(i);
if (score.compareTo(min) < 0) {
min = score;
matches.clear();
matches.add(i);
} else if (score.compareTo(min) == 0) {
matches.add(i);
}
}
for (final Integer m : matches) {
final String match = words.get(m);
// give preference to words that start with our word
if (match.startsWith(word)) {
return match;
}
}
for (final Integer m : matches) {
final String match = words.get(m);
// give preference to words that end with our word
if (match.endsWith(word)) {
return match;
}
}
return words.get(matches.get(0));
}
}