ergo_lib/wallet/
mnemonic.rs1use hmac::Hmac;
4use pbkdf2::pbkdf2;
5use sha2::Sha512;
6extern crate unicode_normalization;
7use unicode_normalization::UnicodeNormalization;
8
9const SHA512_OUTPUT_LEN: usize = 512 / 8;
11
12pub type MnemonicSeed = [u8; SHA512_OUTPUT_LEN];
14
15#[derive(PartialEq, Eq, Debug, Clone)]
17pub struct Mnemonic();
18
19impl Mnemonic {
20 const PBKDF2_ITERATIONS: u32 = 2048;
21
22 pub fn to_seed(mnemonic_phrase: &str, mnemonic_pass: &str) -> MnemonicSeed {
25 let mut seed: MnemonicSeed = [0u8; SHA512_OUTPUT_LEN];
26 let normalized_phrase = mnemonic_phrase.nfkd().collect::<String>();
27 let normalized_pass = mnemonic_pass.nfkd().collect::<String>();
28 pbkdf2::<Hmac<Sha512>>(
29 normalized_phrase.as_bytes(),
30 format!("mnemonic{}", normalized_pass).as_bytes(),
31 Mnemonic::PBKDF2_ITERATIONS,
32 &mut seed,
33 );
34
35 seed
36 }
37}
38
39#[cfg(test)]
40#[allow(clippy::unwrap_used)]
41mod tests {
42 use super::*;
43
44 #[test]
45 fn test_mnemonic_to_seed() {
46 let mnemonic = "change me do not use me change me do not use me";
47 let seed = Mnemonic::to_seed(mnemonic, "");
48 let encoded_seed = base16::encode_lower(&seed);
49 let expected = "c5b2537b52b27b903b34c423783ced17c489e4385ec6d49d6a19a7f892ecd3917db36675de36bcbe3b8dbc6f803877f4155bdf83482ca5f0fc4282a61ac842a3";
50
51 assert_eq!(encoded_seed, expected);
52 }
53
54 #[test]
55 fn test_mnemonic_to_seed_with_pass() {
56 let mnemonic = "change me do not use me change me do not use me";
57 let seed = Mnemonic::to_seed(mnemonic, "password123");
58 let encoded_seed = base16::encode_lower(&seed);
59 let expected = "dfe3088b88e2eb8588482e8c56d9cde497c4e1f63fd29b480cbb0ed0227331d51301cfc2d461acce642868ecb618a37b4fd75d48dc6189674c55fbafd807d69c";
60
61 assert_eq!(encoded_seed, expected);
62 }
63}