Optimize expensive BIP39 seed generation

This commit is contained in:
Christian Reitter 2025-06-29 19:27:49 +02:00
parent 3204e18fa3
commit cf2daed8e8
1 changed files with 32 additions and 0 deletions

View File

@ -78,6 +78,8 @@ mod pbkdf2;
pub use language::Language; pub use language::Language;
use fastpbkdf2::pbkdf2_hmac_sha512;
/// The minimum number of words in a mnemonic. /// The minimum number of words in a mnemonic.
#[allow(unused)] #[allow(unused)]
const MIN_NB_WORDS: usize = 12; const MIN_NB_WORDS: usize = 12;
@ -548,12 +550,42 @@ impl Mnemonic {
} }
/// Convert to seed bytes with a passphrase in normalized UTF8. /// Convert to seed bytes with a passphrase in normalized UTF8.
/// Optimized fastpbkdf2 variant
pub fn to_seed_normalized(&self, normalized_passphrase: &str) -> [u8; 64] { pub fn to_seed_normalized(&self, normalized_passphrase: &str) -> [u8; 64] {
const PBKDF2_ROUNDS: usize = 2048; const PBKDF2_ROUNDS: usize = 2048;
const PBKDF2_BYTES: usize = 64; const PBKDF2_BYTES: usize = 64;
let mut seed = [0u8; PBKDF2_BYTES];
// prepare vector with mnemonic
let mut mnemonic_string_vec : Vec<String> = vec![];
for (_i, word) in self.words().enumerate() {
mnemonic_string_vec.push(word.to_string());
}
// generate actual salt as per BIP39 specification
let full_passphrase = format!("mnemonic{normalized_passphrase}");
// use the external fastpbkdf2 function
pbkdf2_hmac_sha512(
mnemonic_string_vec.join(" ").as_bytes(),
full_passphrase.as_bytes(),
PBKDF2_ROUNDS as u32,
&mut seed,
);
seed
}
/// Convert to seed bytes with a passphrase in normalized UTF8.
/// Stock implementation
pub fn to_seed_normalized_stock_variant(&self, normalized_passphrase: &str) -> [u8; 64] {
const PBKDF2_ROUNDS: usize = 2048;
const PBKDF2_BYTES: usize = 64;
let mut seed = [0u8; PBKDF2_BYTES]; let mut seed = [0u8; PBKDF2_BYTES];
pbkdf2::pbkdf2(self.words(), normalized_passphrase.as_bytes(), PBKDF2_ROUNDS, &mut seed); pbkdf2::pbkdf2(self.words(), normalized_passphrase.as_bytes(), PBKDF2_ROUNDS, &mut seed);
seed seed
} }