BIP39 Support (#1502)
* add BIP39 word list * implement BIP39 * add unit tests * add from_mnemonic() constructor to ExtendedPrivKey * fix formatting * update hasher name * replace rust-crypto supercrate with individual crates * rustfmt
This commit is contained in:
Generated
+18
@@ -789,7 +789,9 @@ dependencies = [
|
||||
"digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"grin_util 0.4.1",
|
||||
"hmac 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pbkdf2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ripemd160 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1686,6 +1688,21 @@ dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pbkdf2"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crypto-mac 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hmac 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
@@ -2953,6 +2970,7 @@ dependencies = [
|
||||
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
||||
"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5"
|
||||
"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c"
|
||||
"checksum pbkdf2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0c09cddfbfc98de7f76931acf44460972edb4023eb14d0c6d4018800e552d8e0"
|
||||
"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
||||
"checksum phf 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)" = "cec29da322b242f4c3098852c77a0ca261c9c01b806cae85a5572a1eb94db9a6"
|
||||
|
||||
@@ -18,10 +18,13 @@ serde = "1"
|
||||
serde_derive = "1"
|
||||
serde_json = "1"
|
||||
uuid = { version = "0.6", features = ["serde", "v4"] }
|
||||
lazy_static = "1"
|
||||
|
||||
digest = "0.7"
|
||||
hmac = "0.6"
|
||||
ripemd160 = "0.7"
|
||||
sha2 = "0.7"
|
||||
pbkdf2 = "0.2"
|
||||
|
||||
|
||||
grin_util = { path = "../util", version = "0.4.1" }
|
||||
|
||||
@@ -38,6 +38,7 @@ use std::str::FromStr;
|
||||
use std::{error, fmt};
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
|
||||
use mnemonic;
|
||||
use util::secp::key::{PublicKey, SecretKey};
|
||||
use util::secp::{self, ContextFlag, Secp256k1};
|
||||
|
||||
@@ -297,6 +298,8 @@ pub enum Error {
|
||||
InvalidChildNumber(ChildNumber),
|
||||
/// Error creating a master seed --- for application use
|
||||
RngError(String),
|
||||
/// Error converting mnemonic to seed
|
||||
MnemonicError(mnemonic::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
@@ -308,6 +311,7 @@ impl fmt::Display for Error {
|
||||
Error::Ecdsa(ref e) => fmt::Display::fmt(e, f),
|
||||
Error::InvalidChildNumber(ref n) => write!(f, "child number {} is invalid", n),
|
||||
Error::RngError(ref s) => write!(f, "rng error {}", s),
|
||||
Error::MnemonicError(ref e) => fmt::Display::fmt(e, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,6 +331,7 @@ impl error::Error for Error {
|
||||
Error::Ecdsa(ref e) => error::Error::description(e),
|
||||
Error::InvalidChildNumber(_) => "child number is invalid",
|
||||
Error::RngError(_) => "rng error",
|
||||
Error::MnemonicError(_) => "mnemonic error",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -361,6 +366,21 @@ impl ExtendedPrivKey {
|
||||
})
|
||||
}
|
||||
|
||||
/// Construct a new master key from a mnemonic and a passphrase
|
||||
pub fn from_mnemonic(
|
||||
secp: &Secp256k1,
|
||||
mnemonic: &str,
|
||||
passphrase: &str,
|
||||
) -> Result<ExtendedPrivKey, Error> {
|
||||
let seed = match mnemonic::to_seed(mnemonic, passphrase) {
|
||||
Ok(s) => s,
|
||||
Err(e) => return Err(Error::MnemonicError(e)),
|
||||
};
|
||||
let mut hasher = BIP32GrinHasher::new();
|
||||
let key = try!(ExtendedPrivKey::new_master(secp, &mut hasher, &seed));
|
||||
Ok(key)
|
||||
}
|
||||
|
||||
/// Attempts to derive an extended private key from a path.
|
||||
pub fn derive_priv<H>(
|
||||
&self,
|
||||
@@ -409,8 +429,7 @@ impl ExtendedPrivKey {
|
||||
hasher.append_sha512(&be_n);
|
||||
let result = hasher.result_sha512();
|
||||
let mut sk = SecretKey::from_slice(secp, &result[..32]).map_err(Error::Ecdsa)?;
|
||||
sk.add_assign(secp, &self.secret_key)
|
||||
.map_err(Error::Ecdsa)?;
|
||||
sk.add_assign(secp, &self.secret_key).map_err(Error::Ecdsa)?;
|
||||
|
||||
Ok(ExtendedPrivKey {
|
||||
network: self.network,
|
||||
|
||||
@@ -85,7 +85,8 @@ impl Keychain for ExtKeychain {
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).collect();
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut neg_keys: Vec<SecretKey> = blind_sum
|
||||
.negative_key_ids
|
||||
@@ -97,7 +98,8 @@ impl Keychain for ExtKeychain {
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).collect();
|
||||
})
|
||||
.collect();
|
||||
|
||||
pos_keys.extend(
|
||||
&blind_sum
|
||||
@@ -218,7 +220,8 @@ mod test {
|
||||
&BlindSum::new()
|
||||
.add_blinding_factor(BlindingFactor::from_secret_key(skey1))
|
||||
.add_blinding_factor(BlindingFactor::from_secret_key(skey2))
|
||||
).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
BlindingFactor::from_secret_key(skey3),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -25,13 +25,17 @@ extern crate serde_derive;
|
||||
extern crate digest;
|
||||
extern crate hmac;
|
||||
extern crate log;
|
||||
extern crate pbkdf2;
|
||||
extern crate ripemd160;
|
||||
extern crate serde_json;
|
||||
extern crate sha2;
|
||||
extern crate uuid;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
mod base58;
|
||||
pub mod extkey_bip32;
|
||||
pub mod mnemonic;
|
||||
mod types;
|
||||
|
||||
pub mod keychain;
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//! # BIP39 Implementation
|
||||
//!
|
||||
//! Implementation of BIP39 Mnemonic code for generating deterministic keys, as defined
|
||||
//! at https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
|
||||
|
||||
use digest::Digest;
|
||||
use hmac::Hmac;
|
||||
use pbkdf2::pbkdf2;
|
||||
use sha2::{Sha256, Sha512};
|
||||
use std::fmt;
|
||||
|
||||
lazy_static! {
|
||||
/// List of bip39 words
|
||||
pub static ref WORDS: Vec<String> = { include_str!("wordlists/en.txt").split_whitespace().map(|s| s.into()).collect() };
|
||||
}
|
||||
|
||||
/// An error that might occur during mnemonic decoding
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum Error {
|
||||
/// Invalid word encountered
|
||||
BadWord(String),
|
||||
/// Checksum was not correct (expected, actual)
|
||||
BadChecksum(u8, u8),
|
||||
/// The number of words was invalid
|
||||
InvalidLength(usize),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Error::BadWord(ref b) => write!(f, "invalid bip39 word {}", b),
|
||||
Error::BadChecksum(exp, actual) => write!(
|
||||
f,
|
||||
"checksum 0x{:x} does not match expected 0x{:x}",
|
||||
actual, exp
|
||||
),
|
||||
Error::InvalidLength(ell) => write!(f, "invalid mnemonic length {}", ell),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the index of a word in the wordlist
|
||||
pub fn search(word: &str) -> Result<u16, Error> {
|
||||
let w = word.to_string();
|
||||
match WORDS.binary_search(&w) {
|
||||
Ok(index) => Ok(index as u16),
|
||||
Err(_) => Err(Error::BadWord(w)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a mnemonic to entropy
|
||||
pub fn to_entropy(mnemonic: &str) -> Result<Vec<u8>, Error> {
|
||||
let words: Vec<String> = mnemonic.split_whitespace().map(|s| s.into()).collect();
|
||||
|
||||
let sizes: [usize; 5] = [12, 15, 18, 21, 24];
|
||||
if !sizes.contains(&words.len()) {
|
||||
return Err(Error::InvalidLength(words.len()));
|
||||
}
|
||||
|
||||
// u11 vector of indexes for each word
|
||||
let mut indexes: Vec<u16> = try!(words.iter().map(|x| search(x)).collect());
|
||||
let checksum_bits = words.len() / 3;
|
||||
let mask = ((1 << checksum_bits) - 1) as u8;
|
||||
let last = indexes.pop().unwrap();
|
||||
let checksum = (last as u8) & mask;
|
||||
|
||||
let datalen = ((11 * words.len()) - checksum_bits) / 8 - 1;
|
||||
let mut entropy: Vec<u8> = vec![0; datalen];
|
||||
// set the last byte to the data part of the last word
|
||||
entropy.push((last >> checksum_bits) as u8);
|
||||
// start setting bits from this index
|
||||
let mut loc: usize = 11 - checksum_bits;
|
||||
|
||||
// cast vector of u11 as u8
|
||||
for index in indexes.iter().rev() {
|
||||
for i in 0..11 {
|
||||
let bit = index & (1 << i) != 0;
|
||||
entropy[datalen - loc / 8] |= (bit as u8) << loc % 8;
|
||||
loc += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut hash = [0; 32];
|
||||
let mut sha2sum = Sha256::default();
|
||||
sha2sum.input(&entropy.clone());
|
||||
hash.copy_from_slice(sha2sum.result().as_slice());
|
||||
|
||||
let actual = (hash[0] >> 8 - checksum_bits) & mask;
|
||||
|
||||
if actual != checksum {
|
||||
return Err(Error::BadChecksum(checksum, actual));
|
||||
}
|
||||
|
||||
Ok(entropy)
|
||||
}
|
||||
|
||||
/// Converts a nemonic and a passphrase into a seed
|
||||
pub fn to_seed<'a, T: 'a>(mnemonic: &str, passphrase: T) -> Result<[u8; 64], Error>
|
||||
where
|
||||
Option<&'a str>: From<T>,
|
||||
{
|
||||
try!(to_entropy(mnemonic));
|
||||
|
||||
let salt = ("mnemonic".to_owned() + Option::from(passphrase).unwrap_or("")).into_bytes();
|
||||
let data = mnemonic.as_bytes();
|
||||
let mut seed = [0; 64];
|
||||
|
||||
pbkdf2::<Hmac<Sha512>>(data, &salt[..], 2048, &mut seed);
|
||||
|
||||
Ok(seed)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{to_entropy, to_seed};
|
||||
use util::{from_hex, to_hex};
|
||||
|
||||
struct Test<'a> {
|
||||
mnemonic: &'a str,
|
||||
entropy: &'a str,
|
||||
seed: &'a str,
|
||||
}
|
||||
|
||||
/// Test vectors from https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#Test_vectors
|
||||
fn tests<'a>() -> Vec<Test<'a>> {
|
||||
vec![
|
||||
Test {
|
||||
entropy: "00000000000000000000000000000000",
|
||||
mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
|
||||
seed: "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04",
|
||||
},
|
||||
Test {
|
||||
entropy: "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
|
||||
mnemonic: "legal winner thank year wave sausage worth useful legal winner thank yellow",
|
||||
seed: "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607",
|
||||
},
|
||||
Test {
|
||||
entropy: "80808080808080808080808080808080",
|
||||
mnemonic: "letter advice cage absurd amount doctor acoustic avoid letter advice cage above",
|
||||
seed: "d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8",
|
||||
},
|
||||
Test {
|
||||
entropy: "ffffffffffffffffffffffffffffffff",
|
||||
mnemonic: "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong",
|
||||
seed: "ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a13332572917f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069",
|
||||
},
|
||||
Test {
|
||||
entropy: "000000000000000000000000000000000000000000000000",
|
||||
mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent",
|
||||
seed: "035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9a565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa",
|
||||
},
|
||||
Test {
|
||||
entropy: "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
|
||||
mnemonic: "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will",
|
||||
seed: "f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c392d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd",
|
||||
},
|
||||
Test {
|
||||
entropy: "808080808080808080808080808080808080808080808080",
|
||||
mnemonic: "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always",
|
||||
seed: "107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913ffb796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65",
|
||||
},
|
||||
Test {
|
||||
entropy: "ffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
mnemonic: "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when",
|
||||
seed: "0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b43348d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528",
|
||||
},
|
||||
Test {
|
||||
entropy: "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art",
|
||||
seed: "bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8",
|
||||
},
|
||||
Test {
|
||||
entropy: "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
|
||||
mnemonic: "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title",
|
||||
seed: "bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146ad717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87",
|
||||
},
|
||||
Test {
|
||||
entropy: "8080808080808080808080808080808080808080808080808080808080808080",
|
||||
mnemonic: "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless",
|
||||
seed: "c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61af0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f",
|
||||
},
|
||||
Test {
|
||||
entropy: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
mnemonic: "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote",
|
||||
seed: "dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0a5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad",
|
||||
},
|
||||
Test {
|
||||
entropy: "9e885d952ad362caeb4efe34a8e91bd2",
|
||||
mnemonic: "ozone drill grab fiber curtain grace pudding thank cruise elder eight picnic",
|
||||
seed: "274ddc525802f7c828d8ef7ddbcdc5304e87ac3535913611fbbfa986d0c9e5476c91689f9c8a54fd55bd38606aa6a8595ad213d4c9c9f9aca3fb217069a41028",
|
||||
},
|
||||
Test {
|
||||
entropy: "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b",
|
||||
mnemonic: "gravity machine north sort system female filter attitude volume fold club stay feature office ecology stable narrow fog",
|
||||
seed: "628c3827a8823298ee685db84f55caa34b5cc195a778e52d45f59bcf75aba68e4d7590e101dc414bc1bbd5737666fbbef35d1f1903953b66624f910feef245ac",
|
||||
},
|
||||
Test {
|
||||
entropy: "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c",
|
||||
mnemonic: "hamster diagram private dutch cause delay private meat slide toddler razor book happy fancy gospel tennis maple dilemma loan word shrug inflict delay length",
|
||||
seed: "64c87cde7e12ecf6704ab95bb1408bef047c22db4cc7491c4271d170a1b213d20b385bc1588d9c7b38f1b39d415665b8a9030c9ec653d75e65f847d8fc1fc440",
|
||||
},
|
||||
Test {
|
||||
entropy: "c0ba5a8e914111210f2bd131f3d5e08d",
|
||||
mnemonic: "scheme spot photo card baby mountain device kick cradle pact join borrow",
|
||||
seed: "ea725895aaae8d4c1cf682c1bfd2d358d52ed9f0f0591131b559e2724bb234fca05aa9c02c57407e04ee9dc3b454aa63fbff483a8b11de949624b9f1831a9612",
|
||||
},
|
||||
Test {
|
||||
entropy: "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3",
|
||||
mnemonic: "horn tenant knee talent sponsor spell gate clip pulse soap slush warm silver nephew swap uncle crack brave",
|
||||
seed: "fd579828af3da1d32544ce4db5c73d53fc8acc4ddb1e3b251a31179cdb71e853c56d2fcb11aed39898ce6c34b10b5382772db8796e52837b54468aeb312cfc3d",
|
||||
},
|
||||
Test {
|
||||
entropy: "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863",
|
||||
mnemonic: "panda eyebrow bullet gorilla call smoke muffin taste mesh discover soft ostrich alcohol speed nation flash devote level hobby quick inner drive ghost inside",
|
||||
seed: "72be8e052fc4919d2adf28d5306b5474b0069df35b02303de8c1729c9538dbb6fc2d731d5f832193cd9fb6aeecbc469594a70e3dd50811b5067f3b88b28c3e8d",
|
||||
},
|
||||
Test {
|
||||
entropy: "23db8160a31d3e0dca3688ed941adbf3",
|
||||
mnemonic: "cat swing flag economy stadium alone churn speed unique patch report train",
|
||||
seed: "deb5f45449e615feff5640f2e49f933ff51895de3b4381832b3139941c57b59205a42480c52175b6efcffaa58a2503887c1e8b363a707256bdd2b587b46541f5",
|
||||
},
|
||||
Test {
|
||||
entropy: "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0",
|
||||
mnemonic: "light rule cinnamon wrap drastic word pride squirrel upgrade then income fatal apart sustain crack supply proud access",
|
||||
seed: "4cbdff1ca2db800fd61cae72a57475fdc6bab03e441fd63f96dabd1f183ef5b782925f00105f318309a7e9c3ea6967c7801e46c8a58082674c860a37b93eda02",
|
||||
},
|
||||
Test {
|
||||
entropy: "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad",
|
||||
mnemonic: "all hour make first leader extend hole alien behind guard gospel lava path output census museum junior mass reopen famous sing advance salt reform",
|
||||
seed: "26e975ec644423f4a4c4f4215ef09b4bd7ef924e85d1d17c4cf3f136c2863cf6df0a475045652c57eb5fb41513ca2a2d67722b77e954b4b3fc11f7590449191d",
|
||||
},
|
||||
Test {
|
||||
entropy: "f30f8c1da665478f49b001d94c5fc452",
|
||||
mnemonic: "vessel ladder alter error federal sibling chat ability sun glass valve picture",
|
||||
seed: "2aaa9242daafcee6aa9d7269f17d4efe271e1b9a529178d7dc139cd18747090bf9d60295d0ce74309a78852a9caadf0af48aae1c6253839624076224374bc63f",
|
||||
},
|
||||
Test {
|
||||
entropy: "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05",
|
||||
mnemonic: "scissors invite lock maple supreme raw rapid void congress muscle digital elegant little brisk hair mango congress clump",
|
||||
seed: "7b4a10be9d98e6cba265566db7f136718e1398c71cb581e1b2f464cac1ceedf4f3e274dc270003c670ad8d02c4558b2f8e39edea2775c9e232c7cb798b069e88",
|
||||
},
|
||||
Test {
|
||||
entropy: "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f",
|
||||
mnemonic: "void come effort suffer camp survey warrior heavy shoot primary clutch crush open amazing screen patrol group space point ten exist slush involve unfold",
|
||||
seed: "01f5bced59dec48e362f2c45b5de68b9fd6c92c6634f44d6d40aab69056506f0e35524a518034ddc1192e1dacd32c1ed3eaa3c3b131c88ed8e7e54c49a5d0998",
|
||||
}
|
||||
]
|
||||
}
|
||||
#[test]
|
||||
fn test_bip39() {
|
||||
let tests = tests();
|
||||
for t in tests.iter() {
|
||||
assert_eq!(
|
||||
to_hex(to_seed(t.mnemonic, "TREZOR").unwrap().to_vec()),
|
||||
t.seed.to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
to_entropy(t.mnemonic).unwrap().to_vec(),
|
||||
from_hex(t.entropy.to_string()).unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_invalid() {
|
||||
// Invalid words
|
||||
assert!(to_entropy("this is not a love song this is not a love song").is_err());
|
||||
assert!(to_entropy("abandon abandon badword abandon abandon abandon abandon abandon abandon abandon abandon abandon").is_err());
|
||||
// Invalid length
|
||||
assert!(to_entropy("abandon abandon abandon abandon abandon abandon").is_err());
|
||||
// Invalid checksum
|
||||
assert!(to_entropy("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon").is_err());
|
||||
assert!(to_entropy("zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo").is_err());
|
||||
assert!(to_entropy("scissors invite lock maple supreme raw rapid void congress muscle digital elegant little brisk hair mango congress abandon").is_err());
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user