use pbkdf2::pbkdf2_hmac_array;
use sha2::Sha512;
use unicode_normalization::UnicodeNormalization;
#[cfg(not(feature = "std"))]
use alloc::string::String;
pub const PBKDF2_ITERATIONS: u32 = 4096;
#[must_use]
pub fn mnemonic_to_seed(mnemonic: &str, passphrase: &str) -> [u8; 64] {
mnemonic_to_seed_with_iterations(mnemonic, passphrase, PBKDF2_ITERATIONS)
}
#[must_use]
pub fn mnemonic_to_seed_with_iterations(
mnemonic: &str,
passphrase: &str,
iterations: u32,
) -> [u8; 64] {
let normalized_mnemonic: String = mnemonic.nfkd().collect();
let normalized_passphrase: String = passphrase.nfkd().collect();
let mut salt = String::with_capacity(8 + normalized_passphrase.len());
salt.push_str("mnemonic");
salt.push_str(&normalized_passphrase);
pbkdf2_hmac_array::<Sha512, 64>(normalized_mnemonic.as_bytes(), salt.as_bytes(), iterations)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_seed_generation() {
let mnemonic =
"哀感天地 哀毁瘠立 挨肩叠背 唉声叹气 挨三顶五 矮子看戏 爱才若渴 暧昧不明 碍手碍脚 安邦定国 安分守己 安魂定魄";
let seed = mnemonic_to_seed(mnemonic, "");
assert_eq!(seed.len(), 64);
}
#[test]
fn test_seed_with_passphrase() {
let mnemonic = "哀感天地 哀毁瘠立 挨肩叠背 唉声叹气 挨三顶五 矮子看戏 爱才若渴 暧昧不明 碍手碍脚 安邦定国 安分守己 安魂定魄";
let seed1 = mnemonic_to_seed(mnemonic, "");
let seed2 = mnemonic_to_seed(mnemonic, "password");
assert_ne!(seed1, seed2);
}
#[test]
fn test_seed_consistency() {
let mnemonic = "哀感天地 哀毁瘠立 挨肩叠背 唉声叹气 挨三顶五 矮子看戏 爱才若渴 暧昧不明 碍手碍脚 安邦定国 安分守己 安魂定魄";
let seed1 = mnemonic_to_seed(mnemonic, "test");
let seed2 = mnemonic_to_seed(mnemonic, "test");
assert_eq!(seed1, seed2);
}
#[test]
fn test_seed_custom_iterations() {
let mnemonic = "哀感天地 哀毁瘠立 挨肩叠背 唉声叹气 挨三顶五 矮子看戏 爱才若渴 暧昧不明 碍手碍脚 安邦定国 安分守己 安魂定魄";
let seed_default = mnemonic_to_seed(mnemonic, "");
let seed_custom = mnemonic_to_seed_with_iterations(mnemonic, "", 4096);
assert_eq!(seed_default, seed_custom);
}
#[test]
fn test_nfkd_normalization_consistency() {
let mnemonic = "哀感天地 哀毁瘠立 挨肩叠背 唉声叹气 挨三顶五 矮子看戏 爱才若渴 暧昧不明 碍手碍脚 安邦定国 安分守己 安魂定魄";
let seed1 = mnemonic_to_seed(mnemonic, "TEST");
let seed2 = mnemonic_to_seed(mnemonic, "TEST");
assert_eq!(seed1, seed2);
let seed3 = mnemonic_to_seed(mnemonic, "密码🔑");
assert_eq!(seed3.len(), 64);
}
}