3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-07 14:54:15 +00:00

Updated to latest version of BIP-0039.

This commit is contained in:
Ken Sedgwick 2013-12-07 14:16:08 -08:00 committed by Mike Hearn
parent 5cd10a537a
commit e86ce7f268
2 changed files with 191 additions and 181 deletions

View File

@ -17,8 +17,6 @@
package com.google.bitcoin.crypto;
import com.google.bitcoin.core.Sha256Hash;
import org.spongycastle.crypto.engines.RijndaelEngine;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.util.encoders.Hex;
import java.io.BufferedReader;
@ -36,10 +34,6 @@ import java.util.List;
* A MnemonicCode object may be used to convert between binary seed values and
* lists of words per <a href="https://en.bitcoin.it/wiki/BIP_0039">the BIP 39
* specification</a>
*
* NOTE - as of 15 Oct 2013 the spec at
* https://en.bitcoin.it/wiki/BIP_0039 is out-of-date. The correct
* spec can be found at https://github.com/trezor/python-mnemonic
*/
public class MnemonicCode {
@ -47,6 +41,8 @@ public class MnemonicCode {
public static String BIP39_ENGLISH_SHA256 = "ad90bf3beb7b0eb7e5acd74727dc0da96e0a280a258354e7293fb7e211ac03db";
private static final int HMAC_ROUNDS = 10000;
public MnemonicCode() throws IOException {
this(MnemonicCode.class.getResourceAsStream("mnemonic/wordlist/english.txt"), BIP39_ENGLISH_SHA256);
}
@ -84,66 +80,89 @@ public class MnemonicCode {
}
/**
* Encodes a 128, 192 or 256 bit seed into a list of words.
* Convert mnemonic word list to seed.
*/
public List<String> encode(byte[] seed) throws MnemonicLengthException {
public static byte[] toSeed(List<String> words, String passphrase) {
// To create binary seed from mnemonic, we use HMAC-SHA512
// function with string "mnemonic" + passphrase (in UTF-8) as
// key and mnemonic sentence (again in UTF-8) as the
// message. We perform 10000 HMAC rounds and use the final
// result as the binary seed.
//
// Pseudocode:
//
// K = "mnemonic" + passphrase
// M = mnemonic_sentence
// for i in 1 ... 10000 do
// M = hmac_sha512(K, M)
// done
// seed = M
byte[] kk = new String("mnemonic" + passphrase).getBytes();
byte[] mm = joinStringList(words).getBytes();
for (int ii = 0; ii < HMAC_ROUNDS; ++ii)
mm = HDUtils.hmacSha512(kk, mm);
return mm;
}
/**
* Convert arbitrary data to mnemonic word list.
*/
public List<String> toMnemonic(byte[] entropy) throws MnemonicLengthException {
if (entropy.length % 4 > 0)
throw new MnemonicLengthException("entropy length not multiple of 32 bits");
// We take initial entropy of ENT bits and compute its
// checksum by taking first ENT / 32 bits of its SHA256 hash.
byte[] hash = Sha256Hash.create(entropy).getBytes();
boolean[] hashBits = bytesToBits(hash);
// 2. Make sure its length (L) is 128, 192 or 256 bits.
int len = seed.length * 8;
if (len != 128 && len != 192 && len != 256)
throw new MnemonicLengthException("seed not 128, 192 or 256 bits");
boolean[] entropyBits = bytesToBits(entropy);
int checksumLengthBits = entropyBits.length / 32;
// 3. Encrypt input data 10000x with Rijndael (ECB mode).
// Set key to SHA256 hash of string ("mnemonic" + user_password).
// Set block size to input size (that's why Rijndael is used, not AES).
byte[] indata = stretch(len, seed);
// We append these bits to the end of the initial entropy.
boolean[] concatBits = new boolean[entropyBits.length + checksumLengthBits];
for (int ii = 0; ii < entropyBits.length; ++ii)
concatBits[ii] = entropyBits[ii];
for (int ii = 0; ii < checksumLengthBits; ++ii)
concatBits[entropyBits.length + ii] = hashBits[ii];
// Convert binary data to array of boolean for processing.
boolean[] inarray = new boolean[indata.length * 8];
for (int ii = 0; ii < indata.length; ++ii)
for (int kk = 0; kk < 8; ++kk)
inarray[(ii * 8) + kk] = (indata[ii] & (1 << (7 - kk))) != 0;
// Next we take these concatenated bits and split them into
// groups of 11 bits. Each group encodes number from 0-2047
// which is a position in a wordlist. We convert numbers into
// words and use joined words as mnemonic sentence.
// 4-6 Compute checksum.
boolean[] chksum = checksum(inarray);
// 7. Concatenate I and C into encoded data (E). Length of E is divisable by 33 bits.
boolean[] ee = new boolean[inarray.length + chksum.length];
for (int ii = 0; ii < inarray.length; ++ii)
ee[ii] = inarray[ii];
for (int ii = 0; ii < chksum.length; ++ii)
ee[inarray.length + ii] = chksum[ii];
// 8. Keep taking 11 bits from E until there are none left.
// 9. Treat them as integer W, add word with index W to the output.
ArrayList<String> words = new ArrayList<String>();
int nwords = ee.length / 11;
int nwords = concatBits.length / 11;
for (int ii = 0; ii < nwords; ++ii) {
int ndx = 0;
for (int kk = 0; kk < 11; ++kk) {
for (int jj = 0; jj < 11; ++jj) {
ndx <<= 1;
if (ee[(ii * 11) + kk])
if (concatBits[(ii * 11) + jj])
ndx |= 0x1;
}
words.add(this.wordList.get(ndx));
}
return words;
return words;
}
/**
* Decodes a list of words into a seed value.
* Check to see if a mnemonic word list is valid.
*/
public byte[] decode(List<String> words) throws MnemonicLengthException, MnemonicWordException, MnemonicChecksumException {
int nwords = words.size();
public void check(List<String> words) throws MnemonicLengthException, MnemonicWordException, MnemonicChecksumException {
if (words.size() % 3 > 0)
throw new MnemonicLengthException("Word list size must be multiple of three words.");
// 2. Make sure the number of words is 12, 18 or 24.
if (nwords != 12 && nwords != 18 && nwords != 24)
throw new MnemonicLengthException("Mnemonic code not 12, 18 or 24 words");
// 3. Figure out word indexes in a dictionary and output them as binary stream E.
int len = nwords * 11;
boolean[] ee = new boolean[len];
// Look up all the words in the list and construct the
// concatenation of the original entropy and the checksum.
//
int concatLenBits = words.size() * 11;
boolean[] concatBits = new boolean[concatLenBits];
int wordindex = 0;
for (String word : words) {
// Find the words index in the wordlist.
@ -153,80 +172,49 @@ public class MnemonicCode {
// Set the next 11 bits to the value of the index.
for (int ii = 0; ii < 11; ++ii)
ee[(wordindex * 11) + ii] = (ndx & (1 << (10 - ii))) != 0;
concatBits[(wordindex * 11) + ii] = (ndx & (1 << (10 - ii))) != 0;
++wordindex;
}
}
// 5. Split E into two parts: B and C, where B are first L/33*32 bits, C are last L/33 bits.
int bblen = (len / 33) * 32;
int cclen = len - bblen;
int checksumLengthBits = concatLenBits / 33;
int entropyLengthBits = concatLenBits - checksumLengthBits;
boolean[] bb = new boolean[bblen];
for (int ii = 0; ii < bblen; ++ii)
bb[ii] = ee[ii];
boolean[] cc = new boolean[cclen];
for (int ii = 0; ii < cclen; ++ii)
cc[ii] = ee[bblen + ii];
// 6. Make sure C is the checksum of B (using the step 5 from the above paragraph).
boolean[] chksum = checksum(bb);
if (!Arrays.equals(chksum, cc))
throw new MnemonicChecksumException("checksum error");
// 8. Treat B as binary data.
byte[] outdata = new byte[bblen / 8];
for (int ii = 0; ii < outdata.length; ++ii)
// Extract original entropy as bytes.
byte[] entropy = new byte[entropyLengthBits / 8];
for (int ii = 0; ii < entropy.length; ++ii)
for (int jj = 0; jj < 8; ++jj)
if (bb[(ii * 8) + jj])
outdata[ii] |= 1 << (7 - jj);
if (concatBits[(ii * 8) + jj])
entropy[ii] |= 1 << (7 - jj);
// 9. Decrypt this data 10000x with Rijndael (ECB mode),
// use the same parameters as used in step 3 of encryption.
byte[] seed = unstretch(bblen, outdata);
// Take the digest of the entropy.
byte[] hash = Sha256Hash.create(entropy).getBytes();
boolean[] hashBits = bytesToBits(hash);
return seed;
// Check all the checksum bits.
for (int ii = 0; ii < checksumLengthBits; ++ii)
if (concatBits[entropyLengthBits + ii] != hashBits[ii])
throw new MnemonicChecksumException("checksum error");
}
private byte[] stretch(int len, byte[] data) {
// 3. Encrypt input data 10000x with Rijndael (ECB mode).
// Set key to SHA256 hash of string ("mnemonic" + user_password).
// Set block size to input size (that's why Rijndael is used, not AES).
byte[] mnemonic = {'m', 'n', 'e', 'm', 'o', 'n', 'i', 'c'};
byte[] key = Sha256Hash.create(mnemonic).getBytes();
byte[] buffer = new byte[data.length];
System.arraycopy(data, 0, buffer, 0, data.length);
RijndaelEngine cipher = new RijndaelEngine(len);
cipher.init(true, new KeyParameter(key));
for (int ii = 0; ii < 10000; ++ii)
cipher.processBlock(buffer, 0, buffer, 0);
return buffer;
private static boolean[] bytesToBits(byte[] data) {
boolean[] bits = new boolean[data.length * 8];
for (int ii = 0; ii < data.length; ++ii)
for (int jj = 0; jj < 8; ++jj)
bits[(ii * 8) + jj] = (data[ii] & (1 << (7 - jj))) != 0;
return bits;
}
private byte[] unstretch(int len, byte[] data) {
// 9. Decrypt this data 10000x with Rijndael (ECB mode),
// use the same parameters as used in step 3 of encryption.
byte[] mnemonic = {'m', 'n', 'e', 'm', 'o', 'n', 'i', 'c'};
byte[] key = Sha256Hash.create(mnemonic).getBytes();
byte[] buffer = new byte[data.length];
System.arraycopy(data, 0, buffer, 0, data.length);
RijndaelEngine cipher = new RijndaelEngine(len);
cipher.init(false, new KeyParameter(key));
for (int ii = 0; ii < 10000; ++ii)
cipher.processBlock(buffer, 0, buffer, 0);
return buffer;
}
private boolean[] checksum(boolean[] bits) {
// 4. Compute the length of the checkum (LC). LC = L/32
int lc = bits.length / 32;
// 5. Split I into chunks of LC bits (I1, I2, I3, ...).
// 6. XOR them altogether and produce the checksum C. C = I1 xor I2 xor I3 ... xor In.
boolean[] cc = new boolean[lc];
for (int ii = 0; ii < 32; ++ii)
for (int jj = 0; jj < lc; ++jj)
cc[jj] ^= bits[(ii * lc) + jj];
return cc;
static private String joinStringList(List<String> list) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (String item : list)
{
if (first)
first = false;
else
sb.append(" ");
sb.append(item);
}
return sb.toString();
}
}

View File

@ -29,80 +29,103 @@ import java.util.List;
import static org.junit.Assert.assertEquals;
public class MnemonicCodeTest {
// These vectors are from https://raw.github.com/trezor/python-mnemonic/master/vectors.json
// These vectors are from https://github.com/trezor/python-mnemonic/blob/master/vectors.json
String vectors[] = {
"00000000000000000000000000000000",
"risk tiger venture dinner age assume float denial penalty hello game wing",
"00000000000000000000000000000000",
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
"cb5e7230ce8229de990674f6aa4288325fd4d8181f761734bd8b5cc944fedc2a4300e64422864b565352de7ffbc5ad0fafdf5344489f3a83e4a4bb5271cafaae",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"truth chase learn pretty right casual acoustic frozen betray main slogan method",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"legal winner thank year wave sausage worth useful legal winner thank yellow",
"de1277934939d6969519f44b7b3757a905d7f635be41e1e88022c346bc52ad26c0a3e9578e73e9b89066873266f285a5891d27d28cb27fccfe26d92bbd7ee364",
"80808080808080808080808080808080",
"olive garment twenty drill people finish hat own usual level milk usage",
"80808080808080808080808080808080",
"letter advice cage absurd amount doctor acoustic avoid letter advice cage above",
"8863bccef9cfffeacef1e4c6fc97bba8227ab0fc7e8e162be7467282689a13521ea364d7c4bc8cd241b59f53c5147a89c18a47248a96592ab9a2c1f1870b026c",
"ffffffffffffffffffffffffffffffff",
"laundry faint system client frog vanish plug shell slot cable large embrace",
"ffffffffffffffffffffffffffffffff",
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong",
"7a29e57c7a1532af1bddb7e02b892cfccc6a57b74fe9784324ea89fab8a66dc64fde79c31166b159685116f4e93c1795496f20ffdc2d3a69d3439931dabde86e",
"000000000000000000000000000000000000000000000000",
"giant twelve seat embark ostrich jazz leader lunch budget hover much weapon vendor build truth garden year list",
"000000000000000000000000000000000000000000000000",
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent",
"c3e382025b6a22a901505cf393faea450eb6c4a5f2a8c8f0596285b2bd84688877a6cc7231420e2bbdd2428e62ed549a78fa215b3adafd8dea075dabfc704d5e",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"awful faint gun mean fuel side slogan marine glad donkey velvet oyster movie real type digital dress federal",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will",
"c82666e40eb097bf6eb05fecd7dc2ddfb6bbdc6071900f4b3fd3c3e635db69aa2094f1f450c98e8dc6103aa72df635abdfcc3b6d6ec5261a9208a07a35a3f1c8",
"808080808080808080808080808080808080808080808080",
"bless carpet daughter animal hospital pave faculty escape fortune song sign twin unknown bread mobile normal agent use",
"808080808080808080808080808080808080808080808080",
"letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always",
"e90681c67c55504afadca009ce4042819341fa0e90300b6d32b4f2e8e8a6678ff7e7fc1da663ae194dc7a2ef7ec7b50112d1a5efce47bfd00c66eec82f2265b5",
"ffffffffffffffffffffffffffffffffffffffffffffffff",
"saddle curve flight drama client resemble venture arch will ordinary enrich clutch razor shallow trophy tumble dice outer",
"ffffffffffffffffffffffffffffffffffffffffffffffff",
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when",
"2a372547df962742942674170a7cef495ea0b97f4864de16d0f3ee82eb577ca1eca345e601cc2df7c626c5bc51c52c28a3b4294224b685c958c7450bee6769e6",
"0000000000000000000000000000000000000000000000000000000000000000",
"supreme army trim onion neglect coach squirrel spider device glass cabbage giant web digital floor able social magnet only fork fuel embrace salt fence",
"0000000000000000000000000000000000000000000000000000000000000000",
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art",
"58cb9c5555d67ecc7b32305a78d1a2fcf0c9b22f1af761cfafc65eb1d3909f63ee2cab84996a7478cfd3e864cda5efb0caf580d56cf49739c6b3638d94e758c1",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"cloth video uncle switch year captain artist country adjust edit inherit ocean tennis soda baby express hospital forest panel actual profit boy spice elite",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title",
"0093cb3ed6d1302d3cf498017f8cb1c7dc2fdbd62ec57fc49e4b2a4dd47a23e44e0b309517d5a3e7b0f4f0ef0ed132818cf120a098a92e572ad086f1a90ccb7f",
"8080808080808080808080808080808080808080808080808080808080808080",
"fence twin prize extra choose mask twist deny cereal quarter can power term ostrich leg staff nature nut swift sausage amateur aim script wisdom",
"8080808080808080808080808080808080808080808080808080808080808080",
"letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless",
"8a21e46b9d264328c63e707e3d38ed4eb21508deda309fa2ef57cc8eca8b351ca3018758844ba9fb5851bab15d026a61cabace53a9a39bc91dc2c51407542cf5",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"moon fiscal evidence exile rifle series neglect giant exclude banana glance frown kangaroo globe turtle hat fitness casual sudden select idle arctic best unlock",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote",
"5c8a1a284ab2844daf02cab322df3996574c9d53cbd36159c493441990f0d2a6bc9bc1502e3a067943d8ec67324663cbfb9667b57fed220e3f28335e26a90f93",
"449ea2d7249c6e0d8d295424fb8894cf",
"choice barrel artefact cram increase sell veteran matrix mirror hollow walk pave",
"1083fa24dbb0afa4e7b327d23f666567",
"awesome cabin matrix resist april sponsor paddle gossip split will off soon",
"467406b36a0176e40e013393e5ecef1f5b4019980b502eda9db1db06f7786e088b206f045f2bfcf93bd3b17a598335b078fcc5890115857ff741bd154b54f049",
"75fc3f44a7ff8e2b8af05aa18bded3827a3796df406763dd",
"crack outside teach chat praise client manual scorpion predict chalk decrease casino lunch garbage enable ball when bamboo",
"d8cbcd1ac2153ecd74048480c2732f637d642b21f0dd40df",
"sugar fury effort loud fault grit source mountain liar bean slim shoulder stone better march brick dolphin zero",
"f60180ea5047659cbb17ed6ef79c974de86c0170c7a1962b205329eb8fe9dcdd148615d35c515c4ec8da25f4cf54d5b7cd8cd5bf8dc4059df3a7900ca25f8306",
"1cce2f8c2c6a7f2d8473ebf1c32ce13b36737835d7a8768f44dcf96d64782c0e",
"muffin evoke all fiber night guard black quote neck expire dial tenant leisure have dragon neck notable peace captain insane nice uphold shine angry",
"2952f95cefe041616f6f379ab649cf8b702ecf8e4acceaebdda4cc50e2bf1d7b",
"citizen oak fire thank advice radar sad tragic one rather initial black actual guitar decrease flower turtle galaxy hard obvious athlete garbage invest have",
"eff4b6a15bb55fcf4bbfa2b3b9e24e7dc4bed8319ef7703f1786d472c73666922925778eaa5a06f8a26d2c7e7240be746fd69edfaf197e0dae12d7e0b550cfc8",
"3daa82dd08bd144ec9fb9f77c6ece3d2",
"foil dawn net enroll turtle bird vault trumpet service fun immune unveil",
"f5e82717078a6ddc538a03e825f91bed",
"vote donkey shift audit plug until evolve document trial cool eight swarm",
"83dad22293225780a914083fc1a69bfe1d910f5b5962b0364820132a42ae1bd567a1fb4d5a19ad3d64539e38a7ee3d6429fac2b74e72b020913131c5eadb7db4",
"9720239c0039f8446d44334daec325f3c24b3a490315d6d9",
"damp all desert dash insane pear debate easily soup enough goddess make friend plug violin pact wealth insect",
"16b59b6a426f2f302f73049a32ab8572394278982212357a",
"birth proud surround luggage very object saddle gauge olive next throw tongue neither detail gauge drastic cube strategy",
"38ceb07e0dad221f612631843be6ae44a650aaf789c8ebea9313e07498d7864385227d25c7a8268a5b850367eef31639632e9218acadead20980b864b1cd477e",
"fe58c6644bc3fad95832d4400cea0cce208c8b19bb4734a26995440b7fae7600",
"wet sniff asthma once gap enrich pumpkin define trust rude gesture keen grass fine emerge census immense smooth ritual spirit rescue problem beef choice",
"95b6cb48c7bc9c2a54496ae3eea790824b57e52b9637058f084555bc1b809b2f",
"noble rent split month six benefit eye coil token inside tomorrow afraid rely verb purity shoulder airport joke bacon problem script scare hole trumpet",
"e33e3d32e467877596a18ac60050488a0ec1557fda6bf95bad3d33d964c5e99dcd97d378403cc2723ed1c85c12b42bc59f15458d970d7a9d015f556109c146b0",
"99fe82c94edadffe75e1cc64cbd7ada7",
"thing real emerge verify domain cloud lens teach travel radio effort glad",
"7f93397f750f70a26513de2732ed95ee",
"legend oil garlic tube warfare eye nephew knock cheese number grace tackle",
"7f92ad63e4cdf4f15c23740556ad81e7f8cbd67cc672c93894c9c0d4fb171539eed5ab29f366570ed9940b816f45a539c3816f7ac19511794b752c5c1ec0e732",
"4fd6e8d06d55b4700130f8f462f7f9bfc6188da83e3faadb",
"diary opinion lobster code orange odor insane permit spirit evolve upset final antique grant friend dutch say enroll",
"14c29fe840dd1c9f05d392ba13e4e1466b32ed0726a15f89",
"below belt wheel like spike exhibit blanket inch ring palace debate mimic rebel isolate broken stage garbage enhance",
"7bae6e54f8bad645f18f574b310bd3e6fde126dabcaf63a889940380e4798810e48c8151fc56bb2389c07498deacef025f03cbf8fc57ea3ec68f6421b0fcb649",
"7a547fb59606e89ba88188013712946f6cb31c3e0ca606a7ee1ff23f57272c63",
"layer owner legal stadium glance oyster element spell episode eager wagon stand pride old defense black print junior fade easy topic ready galaxy debris",
"cb30610d175ffeab8357d5190d31923997752a7f9815087bfcad5eb0b43f6468",
"sleep loan drive concert zoo fiction ask wide boil hat goose industry jar news wrist actor anchor that clip runway area cabbage museum abuse",
"b922030609e7626696b9cf5ca4c06cd99290be30b1052770f6a60c5f26532d178f287a4285d7a2add2845dc89a816b26fdba1c830067d130740f64c0ab5cfbe1",
"e5fc62d20e0e5d9b2756e8d4d91cbb80",
"flat make unit discover rifle armed unit acquire group panel nerve want",
"a30b50a5439dcd1774f412ea5ec33403",
"perfect fold citizen mango system merry stable liquid tumble voyage snack alter",
"aae175f26848370c4d5d3d0640597e2bf1b28e95908dd877259b3eac5d71ffe3140739a3ed80180f88159571df84441985620e6b2fb0696e5cba1aa7b8d10b98",
"d29be791a9e4b6a48ff79003dbf31d6afabdc4290a273765",
"absurd valve party disorder basket injury make blanket vintage ancient please random theory cart retire odor borrow belt",
"70044da2175ad681d0ebbf2da83cf407eb9c8fd91fc0a8c9",
"hybrid carbon hammer concert pulp domain dry jewel color draft dial average right elevator good way potato energy",
"a3dffe3a31a2e949d1b04af7495a5b59db17e41d93b985feeaaae89260a9c86c6dcdf7cb32eaba61c2f4f0340f0f17d1ebb67af11657286b2ffd66ec4e05a8b7",
"c87c135433c16f1ecbf9919dc53dd9f30f85824dc7264d4e1bd644826c902be2",
"upper will wisdom term once bean blur inquiry used bamboo frequent hamster amazing cake attack any author mimic leopard day token joy install company",
"0e0bab4df9669b97ba3f75a50b2e92423bbe6e91a1b01dbbf3ba200a917c9106",
"asthma front square version have slim trophy upgrade pink floor pig love room dance educate current buffalo test update divorce poverty salad dune scheme",
"2eb4d85fbd8deaf9b06bf9cdb3e5f36e8da040d110312075eb32e776fc8e505b94be3e63c1525ad41f5e5968a263853001dc7c40ea3af8e8b0cfb7effd5f408c",
};
private MnemonicCode mc;
@ -112,43 +135,42 @@ public class MnemonicCodeTest {
}
@Test
public void testEncodeVectors() throws Exception {
for (int ii = 0; ii < vectors.length; ii += 2) {
List<String> words = mc.encode(Hex.decode(vectors[ii]));
assertEquals(vectors[ii + 1], Joiner.on(' ').join(words));
}
}
public void testVectors() throws Exception {
for (int ii = 0; ii < vectors.length; ii += 3) {
String vecData = vectors[ii];
String vecCode = vectors[ii+1];
String vecSeed = vectors[ii+2];
@Test
public void testDecodeVectors() throws Exception {
for (int ii = 0; ii < vectors.length; ii += 2) {
byte[] seed = mc.decode(split(vectors[ii+1]));
assertEquals(vectors[ii], new String(Hex.encode(seed)));
List<String> code = mc.toMnemonic(Hex.decode(vecData));
byte[] seed = MnemonicCode.toSeed(code, "TREZOR");
assertEquals(vecCode, Joiner.on(' ').join(code));
assertEquals(vecSeed, new String(Hex.encode(seed)));
}
}
@Test(expected = MnemonicLengthException.class)
public void testBadSeedLength() throws Exception {
byte[] seed = Hex.decode("7f7f7f7f7f7f7f7f7f7f7f7f7f7f");
mc.encode(seed);
public void testBadEntropyLength() throws Exception {
byte[] entropy = Hex.decode("7f7f7f7f7f7f7f7f7f7f7f7f7f7f");
mc.toMnemonic(entropy);
}
@Test(expected = MnemonicLengthException.class)
public void testBadLength() throws Exception {
List<String> words = split("risk tiger venture dinner age assume float denial penalty");
mc.decode(words);
List<String> words = split("risk tiger venture dinner age assume float denial penalty hello");
mc.check(words);
}
@Test(expected = MnemonicWordException.class)
public void testBadWord() throws Exception {
List<String> words = split("risk tiger venture dinner xyzzy assume float denial penalty hello game wing");
mc.decode(words);
mc.check(words);
}
@Test(expected = MnemonicChecksumException.class)
public void testBadChecksum() throws Exception {
List<String> words = split("risk tiger venture dinner age assume float denial penalty hello game game");
mc.decode(words);
List<String> words = split("bless cloud wheel regular tiny venue bird web grief security dignity zoo");
mc.check(words);
}
static public List<String> split(String words) {