Skip to content

Commit a455e4d

Browse files
committed
improve to_seed
1 parent eef7ef8 commit a455e4d

2 files changed

Lines changed: 49 additions & 46 deletions

File tree

bip0039/src/mnemonic/mod.rs

Lines changed: 5 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
11
mod bit_accumulator;
22
mod entropy;
33
mod phrase;
4+
mod seed;
45

56
#[cfg(not(feature = "std"))]
67
use alloc::{
78
borrow::Cow,
8-
format,
99
string::{String, ToString},
1010
vec::Vec,
1111
};
1212
use core::{fmt, marker::PhantomData, mem, str};
1313
#[cfg(feature = "std")]
1414
use std::borrow::Cow;
1515

16-
use hmac::Hmac;
17-
use sha2::Sha512;
1816
use unicode_normalization::{IsNormalized, UnicodeNormalization, is_nfkd_quick};
1917
use zeroize::Zeroizing;
2018

2119
use self::{
2220
bit_accumulator::BitAccumulator,
2321
entropy::{encode_entropy, encode_entropy_with},
2422
phrase::{DecodeMode, decode_phrase},
23+
seed::to_seed,
2524
};
2625
use crate::{
2726
error::Error,
@@ -406,30 +405,8 @@ assert_eq!(result.unwrap_err(), Error::UnknownWord("ばか".nfkd().to_string()))
406405
/// assert_eq!(mnemonic.to_seed("").len(), 64);
407406
/// ```
408407
pub fn to_seed<P: AsRef<str>>(&self, passphrase: P) -> [u8; 64] {
409-
// use the PBKDF2 function with a mnemonic sentence (in UTF-8 NFKD) used as the password
410-
// and the string "mnemonic" + passphrase (again in UTF-8 NFKD) used as the salt.
411-
// The iteration count is set to 2048 and HMAC-SHA512 is used as the pseudo-random function.
412-
// The length of the derived key is 512 bits (= 64 bytes).
413-
const PBKDF2_ROUNDS: u32 = 2048;
414-
const PBKDF2_BYTES: usize = 64;
415-
416408
// the phrase has been normalized
417-
let normalized_password = self.phrase();
418-
let normalized_salt = {
419-
let mut salt = Cow::Owned(format!("mnemonic{}", passphrase.as_ref()));
420-
normalize_utf8(&mut salt);
421-
salt
422-
};
423-
424-
let mut seed = [0u8; PBKDF2_BYTES];
425-
pbkdf2::pbkdf2::<Hmac<Sha512>>(
426-
normalized_password.as_bytes(),
427-
normalized_salt.as_bytes(),
428-
PBKDF2_ROUNDS,
429-
&mut seed,
430-
)
431-
.expect("HMAC can be initialized with any key length");
432-
seed
409+
to_seed(self.phrase(), passphrase.as_ref())
433410
}
434411

435412
/// Returns the mnemonic phrase as a string slice.
@@ -688,26 +665,8 @@ assert_eq!(result.unwrap_err(), Error::UnknownWord("ばか".nfkd().to_string()))
688665
/// assert_eq!(seed.len(), 64);
689666
/// ```
690667
pub fn to_seed<P: AsRef<str>>(&self, passphrase: P) -> [u8; 64] {
691-
// same as Mnemonic::to_seed; phrase is already normalized
692-
const PBKDF2_ROUNDS: u32 = 2048;
693-
const PBKDF2_BYTES: usize = 64;
694-
695-
let normalized_password = self.phrase();
696-
let normalized_salt = {
697-
let mut salt = Cow::Owned(format!("mnemonic{}", passphrase.as_ref()));
698-
normalize_utf8(&mut salt);
699-
salt
700-
};
701-
702-
let mut seed = [0u8; PBKDF2_BYTES];
703-
pbkdf2::pbkdf2::<Hmac<Sha512>>(
704-
normalized_password.as_bytes(),
705-
normalized_salt.as_bytes(),
706-
PBKDF2_ROUNDS,
707-
&mut seed,
708-
)
709-
.expect("HMAC can be initialized with any key length");
710-
seed
668+
// phrase is already normalized
669+
to_seed(self.phrase(), passphrase.as_ref())
711670
}
712671

713672
/// Returns the language used to encode/decode this mnemonic.

bip0039/src/mnemonic/seed.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//! Seed derivation for BIP-0039.
2+
//!
3+
//! This module contains the PBKDF2-HMAC-SHA512 logic for turning a normalized mnemonic phrase
4+
//! into a 64-byte seed.
5+
6+
#[cfg(not(feature = "std"))]
7+
use alloc::{borrow::Cow, format};
8+
use hmac::Hmac;
9+
use sha2::Sha512;
10+
#[cfg(feature = "std")]
11+
use std::borrow::Cow;
12+
13+
use super::normalize_utf8;
14+
15+
const PBKDF2_ROUNDS: u32 = 2048;
16+
const PBKDF2_BYTES: usize = 64;
17+
18+
/// Derives a 64-byte seed from a normalized mnemonic phrase and a passphrase.
19+
///
20+
/// Notes:
21+
/// - `normalized_phrase` must already be normalized to UTF-8 NFKD.
22+
/// - The salt is `"mnemonic{passphrase}"`, normalized to UTF-8 NFKD.
23+
pub fn to_seed(normalized_phrase: &str, passphrase: &str) -> [u8; 64] {
24+
// use the PBKDF2 function with a mnemonic sentence (in UTF-8 NFKD) used as the password
25+
// and the string "mnemonic" + passphrase (again in UTF-8 NFKD) used as the salt.
26+
// The iteration count is set to 2048 and HMAC-SHA512 is used as the pseudo-random function.
27+
// The length of the derived key is 512 bits (= 64 bytes).
28+
29+
let normalized_password = normalized_phrase;
30+
let normalized_salt = {
31+
let mut salt = Cow::Owned(format!("mnemonic{}", passphrase));
32+
normalize_utf8(&mut salt);
33+
salt
34+
};
35+
let mut seed = [0u8; PBKDF2_BYTES];
36+
pbkdf2::pbkdf2::<Hmac<Sha512>>(
37+
normalized_password.as_bytes(),
38+
normalized_salt.as_bytes(),
39+
PBKDF2_ROUNDS,
40+
&mut seed,
41+
)
42+
.expect("HMAC can be initialized with any key length");
43+
seed
44+
}

0 commit comments

Comments
 (0)