From cf2daed8e8c4d105440d0f944f4f066935ac514e Mon Sep 17 00:00:00 2001 From: Christian Reitter Date: Sun, 29 Jun 2025 19:27:49 +0200 Subject: [PATCH] Optimize expensive BIP39 seed generation --- src/lib.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index bd9223e..c32a687 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,6 +78,8 @@ mod pbkdf2; pub use language::Language; +use fastpbkdf2::pbkdf2_hmac_sha512; + /// The minimum number of words in a mnemonic. #[allow(unused)] const MIN_NB_WORDS: usize = 12; @@ -548,12 +550,42 @@ impl Mnemonic { } /// Convert to seed bytes with a passphrase in normalized UTF8. + /// Optimized fastpbkdf2 variant pub fn to_seed_normalized(&self, normalized_passphrase: &str) -> [u8; 64] { const PBKDF2_ROUNDS: usize = 2048; const PBKDF2_BYTES: usize = 64; + let mut seed = [0u8; PBKDF2_BYTES]; + + // prepare vector with mnemonic + let mut mnemonic_string_vec : Vec = 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]; + pbkdf2::pbkdf2(self.words(), normalized_passphrase.as_bytes(), PBKDF2_ROUNDS, &mut seed); + seed }