3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-01-31 15:22:16 +00:00

Update to latest version of mnemonic code spec from the Trezor team.

This commit is contained in:
Ken Sedgwick 2013-12-17 15:02:05 -08:00 committed by Mike Hearn
parent 8cc1920fa2
commit 29e2af7ec0
7 changed files with 457 additions and 251 deletions

View File

@ -1,35 +0,0 @@
/*
* Copyright 2013 Ken Sedgwick
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.bitcoin.crypto;
/**
* Thrown when a list of MnemonicCode words fails the checksum check.
*/
@SuppressWarnings("serial")
public class MnemonicChecksumException extends Exception {
public MnemonicChecksumException(String msg) {
super(msg);
}
public MnemonicChecksumException(Exception e) {
super(e);
}
public MnemonicChecksumException(String msg, Exception e) {
super(msg, e);
}
}

View File

@ -25,6 +25,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -41,7 +42,7 @@ public class MnemonicCode {
public static String BIP39_ENGLISH_SHA256 = "ad90bf3beb7b0eb7e5acd74727dc0da96e0a280a258354e7293fb7e211ac03db";
private static final int HMAC_ROUNDS = 10000;
private static final int PBKDF2_ROUNDS = 4096;
public MnemonicCode() throws IOException {
this(MnemonicCode.class.getResourceAsStream("mnemonic/wordlist/english.txt"), BIP39_ENGLISH_SHA256);
@ -84,36 +85,73 @@ public class MnemonicCode {
*/
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.
// To create binary seed from mnemonic, we use PBKDF2 function
// with mnemonic sentence (in UTF-8) used as a password and
// string "mnemonic" + passphrase (again in UTF-8) used as a
// salt. Iteration count is set to 4096 and HMAC-SHA512 is
// used as a pseudo-random function. Desired length of the
// derived key is 512 bits (= 64 bytes).
//
// Pseudocode:
String pass = joinStringList(words);
String salt = new String("mnemonic" + passphrase);
byte[] hash = PBKDF2SHA512.derive(pass, salt, PBKDF2_ROUNDS, 64);
return hash;
}
/**
* Convert mnemonic word list to original entropy value.
*/
public byte[] toEntropy(List<String> words) throws MnemonicException.MnemonicLengthException, MnemonicException.MnemonicWordException, MnemonicException.MnemonicChecksumException {
if (words.size() % 3 > 0)
throw new MnemonicException.MnemonicLengthException("Word list size must be multiple of three words.");
// Look up all the words in the list and construct the
// concatenation of the original entropy and the checksum.
//
// K = "mnemonic" + passphrase
// M = mnemonic_sentence
// for i in 1 ... 10000 do
// M = hmac_sha512(K, M)
// done
// seed = M
int concatLenBits = words.size() * 11;
boolean[] concatBits = new boolean[concatLenBits];
int wordindex = 0;
for (String word : words) {
// Find the words index in the wordlist.
int ndx = Collections.binarySearch(this.wordList, word);
if (ndx < 0)
throw new MnemonicException.MnemonicWordException("\"" + word + "\" invalid", word);
byte[] kk = new String("mnemonic" + passphrase).getBytes();
byte[] mm = joinStringList(words).getBytes();
// Set the next 11 bits to the value of the index.
for (int ii = 0; ii < 11; ++ii)
concatBits[(wordindex * 11) + ii] = (ndx & (1 << (10 - ii))) != 0;
++wordindex;
}
for (int ii = 0; ii < HMAC_ROUNDS; ++ii)
mm = HDUtils.hmacSha512(kk, mm);
int checksumLengthBits = concatLenBits / 33;
int entropyLengthBits = concatLenBits - checksumLengthBits;
return mm;
// 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 (concatBits[(ii * 8) + jj])
entropy[ii] |= 1 << (7 - jj);
// Take the digest of the entropy.
byte[] hash = Sha256Hash.create(entropy).getBytes();
boolean[] hashBits = bytesToBits(hash);
// Check all the checksum bits.
for (int ii = 0; ii < checksumLengthBits; ++ii)
if (concatBits[entropyLengthBits + ii] != hashBits[ii])
throw new MnemonicException.MnemonicChecksumException("checksum error");
return entropy;
}
/**
* Convert entropy data to mnemonic word list.
*/
public List<String> toMnemonic(byte[] entropy) throws MnemonicLengthException {
public List<String> toMnemonic(byte[] entropy) throws MnemonicException.MnemonicLengthException {
if (entropy.length % 4 > 0)
throw new MnemonicLengthException("entropy length not multiple of 32 bits");
throw new MnemonicException.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.
@ -154,46 +192,8 @@ public class MnemonicCode {
/**
* Check to see if a mnemonic word list is valid.
*/
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.");
// 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.
int ndx = Collections.binarySearch(this.wordList, word);
if (ndx < 0)
throw new MnemonicWordException("\"" + word + "\" invalid", word);
// Set the next 11 bits to the value of the index.
for (int ii = 0; ii < 11; ++ii)
concatBits[(wordindex * 11) + ii] = (ndx & (1 << (10 - ii))) != 0;
++wordindex;
}
int checksumLengthBits = concatLenBits / 33;
int entropyLengthBits = concatLenBits - checksumLengthBits;
// 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 (concatBits[(ii * 8) + jj])
entropy[ii] |= 1 << (7 - jj);
// Take the digest of the entropy.
byte[] hash = Sha256Hash.create(entropy).getBytes();
boolean[] hashBits = bytesToBits(hash);
// Check all the checksum bits.
for (int ii = 0; ii < checksumLengthBits; ++ii)
if (concatBits[entropyLengthBits + ii] != hashBits[ii])
throw new MnemonicChecksumException("checksum error");
public void check(List<String> words) throws MnemonicException.MnemonicLengthException, MnemonicException.MnemonicWordException, MnemonicException.MnemonicChecksumException {
toEntropy(words);
}
private static boolean[] bytesToBits(byte[] data) {

View File

@ -0,0 +1,87 @@
/*
* Copyright 2013 Ken Sedgwick
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.bitcoin.crypto;
/**
* Exceptions thrown by the MnemonicCode module.
*/
@SuppressWarnings("serial")
public class MnemonicException extends Exception {
public MnemonicException(String msg) {
super(msg);
}
public MnemonicException(Exception ex) {
super(ex);
}
public MnemonicException(String msg, Exception ex) {
super(msg, ex);
}
/**
* Thrown when an argument to MnemonicCode is the wrong length.
*/
public static class MnemonicLengthException extends MnemonicException {
public MnemonicLengthException(String msg) {
super(msg);
}
public MnemonicLengthException(Exception ex) {
super(ex);
}
public MnemonicLengthException(String msg, Exception ex) {
super(msg, ex);
}
}
/**
* Thrown when a list of MnemonicCode words fails the checksum check.
*/
public static class MnemonicChecksumException extends MnemonicException {
public MnemonicChecksumException(String msg) {
super(msg);
}
public MnemonicChecksumException(Exception ex) {
super(ex);
}
public MnemonicChecksumException(String msg, Exception ex) {
super(msg, ex);
}
}
/**
* Thrown when a word is encountered which is not in the MnemonicCode's word list.
*/
public static class MnemonicWordException extends MnemonicException {
/** Contains the word that was not found in the word list. */
public String badWord;
public MnemonicWordException(String msg, String badWord) {
super(msg);
this.badWord = badWord;
}
public MnemonicWordException(String badWord, Exception ex) {
super(ex);
this.badWord = badWord;
}
public MnemonicWordException(String msg, String badWord, Exception ex) {
super(msg, ex);
this.badWord = badWord;
}
public String getBadWord() {
return badWord;
}
}
}

View File

@ -1,35 +0,0 @@
/*
* Copyright 2013 Ken Sedgwick
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.bitcoin.crypto;
/**
* Thrown when an argument to MnemonicCode is the wrong length.
*/
@SuppressWarnings("serial")
public class MnemonicLengthException extends Exception {
public MnemonicLengthException(String msg) {
super(msg);
}
public MnemonicLengthException(Exception e) {
super(e);
}
public MnemonicLengthException(String msg, Exception e) {
super(msg, e);
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright 2013 Ken Sedgwick
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.bitcoin.crypto;
/**
* Thrown when a word is encountered which is not in the MnemonicCode's word list.
*/
@SuppressWarnings("serial")
public class MnemonicWordException extends Exception {
/** Contains the word that was not found in the word list. */
public String badWord;
public MnemonicWordException(String msg, String badWord) {
super(msg);
this.badWord = badWord;
}
public MnemonicWordException(String badWord, Exception e) {
super(e);
this.badWord = badWord;
}
public MnemonicWordException(String msg, String badWord, Exception e) {
super(msg, e);
this.badWord = badWord;
}
public String getBadWord() {
return badWord;
}
}

View File

@ -0,0 +1,232 @@
/*
* Copyright (c) 2012 Cole Barnes [cryptofreek{at}gmail{dot}com]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* -----------------------------------------------------------------------------
*
* This is a clean-room implementation of PBKDF2 using RFC 2898 as a reference.
*
* RFC 2898:
* http://tools.ietf.org/html/rfc2898#section-5.2
*
* This code passes all RFC 6070 test vectors:
* http://tools.ietf.org/html/rfc6070
*
* The function "nativeDerive()" is supplied as an example of the native Java
* PBKDF2WithHmacSHA1 implementation. It is used for benchmarking and
* comparison only.
*
* The functions "fromHex()" and "toHex()" came from some message board
* somewhere. No license was included.
*
* http://cryptofreek.org/2012/11/29/pbkdf2-pure-java-implementation/
* Modified to use SHA-512 - Ken Sedgwick ken@bonsai.com
*/
package com.google.bitcoin.crypto;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.spec.KeySpec;
import java.util.Formatter;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class PBKDF2SHA512
{
/* START RFC 2898 IMPLEMENTATION */
public static byte[] derive(String P, String S, int c, int dkLen)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
{
int hLen = 20;
if (dkLen > ((Math.pow(2, 32)) - 1) * hLen)
{
System.out.println("derived key too long");
}
else
{
int l = (int) Math.ceil((double) dkLen / (double) hLen);
// int r = dkLen - (l-1)*hLen;
for (int i = 1; i <= l; i++)
{
byte[] T = F(P, S, c, i);
baos.write(T);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
byte[] baDerived = new byte[dkLen];
System.arraycopy(baos.toByteArray(), 0, baDerived, 0, baDerived.length);
return baDerived;
}
private static byte[] F(String P, String S, int c, int i) throws Exception
{
byte[] U_LAST = null;
byte[] U_XOR = null;
SecretKeySpec key = new SecretKeySpec(P.getBytes("UTF-8"), "HmacSHA512");
Mac mac = Mac.getInstance(key.getAlgorithm());
mac.init(key);
for (int j = 0; j < c; j++)
{
if (j == 0)
{
byte[] baS = S.getBytes("UTF-8");
byte[] baI = INT(i);
byte[] baU = new byte[baS.length + baI.length];
System.arraycopy(baS, 0, baU, 0, baS.length);
System.arraycopy(baI, 0, baU, baS.length, baI.length);
U_XOR = mac.doFinal(baU);
U_LAST = U_XOR;
mac.reset();
}
else
{
byte[] baU = mac.doFinal(U_LAST);
mac.reset();
for (int k = 0; k < U_XOR.length; k++)
{
U_XOR[k] = (byte) (U_XOR[k] ^ baU[k]);
}
U_LAST = baU;
}
}
return U_XOR;
}
private static byte[] INT(int i)
{
ByteBuffer bb = ByteBuffer.allocate(4);
bb.order(ByteOrder.BIG_ENDIAN);
bb.putInt(i);
return bb.array();
}
/* END RFC 2898 IMPLEMENTATION */
/* START HELPER FUNCTIONS */
private static String toHex(byte[] ba)
{
String strHex = null;
if (ba != null)
{
StringBuilder sb = new StringBuilder(ba.length * 2);
Formatter formatter = new Formatter(sb);
for (byte b : ba)
{
formatter.format("%02x", b);
}
formatter.close();
strHex = sb.toString().toLowerCase();
}
return strHex;
}
private static byte[] nativeDerive(String strPassword, String strSalt, int nIterations, int nKeyLen)
{
byte[] baDerived = null;
try
{
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec ks = new PBEKeySpec(strPassword.toCharArray(), strSalt.getBytes("UTF-8"), nIterations, nKeyLen * 8);
SecretKey s = f.generateSecret(ks);
baDerived = s.getEncoded();
}
catch (Exception e)
{
e.printStackTrace();
}
return baDerived;
}
/* END HELPER FUNCTIONS */
public static void runTestVector(String P, String S, int c, int dkLen, String strExpectedDk)
{
System.out.println("Input:");
System.out.println(" P = \"" + P + "\"");
System.out.println(" S = \"" + S + "\"");
System.out.println(" c = " + c);
System.out.println(" dkLen = " + dkLen);
System.out.println();
long nStartDk = System.nanoTime();
byte[] DK = derive(P, S, c, dkLen);
long nStopDk = System.nanoTime();
long nStartDkNative = System.nanoTime();
byte[] DK_NATIVE = nativeDerive(P, S, c, dkLen);
long nStopDkNative = System.nanoTime();
System.out.println("Output:");
System.out.println(" DK = " + toHex(DK));
System.out.println(" DK_NATIVE = " + toHex(DK_NATIVE));
System.out.println(" DK_EXPECTED = " + strExpectedDk.replaceAll(" ", ""));
System.out.println();
System.out.println("Duration [my implementation]: " + (nStopDk - nStartDk) + " ns" );
System.out.println("Duration [native implementation]: " + (nStopDkNative - nStartDkNative) + " ns" );
System.out.println("---------------------------------------------------------------");
System.out.println();
}
public static void RFC6070()
{
runTestVector("password", "salt", 1, 20, "0c 60 c8 0f 96 1f 0e 71 f3 a9 b5 24 af 60 12 06 2f e0 37 a6");
runTestVector("password", "salt", 2, 20, "ea 6c 01 4d c7 2d 6f 8c cd 1e d9 2a ce 1d 41 f0 d8 de 89 57");
runTestVector("password", "salt", 4096, 20, "4b 00 79 01 b7 65 48 9a be ad 49 d9 26 f7 21 d0 65 a4 29 c1");
runTestVector("password", "salt", 16777216, 20, "ee fe 3d 61 cd 4d a4 e4 e9 94 5b 3d 6b a2 15 8c 26 34 e9 84");
runTestVector("passwordPASSWORDpassword", "saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 25, "3d 2e ec 4f e4 1c 84 9b 80 c8 d8 36 62 c0 e4 4a 8b 29 1a 96 4c f2 f0 70 38");
runTestVector("pass\0word", "sa\0lt", 4096, 16, "56 fa 6a a7 55 48 09 9d cc 37 d7 f0 34 25 e0 c3");
}
public static void main(String[] args)
{
RFC6070();
}
}

View File

@ -31,101 +31,101 @@ import static org.junit.Assert.assertEquals;
public class MnemonicCodeTest {
// These vectors are from https://github.com/trezor/python-mnemonic/blob/master/vectors.json
String vectors[] = {
"00000000000000000000000000000000",
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
"cb5e7230ce8229de990674f6aa4288325fd4d8181f761734bd8b5cc944fedc2a4300e64422864b565352de7ffbc5ad0fafdf5344489f3a83e4a4bb5271cafaae",
"00000000000000000000000000000000",
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
"3d39670caaa237f5fb2999474413733b59d9dfe12b2cccfe878069a2f605ae467a669619a0a45c7b3378c4c812b80be677c1b8f8f60db9383f1ed265c45eb41c",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"legal winner thank year wave sausage worth useful legal winner thank yellow",
"de1277934939d6969519f44b7b3757a905d7f635be41e1e88022c346bc52ad26c0a3e9578e73e9b89066873266f285a5891d27d28cb27fccfe26d92bbd7ee364",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"legal winner thank year wave sausage worth useful legal winner thank yellow",
"34eb04e0d4d60d00217f1c0150d8b0d6ffc6086e365a8a94fcceae8614e38274e719ebe7a693356426d1c62fdf90c84eaaac3d920743f3e79e0970a295886a08",
"80808080808080808080808080808080",
"letter advice cage absurd amount doctor acoustic avoid letter advice cage above",
"8863bccef9cfffeacef1e4c6fc97bba8227ab0fc7e8e162be7467282689a13521ea364d7c4bc8cd241b59f53c5147a89c18a47248a96592ab9a2c1f1870b026c",
"80808080808080808080808080808080",
"letter advice cage absurd amount doctor acoustic avoid letter advice cage above",
"acd45eb0b06e53d2e0fa6d1b3e8b3c33f200d2be6013fc5f8796c8c1d238552a615a01f325d78a10e633991d92f1236e21c24afe7c679fa1ecbc67fe71a5337d",
"ffffffffffffffffffffffffffffffff",
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong",
"7a29e57c7a1532af1bddb7e02b892cfccc6a57b74fe9784324ea89fab8a66dc64fde79c31166b159685116f4e93c1795496f20ffdc2d3a69d3439931dabde86e",
"ffffffffffffffffffffffffffffffff",
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong",
"d20f4e7902c3fd2f7716a533b131042036e6df2e44b14c8d65eb57403d002e4a12fa9be5325b257637ad1209e850188ffb061b3033a315b236ffc70c4ab4ea96",
"000000000000000000000000000000000000000000000000",
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent",
"c3e382025b6a22a901505cf393faea450eb6c4a5f2a8c8f0596285b2bd84688877a6cc7231420e2bbdd2428e62ed549a78fa215b3adafd8dea075dabfc704d5e",
"000000000000000000000000000000000000000000000000",
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent",
"55fb6d9683e16f71025b73efa1a297d522010e37a4fc5b54770b09173e4f7fed85f83b075142965015d17c8f7a365e589ac943ed83cfbf76dcaf301c6c53b9d6",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will",
"c82666e40eb097bf6eb05fecd7dc2ddfb6bbdc6071900f4b3fd3c3e635db69aa2094f1f450c98e8dc6103aa72df635abdfcc3b6d6ec5261a9208a07a35a3f1c8",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will",
"a2455beee8e73686d56f92979ed8a69011772f68e8329a437f47e55d79eaeec25afc2ac5ff636ac8578161a09a2ea690747575653f9d91016b09b71227a53791",
"808080808080808080808080808080808080808080808080",
"letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always",
"e90681c67c55504afadca009ce4042819341fa0e90300b6d32b4f2e8e8a6678ff7e7fc1da663ae194dc7a2ef7ec7b50112d1a5efce47bfd00c66eec82f2265b5",
"808080808080808080808080808080808080808080808080",
"letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always",
"dd53ab268c524bad304e3decf4298ba1413a785bc866c2118988d1634bddf5a1301718191b247761060bc6dce3c62f833b22c062e51e7508fc04201cd7f8515b",
"ffffffffffffffffffffffffffffffffffffffffffffffff",
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when",
"2a372547df962742942674170a7cef495ea0b97f4864de16d0f3ee82eb577ca1eca345e601cc2df7c626c5bc51c52c28a3b4294224b685c958c7450bee6769e6",
"ffffffffffffffffffffffffffffffffffffffffffffffff",
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when",
"f0747118b52dcd33d383e5f3d6dddc94f66accd38b6d48f8a07fed9752fa8457dcb40bba5f40399814dcbd1a3f5cfaead1cf26c72268d1aa71561611421d4aaf",
"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",
"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",
"681088fbeaf5e4c29de23f55967a942bcb3400dc5b6e507477dfdcb493d921902352e015cd1235279c61ddf26b9536e6cf87fccb3cf2e142db44689f78ccad12",
"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",
"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",
"0881d39ee42046f433bff48ae0520128b79c0b9ff376c805b384340bd73767cdd8d1583606bafe2879be99ff44847e83057dbe521415a6067e8e4d7334e35a6c",
"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",
"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",
"63362d97a394e67674c5e337b8b8221f242cdf84eac057e08e8d522ac458e0c8b577c487bf82255d41e2ecfaf9326be2b3b31534a990608950b05a5d849e0603",
"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",
"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",
"3c22432ca0b5c9572a631b1068749bb6b663a78390322ab4b763c3ee21d81a7774f8ecdbc6ec73932b961c7374c7d14156cd61f81e433de3953fad23ea407e58",
"1083fa24dbb0afa4e7b327d23f666567",
"awesome cabin matrix resist april sponsor paddle gossip split will off soon",
"467406b36a0176e40e013393e5ecef1f5b4019980b502eda9db1db06f7786e088b206f045f2bfcf93bd3b17a598335b078fcc5890115857ff741bd154b54f049",
"b71edfa823c78c5f8d6cade654e298b4",
"require want tube elegant juice cool cup noble town poem plate harsh",
"b424ec5ee4eb4127c3ce0722572c456a47084cda617a26fb647f9a02f43fcc3d11a84dadb6e892ec2641d8592149018a39c8bd9c1cadc969188da4b820bf3371",
"d8cbcd1ac2153ecd74048480c2732f637d642b21f0dd40df",
"sugar fury effort loud fault grit source mountain liar bean slim shoulder stone better march brick dolphin zero",
"f60180ea5047659cbb17ed6ef79c974de86c0170c7a1962b205329eb8fe9dcdd148615d35c515c4ec8da25f4cf54d5b7cd8cd5bf8dc4059df3a7900ca25f8306",
"8ffd2ff2b2fa4dd7c61f019698893918dfd72c0ea37d0027",
"morning truly witness grass pill typical blur then notable session exact coyote word noodle dentist hurry ability dignity",
"d20f3879eebf9858443a6ca0f04f568aac06e74fb542475824101855133ed5f54d0805d0fc9bc0e6f03c1f820ee01a462b291caeba7cbf659b670afd00e0db42",
"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",
"9b655bc7d4e380bad6148df1cf8d8a6b023b781b05c2e823c5b5dd05139d30f6",
"opinion client vehicle prefer day frost flame museum vault ladder glad stock casual rose hire reunion trial bullet hope ring eye soldier sense stereo",
"3c6d3843502c73e29d7e9ddc3e81354d3467121244e0b713cdb8e0e76c357d6db2f738c43bc2550bb85c9d5c900fbd7fbba10c76e7a8b920e0d450ef5a6750eb",
"f5e82717078a6ddc538a03e825f91bed",
"vote donkey shift audit plug until evolve document trial cool eight swarm",
"83dad22293225780a914083fc1a69bfe1d910f5b5962b0364820132a42ae1bd567a1fb4d5a19ad3d64539e38a7ee3d6429fac2b74e72b020913131c5eadb7db4",
"bdc823540d4ff8d372d29f4265fe5cf8",
"saddle donate steak box zebra have slender fault draw copper now various",
"0c960d7d54415e5d3ae41ea805bc961f14d7031ea0b92058c19cecab7b7e51f82a4d987dbe63dfaed30805bd746d93e645fd5dffea8354b90688711d6fa570bd",
"16b59b6a426f2f302f73049a32ab8572394278982212357a",
"birth proud surround luggage very object saddle gauge olive next throw tongue neither detail gauge drastic cube strategy",
"38ceb07e0dad221f612631843be6ae44a650aaf789c8ebea9313e07498d7864385227d25c7a8268a5b850367eef31639632e9218acadead20980b864b1cd477e",
"53de16bcad3ea92c691f5d069de6f1870a9adfe764b1aa33",
"fatigue vague quality foil tunnel normal piece two alley upset round asthma predict husband outside normal pretty oppose",
"fa384e2775768bc4905a5f7a014cdb62bbf77f751a039d5a124191099970dafc02e679232aeab769cb1582038907829baa3995255be01fe042b462539b26f1af",
"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",
"29932ac2fbba5682ef711bd7429068ac7f90fe6132c9f1a722e8441240cb9a96",
"civil off radar wash pistol door saddle casino struggle behind boss flight weekend left luggage float vast decorate ring market catch grape heart sport",
"777122f7b4e1dd21d385e71b9811d7d8d2adffcb8d0cebb667c93346156d4baec6b23adc519515742a4f6a712cbbef3e03e528f912498a3104206f33259d8823",
"7f93397f750f70a26513de2732ed95ee",
"legend oil garlic tube warfare eye nephew knock cheese number grace tackle",
"7f92ad63e4cdf4f15c23740556ad81e7f8cbd67cc672c93894c9c0d4fb171539eed5ab29f366570ed9940b816f45a539c3816f7ac19511794b752c5c1ec0e732",
"498e5f6f8039399a5e307406f448f846",
"end indicate swim about near snake juice attend alone pelican dignity mimic",
"551e36122e37276b2840ab5c71b2a33888a6efa501a47b8323b313bf03f6dec1fb3d2ef11bfb35ec41580c5c0be3f881907fe2a3154b6e0ba8e05177b8e928a6",
"14c29fe840dd1c9f05d392ba13e4e1466b32ed0726a15f89",
"below belt wheel like spike exhibit blanket inch ring palace debate mimic rebel isolate broken stage garbage enhance",
"7bae6e54f8bad645f18f574b310bd3e6fde126dabcaf63a889940380e4798810e48c8151fc56bb2389c07498deacef025f03cbf8fc57ea3ec68f6421b0fcb649",
"7d205696a272051f60c14f146808a2c83bb0f7ef95037b4e",
"large actor pizza eager cake moral loan clarify behave doctor chunk motor roast know salad parrot kitten item",
"d8bb3b18a5b9844ae1117b680986d93074efc691d9084dc5ef9d3570d9f9bcaffc9c319fb53d6c728564ee0e4494953245607688adb2efbbe77b912835f40e8c",
"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",
"d10c1c341f19c89a5c8c505cabfa027422ea6cb4cb6c28003898676ef7611cd2",
"speed genius artist dilemma orient essay impulse meat frequent garlic letter tribe concert curve spring horn chimney achieve champion solution urge rack infant furnace",
"a2f0b91b238ca1df0c4ac89eaa628701800f70732a1952982f3021e94bf7c3aafa0bb51bbdcc210f1e433d3e740660d1e4053c12edfdc1eb77ceafbe6a32723e",
"a30b50a5439dcd1774f412ea5ec33403",
"perfect fold citizen mango system merry stable liquid tumble voyage snack alter",
"aae175f26848370c4d5d3d0640597e2bf1b28e95908dd877259b3eac5d71ffe3140739a3ed80180f88159571df84441985620e6b2fb0696e5cba1aa7b8d10b98",
"719ddb2a59b10066c74d26954da2dc2e",
"immense uphold skin recall avoid cricket brush pill next home require friend",
"9be5826432f915ace1f77827028a0ab7098dd3776304aa17e03698b09e5e93914e3e3f0d3d38c9b265ec2cc4bba1da8c9d9a97c8a3b1ec05add8e34a1c676490",
"70044da2175ad681d0ebbf2da83cf407eb9c8fd91fc0a8c9",
"hybrid carbon hammer concert pulp domain dry jewel color draft dial average right elevator good way potato energy",
"a3dffe3a31a2e949d1b04af7495a5b59db17e41d93b985feeaaae89260a9c86c6dcdf7cb32eaba61c2f4f0340f0f17d1ebb67af11657286b2ffd66ec4e05a8b7",
"5746a7704cd3b9dc0a022f2a9025618d813c8ca873b8008c",
"firm cry swing often describe unlock chimney echo clever license flash brand because edge peace jacket above gentle",
"06f5b2d7af46c2e7b7b99c87aa52d17c27925ba685ba5e572b4e978da2adee44fe7d5726966cd2ee1ae47b65790baa4b3f7952505b0b45d9c8673a29e6a57ffc",
"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",
"8fdda21cc1b39a6fb264ab3c007995cf9ed9efcfebc07652951e769b6bcbfad4",
"more unfair mango lock defy daughter sister nice despair adult grace palace unique wave distance job iron net elegant unfold repeat tourist twice number",
"c37ae2956e1396b03a722d647dbcf2672cb8db1493c2c136ab9370a62c19c8f45023a635b7c2646a9748ff28c7ef64d93d089c315d390c50cee19cb46a01927f"
};
private MnemonicCode mc;
@ -143,31 +143,33 @@ public class MnemonicCodeTest {
List<String> code = mc.toMnemonic(Hex.decode(vecData));
byte[] seed = MnemonicCode.toSeed(code, "TREZOR");
byte[] entropy = mc.toEntropy(split(vecCode));
assertEquals(vecCode, Joiner.on(' ').join(code));
assertEquals(vecSeed, new String(Hex.encode(seed)));
assertEquals(vecData, new String(Hex.encode(entropy)));
}
}
@Test(expected = MnemonicLengthException.class)
@Test(expected = MnemonicException.MnemonicLengthException.class)
public void testBadEntropyLength() throws Exception {
byte[] entropy = Hex.decode("7f7f7f7f7f7f7f7f7f7f7f7f7f7f");
mc.toMnemonic(entropy);
}
@Test(expected = MnemonicLengthException.class)
@Test(expected = MnemonicException.MnemonicLengthException.class)
public void testBadLength() throws Exception {
List<String> words = split("risk tiger venture dinner age assume float denial penalty hello");
mc.check(words);
}
@Test(expected = MnemonicWordException.class)
@Test(expected = MnemonicException.MnemonicWordException.class)
public void testBadWord() throws Exception {
List<String> words = split("risk tiger venture dinner xyzzy assume float denial penalty hello game wing");
mc.check(words);
}
@Test(expected = MnemonicChecksumException.class)
@Test(expected = MnemonicException.MnemonicChecksumException.class)
public void testBadChecksum() throws Exception {
List<String> words = split("bless cloud wheel regular tiny venue bird web grief security dignity zoo");
mc.check(words);