parent
779863ad21
commit
b8ea0b86bf
|
@ -8,8 +8,13 @@ use test::Bencher;
|
|||
use bip39::*;
|
||||
|
||||
#[cfg(not(any(
|
||||
feature = "chinese-simplified", feature = "chinese-traditional", feature = "czech",
|
||||
feature = "french", feature = "italian", feature = "japanese", feature = "korean",
|
||||
feature = "chinese-simplified",
|
||||
feature = "chinese-traditional",
|
||||
feature = "czech",
|
||||
feature = "french",
|
||||
feature = "italian",
|
||||
feature = "japanese",
|
||||
feature = "korean",
|
||||
feature = "spanish"
|
||||
)))]
|
||||
const LANG: Language = Language::English;
|
||||
|
@ -32,38 +37,38 @@ const LANG: Language = Language::Spanish;
|
|||
|
||||
#[bench]
|
||||
fn validate(b: &mut Bencher) {
|
||||
let entropy = "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f".as_bytes();
|
||||
let mnemonic = Mnemonic::from_entropy_in(LANG, &entropy).unwrap();
|
||||
let entropy = "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f".as_bytes();
|
||||
let mnemonic = Mnemonic::from_entropy_in(LANG, &entropy).unwrap();
|
||||
assert_eq!(mnemonic.word_count(), 24);
|
||||
let phrase = mnemonic.to_string();
|
||||
|
||||
b.iter(|| {
|
||||
let _ = Mnemonic::parse_in(Language::English, &phrase);
|
||||
});
|
||||
b.iter(|| {
|
||||
let _ = Mnemonic::parse_in(Language::English, &phrase);
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn from_entropy(b: &mut Bencher) {
|
||||
let entropy = "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f".as_bytes();
|
||||
let entropy = "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f".as_bytes();
|
||||
|
||||
b.iter(|| {
|
||||
let _ = Mnemonic::from_entropy_in(LANG, &entropy).unwrap();
|
||||
});
|
||||
b.iter(|| {
|
||||
let _ = Mnemonic::from_entropy_in(LANG, &entropy).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn new_mnemonic(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let _ = Mnemonic::generate_in(LANG, 24);
|
||||
});
|
||||
b.iter(|| {
|
||||
let _ = Mnemonic::generate_in(LANG, 24);
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn to_seed(b: &mut Bencher) {
|
||||
let entropy = "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f".as_bytes();
|
||||
let m = Mnemonic::from_entropy_in(LANG, &entropy).unwrap();
|
||||
let entropy = "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f".as_bytes();
|
||||
let m = Mnemonic::from_entropy_in(LANG, &entropy).unwrap();
|
||||
|
||||
b.iter(|| {
|
||||
let _ = m.to_seed("");
|
||||
});
|
||||
b.iter(|| {
|
||||
let _ = m.to_seed("");
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,59 +1,58 @@
|
|||
|
||||
/// Implement serde serialization based on the
|
||||
/// fmt::Display and std::FromStr traits.
|
||||
macro_rules! serde_string_impl {
|
||||
($name:ident, $expecting:expr) => {
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de> $crate::serde::Deserialize<'de> for $name {
|
||||
fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
|
||||
where
|
||||
D: $crate::serde::de::Deserializer<'de>,
|
||||
{
|
||||
use ::std::fmt::{self, Formatter};
|
||||
use ::std::str::FromStr;
|
||||
($name:ident, $expecting:expr) => {
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de> $crate::serde::Deserialize<'de> for $name {
|
||||
fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
|
||||
where
|
||||
D: $crate::serde::de::Deserializer<'de>,
|
||||
{
|
||||
use std::fmt::{self, Formatter};
|
||||
use std::str::FromStr;
|
||||
|
||||
struct Visitor;
|
||||
impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
|
||||
type Value = $name;
|
||||
struct Visitor;
|
||||
impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
|
||||
type Value = $name;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||
formatter.write_str($expecting)
|
||||
}
|
||||
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||
formatter.write_str($expecting)
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: $crate::serde::de::Error,
|
||||
{
|
||||
$name::from_str(v).map_err(E::custom)
|
||||
}
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: $crate::serde::de::Error,
|
||||
{
|
||||
$name::from_str(v).map_err(E::custom)
|
||||
}
|
||||
|
||||
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: $crate::serde::de::Error,
|
||||
{
|
||||
self.visit_str(v)
|
||||
}
|
||||
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: $crate::serde::de::Error,
|
||||
{
|
||||
self.visit_str(v)
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: $crate::serde::de::Error,
|
||||
{
|
||||
self.visit_str(&v)
|
||||
}
|
||||
}
|
||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: $crate::serde::de::Error,
|
||||
{
|
||||
self.visit_str(&v)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_str(Visitor)
|
||||
}
|
||||
}
|
||||
deserializer.deserialize_str(Visitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de> $crate::serde::Serialize for $name {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: $crate::serde::Serializer,
|
||||
{
|
||||
serializer.collect_str(&self)
|
||||
}
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de> $crate::serde::Serialize for $name {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: $crate::serde::Serializer,
|
||||
{
|
||||
serializer.collect_str(&self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
|
||||
use core::fmt;
|
||||
|
||||
mod english;
|
||||
#[cfg(feature = "chinese-simplified")]
|
||||
mod chinese_simplified;
|
||||
#[cfg(feature = "chinese-traditional")]
|
||||
mod chinese_traditional;
|
||||
#[cfg(feature = "czech")]
|
||||
mod czech;
|
||||
mod english;
|
||||
#[cfg(feature = "french")]
|
||||
mod french;
|
||||
#[cfg(feature = "italian")]
|
||||
|
@ -142,7 +141,7 @@ impl Language {
|
|||
None => return &[],
|
||||
};
|
||||
let count = self.word_list()[first..].iter().take_while(|w| w.starts_with(prefix)).count();
|
||||
&self.word_list()[first .. first + count]
|
||||
&self.word_list()[first..first + count]
|
||||
}
|
||||
|
||||
/// Get the index of the word in the word list.
|
||||
|
@ -163,8 +162,13 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
#[cfg(all(
|
||||
feature = "chinese-simplified", feature = "chinese-traditional", feature = "czech",
|
||||
feature = "french", feature = "italian", feature = "japanese", feature = "korean",
|
||||
feature = "chinese-simplified",
|
||||
feature = "chinese-traditional",
|
||||
feature = "czech",
|
||||
feature = "french",
|
||||
feature = "italian",
|
||||
feature = "japanese",
|
||||
feature = "korean",
|
||||
feature = "spanish"
|
||||
))]
|
||||
#[test]
|
||||
|
@ -185,13 +189,22 @@ mod tests {
|
|||
use bitcoin_hashes::{sha256, Hash, HashEngine};
|
||||
|
||||
let checksums = [
|
||||
("5c5942792bd8340cb8b27cd592f1015edf56a8c5b26276ee18a482428e7c5726", Language::SimplifiedChinese),
|
||||
("417b26b3d8500a4ae3d59717d7011952db6fc2fb84b807f3f94ac734e89c1b5f", Language::TraditionalChinese),
|
||||
(
|
||||
"5c5942792bd8340cb8b27cd592f1015edf56a8c5b26276ee18a482428e7c5726",
|
||||
Language::SimplifiedChinese,
|
||||
),
|
||||
(
|
||||
"417b26b3d8500a4ae3d59717d7011952db6fc2fb84b807f3f94ac734e89c1b5f",
|
||||
Language::TraditionalChinese,
|
||||
),
|
||||
("7e80e161c3e93d9554c2efb78d4e3cebf8fc727e9c52e03b83b94406bdcc95fc", Language::Czech),
|
||||
("2f5eed53a4727b4bf8880d8f3f199efc90e58503646d9ff8eff3a2ed3b24dbda", Language::English),
|
||||
("ebc3959ab7801a1df6bac4fa7d970652f1df76b683cd2f4003c941c63d517e59", Language::French),
|
||||
("d392c49fdb700a24cd1fceb237c1f65dcc128f6b34a8aacb58b59384b5c648c2", Language::Italian),
|
||||
("2eed0aef492291e061633d7ad8117f1a2b03eb80a29d0e4e3117ac2528d05ffd", Language::Japanese),
|
||||
(
|
||||
"2eed0aef492291e061633d7ad8117f1a2b03eb80a29d0e4e3117ac2528d05ffd",
|
||||
Language::Japanese,
|
||||
),
|
||||
("9e95f86c167de88f450f0aaf89e87f6624a57f973c67b516e338e8e8b8897f60", Language::Korean),
|
||||
("46846a5a0139d1e3cb77293e521c2865f7bcdb82c44e8d0a06a2cd0ecba48c0b", Language::Spanish),
|
||||
];
|
||||
|
@ -206,8 +219,11 @@ mod tests {
|
|||
digest.input("\n".as_bytes());
|
||||
}
|
||||
#[cfg(feature = "std")]
|
||||
assert_eq!(sha256::Hash::from_engine(digest).to_string(), _sum,
|
||||
"word list for language {} failed checksum check", lang,
|
||||
assert_eq!(
|
||||
sha256::Hash::from_engine(digest).to_string(),
|
||||
_sum,
|
||||
"word list for language {} failed checksum check",
|
||||
lang,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -217,7 +233,7 @@ mod tests {
|
|||
let lang = Language::English;
|
||||
|
||||
let res = lang.words_by_prefix("woo");
|
||||
assert_eq!(res, ["wood","wool"]);
|
||||
assert_eq!(res, ["wood", "wool"]);
|
||||
|
||||
let res = lang.words_by_prefix("");
|
||||
assert_eq!(res.len(), 2048);
|
||||
|
@ -227,8 +243,13 @@ mod tests {
|
|||
}
|
||||
|
||||
#[cfg(all(
|
||||
feature = "chinese-simplified", feature = "chinese-traditional", feature = "czech",
|
||||
feature = "french", feature = "italian", feature = "japanese", feature = "korean",
|
||||
feature = "chinese-simplified",
|
||||
feature = "chinese-traditional",
|
||||
feature = "czech",
|
||||
feature = "french",
|
||||
feature = "italian",
|
||||
feature = "japanese",
|
||||
feature = "korean",
|
||||
feature = "spanish"
|
||||
))]
|
||||
#[test]
|
||||
|
|
141
src/lib.rs
141
src/lib.rs
|
@ -25,7 +25,6 @@
|
|||
#![deny(dead_code)]
|
||||
#![deny(unused_imports)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
|
||||
|
||||
#[cfg(any(test, feature = "std"))]
|
||||
|
@ -44,10 +43,10 @@ pub extern crate serde;
|
|||
|
||||
use core::{fmt, str};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::error;
|
||||
#[cfg(feature = "std")]
|
||||
use std::borrow::Cow;
|
||||
#[cfg(feature = "std")]
|
||||
use std::error;
|
||||
|
||||
use bitcoin_hashes::{sha256, Hash};
|
||||
|
||||
|
@ -114,14 +113,14 @@ pub enum Error {
|
|||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Error::BadWordCount(c) => write!(f,
|
||||
"mnemonic has a word count that is not a multiple of 6: {}", c,
|
||||
),
|
||||
Error::UnknownWord(i) => write!(f,
|
||||
"mnemonic contains an unknown word (word {})", i,
|
||||
),
|
||||
Error::BadEntropyBitCount(c) => write!(f,
|
||||
"entropy was not between 128-256 bits or not a multiple of 32 bits: {} bits", c,
|
||||
Error::BadWordCount(c) => {
|
||||
write!(f, "mnemonic has a word count that is not a multiple of 6: {}", c,)
|
||||
}
|
||||
Error::UnknownWord(i) => write!(f, "mnemonic contains an unknown word (word {})", i,),
|
||||
Error::BadEntropyBitCount(c) => write!(
|
||||
f,
|
||||
"entropy was not between 128-256 bits or not a multiple of 32 bits: {} bits",
|
||||
c,
|
||||
),
|
||||
Error::InvalidChecksum => write!(f, "the mnemonic has an invalid checksum"),
|
||||
Error::AmbiguousLanguages(a) => {
|
||||
|
@ -231,8 +230,13 @@ impl Mnemonic {
|
|||
/// let mut rng = rand::thread_rng();
|
||||
/// let m = Mnemonic::generate_in_with(&mut rng, Language::English, 24).unwrap();
|
||||
/// ```
|
||||
pub fn generate_in_with<R>(rng: &mut R, language: Language, word_count: usize) -> Result<Mnemonic, Error>
|
||||
where R: rand_core::RngCore + rand_core::CryptoRng,
|
||||
pub fn generate_in_with<R>(
|
||||
rng: &mut R,
|
||||
language: Language,
|
||||
word_count: usize,
|
||||
) -> Result<Mnemonic, Error>
|
||||
where
|
||||
R: rand_core::RngCore + rand_core::CryptoRng,
|
||||
{
|
||||
if word_count < MIN_NB_WORDS || word_count % 6 != 0 || word_count > MAX_NB_WORDS {
|
||||
return Err(Error::BadWordCount(word_count));
|
||||
|
@ -288,7 +292,8 @@ impl Mnemonic {
|
|||
fn language_of_iter<'a, W: Iterator<Item = &'a str>>(words: W) -> Result<Language, Error> {
|
||||
let mut words = words.peekable();
|
||||
let langs = Language::all();
|
||||
{ // Start scope to drop first_word so that words can be reborrowed later.
|
||||
{
|
||||
// Start scope to drop first_word so that words can be reborrowed later.
|
||||
let first_word = words.peek().ok_or(Error::BadWordCount(0))?;
|
||||
if first_word.len() == 0 {
|
||||
return Err(Error::BadWordCount(0));
|
||||
|
@ -404,7 +409,10 @@ impl Mnemonic {
|
|||
|
||||
/// Parse a mnemonic in the given language.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn parse_in<'a, S: Into<Cow<'a, str>>>(language: Language, s: S) -> Result<Mnemonic, Error> {
|
||||
pub fn parse_in<'a, S: Into<Cow<'a, str>>>(
|
||||
language: Language,
|
||||
s: S,
|
||||
) -> Result<Mnemonic, Error> {
|
||||
let mut cow = s.into();
|
||||
Mnemonic::normalize_utf8_cow(&mut cow);
|
||||
Ok(Mnemonic::parse_in_normalized(language, cow.as_ref())?)
|
||||
|
@ -437,7 +445,12 @@ impl Mnemonic {
|
|||
|
||||
let nb_words = self.word_count();
|
||||
let mut seed = [0u8; PBKDF2_BYTES];
|
||||
pbkdf2::pbkdf2(&self.0[0..nb_words], normalized_passphrase.as_bytes(), PBKDF2_ROUNDS, &mut seed);
|
||||
pbkdf2::pbkdf2(
|
||||
&self.0[0..nb_words],
|
||||
normalized_passphrase.as_bytes(),
|
||||
PBKDF2_ROUNDS,
|
||||
&mut seed,
|
||||
);
|
||||
seed
|
||||
}
|
||||
|
||||
|
@ -519,9 +532,13 @@ impl str::FromStr for Mnemonic {
|
|||
|
||||
fn from_str(s: &str) -> Result<Mnemonic, Error> {
|
||||
#[cfg(feature = "std")]
|
||||
{ Mnemonic::parse(s) }
|
||||
{
|
||||
Mnemonic::parse(s)
|
||||
}
|
||||
#[cfg(not(feature = "std"))]
|
||||
{ Mnemonic::parse_normalized(s) }
|
||||
{
|
||||
Mnemonic::parse_normalized(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -537,7 +554,10 @@ mod tests {
|
|||
for lang in Language::all() {
|
||||
let m = Mnemonic::generate_in(*lang, 24).unwrap();
|
||||
assert_eq!(*lang, Mnemonic::language_of_iter(m.word_iter()).unwrap());
|
||||
assert_eq!(*lang, Mnemonic::language_of_iter(m.to_string().split_whitespace()).unwrap());
|
||||
assert_eq!(
|
||||
*lang,
|
||||
Mnemonic::language_of_iter(m.to_string().split_whitespace()).unwrap()
|
||||
);
|
||||
assert_eq!(*lang, Mnemonic::language_of(m.to_string()).unwrap());
|
||||
assert_eq!(*lang, Mnemonic::language_of(&m.to_string()).unwrap());
|
||||
}
|
||||
|
@ -703,27 +723,53 @@ mod tests {
|
|||
|
||||
let mnemonic = Mnemonic::from_entropy(&entropy).unwrap();
|
||||
|
||||
assert_eq!(mnemonic, Mnemonic::parse_in_normalized(Language::English, mnemonic_str).unwrap(),
|
||||
"failed vector: {}", mnemonic_str);
|
||||
assert_eq!(mnemonic, Mnemonic::parse_normalized(mnemonic_str).unwrap(),
|
||||
"failed vector: {}", mnemonic_str);
|
||||
assert_eq!(&seed[..], &mnemonic.to_seed_normalized("TREZOR")[..],
|
||||
"failed vector: {}", mnemonic_str);
|
||||
assert_eq!(
|
||||
mnemonic,
|
||||
Mnemonic::parse_in_normalized(Language::English, mnemonic_str).unwrap(),
|
||||
"failed vector: {}",
|
||||
mnemonic_str
|
||||
);
|
||||
assert_eq!(
|
||||
mnemonic,
|
||||
Mnemonic::parse_normalized(mnemonic_str).unwrap(),
|
||||
"failed vector: {}",
|
||||
mnemonic_str
|
||||
);
|
||||
assert_eq!(
|
||||
&seed[..],
|
||||
&mnemonic.to_seed_normalized("TREZOR")[..],
|
||||
"failed vector: {}",
|
||||
mnemonic_str
|
||||
);
|
||||
|
||||
#[cfg(features = "std")]
|
||||
{
|
||||
assert_eq!(&mnemonic.to_string(), mnemonic_str,
|
||||
"failed vector: {}", mnemonic_str);
|
||||
assert_eq!(mnemonic, Mnemonic::parse_in(Language::English, mnemonic_str).unwrap(),
|
||||
"failed vector: {}", mnemonic_str);
|
||||
assert_eq!(mnemonic, Mnemonic::parse(mnemonic_str).unwrap(),
|
||||
"failed vector: {}", mnemonic_str);
|
||||
assert_eq!(&seed[..], &mnemonic.to_seed("TREZOR")[..],
|
||||
"failed vector: {}", mnemonic_str);
|
||||
assert_eq!(&entropy, &mnemonic.to_entropy(),
|
||||
"failed vector: {}", mnemonic_str);
|
||||
assert_eq!(&entropy, &mnemonic.to_entropy_array().0[0..entropy.len()],
|
||||
"failed vector: {}", mnemonic_str);
|
||||
assert_eq!(&mnemonic.to_string(), mnemonic_str, "failed vector: {}", mnemonic_str);
|
||||
assert_eq!(
|
||||
mnemonic,
|
||||
Mnemonic::parse_in(Language::English, mnemonic_str).unwrap(),
|
||||
"failed vector: {}",
|
||||
mnemonic_str
|
||||
);
|
||||
assert_eq!(
|
||||
mnemonic,
|
||||
Mnemonic::parse(mnemonic_str).unwrap(),
|
||||
"failed vector: {}",
|
||||
mnemonic_str
|
||||
);
|
||||
assert_eq!(
|
||||
&seed[..],
|
||||
&mnemonic.to_seed("TREZOR")[..],
|
||||
"failed vector: {}",
|
||||
mnemonic_str
|
||||
);
|
||||
assert_eq!(&entropy, &mnemonic.to_entropy(), "failed vector: {}", mnemonic_str);
|
||||
assert_eq!(
|
||||
&entropy,
|
||||
&mnemonic.to_entropy_array().0[0..entropy.len()],
|
||||
"failed vector: {}",
|
||||
mnemonic_str
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -765,22 +811,13 @@ mod tests {
|
|||
#[test]
|
||||
fn test_invalid_entropy() {
|
||||
//between 128 and 256 bits, but not divisible by 32
|
||||
assert_eq!(
|
||||
Mnemonic::from_entropy(&vec![b'x'; 17]),
|
||||
Err(Error::BadEntropyBitCount(136))
|
||||
);
|
||||
assert_eq!(Mnemonic::from_entropy(&vec![b'x'; 17]), Err(Error::BadEntropyBitCount(136)));
|
||||
|
||||
//less than 128 bits
|
||||
assert_eq!(
|
||||
Mnemonic::from_entropy(&vec![b'x'; 4]),
|
||||
Err(Error::BadEntropyBitCount(32))
|
||||
);
|
||||
assert_eq!(Mnemonic::from_entropy(&vec![b'x'; 4]), Err(Error::BadEntropyBitCount(32)));
|
||||
|
||||
//greater than 256 bits
|
||||
assert_eq!(
|
||||
Mnemonic::from_entropy(&vec![b'x'; 36]),
|
||||
Err(Error::BadEntropyBitCount(288))
|
||||
);
|
||||
assert_eq!(Mnemonic::from_entropy(&vec![b'x'; 36]), Err(Error::BadEntropyBitCount(288)));
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "japanese", feature = "std"))]
|
||||
|
@ -948,16 +985,14 @@ mod tests {
|
|||
|
||||
let mnemonic = Mnemonic::from_entropy_in(Language::Japanese, &entropy).unwrap();
|
||||
|
||||
assert_eq!(seed, &mnemonic.to_seed(passphrase)[..],
|
||||
"failed vector: {}", mnemonic_str);
|
||||
assert_eq!(seed, &mnemonic.to_seed(passphrase)[..], "failed vector: {}", mnemonic_str);
|
||||
let rt = Mnemonic::parse_in(Language::Japanese, mnemonic.to_string())
|
||||
.expect(&format!("vector: {}", mnemonic_str));
|
||||
assert_eq!(seed, &rt.to_seed(passphrase)[..]);
|
||||
|
||||
let mnemonic = Mnemonic::parse_in(Language::Japanese, mnemonic_str)
|
||||
.expect(&format!("vector: {}", mnemonic_str));
|
||||
assert_eq!(seed, &mnemonic.to_seed(passphrase)[..],
|
||||
"failed vector: {}", mnemonic_str);
|
||||
assert_eq!(seed, &mnemonic.to_seed(passphrase)[..], "failed vector: {}", mnemonic_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
use bitcoin_hashes::{hmac, sha512, Hash, HashEngine};
|
||||
|
||||
const SALT_PREFIX: &'static str = "mnemonic";
|
||||
|
@ -81,7 +80,7 @@ fn create_hmac_engine(mnemonic: &[&'static str]) -> hmac::HmacEngine<sha512::Has
|
|||
fn u32_to_array_be(val: u32) -> [u8; 4] {
|
||||
let mut res = [0; 4];
|
||||
for i in 0..4 {
|
||||
res[i] = ((val >> (4 - i - 1)*8) & 0xff) as u8;
|
||||
res[i] = ((val >> (4 - i - 1) * 8) & 0xff) as u8;
|
||||
}
|
||||
res
|
||||
}
|
||||
|
@ -98,7 +97,9 @@ pub(crate) fn pbkdf2(mnemonic: &[&'static str], unprefixed_salt: &[u8], c: usize
|
|||
let prf = create_hmac_engine(mnemonic);
|
||||
|
||||
for (i, chunk) in res.chunks_mut(sha512::Hash::LEN).enumerate() {
|
||||
for v in chunk.iter_mut() { *v = 0; }
|
||||
for v in chunk.iter_mut() {
|
||||
*v = 0;
|
||||
}
|
||||
|
||||
let mut salt = {
|
||||
let mut prfc = prf.clone();
|
||||
|
|
Loading…
Reference in New Issue