//! 助记词管理模块 //! //! 实现BIP39助记词导入、验证、密钥派生和地址生成 use crate::WalletError; use sha2::{Sha256, Sha512, Digest}; use std::collections::HashMap; /// BIP39助记词语言 #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Language { /// 英语 English, /// 简体中文 SimplifiedChinese, /// 繁体中文 TraditionalChinese, /// 日语 Japanese, /// 韩语 Korean, /// 法语 French, /// 意大利语 Italian, /// 西班牙语 Spanish, } /// 助记词长度 #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum MnemonicLength { /// 12个单词 (128位熵) Words12 = 12, /// 15个单词 (160位熵) Words15 = 15, /// 18个单词 (192位熵) Words18 = 18, /// 21个单词 (224位熵) Words21 = 21, /// 24个单词 (256位熵) Words24 = 24, } impl MnemonicLength { /// 获取熵长度(位) pub fn entropy_bits(&self) -> usize { match self { MnemonicLength::Words12 => 128, MnemonicLength::Words15 => 160, MnemonicLength::Words18 => 192, MnemonicLength::Words21 => 224, MnemonicLength::Words24 => 256, } } /// 获取熵长度(字节) pub fn entropy_bytes(&self) -> usize { self.entropy_bits() / 8 } } /// 助记词 #[derive(Debug, Clone)] pub struct Mnemonic { /// 助记词单词列表 words: Vec, /// 语言 language: Language, /// 熵 entropy: Vec, } impl Mnemonic { /// 从单词列表创建助记词 pub fn from_words(words: Vec, language: Language) -> Result { // 验证单词数量 let word_count = words.len(); let valid_counts = [12, 15, 18, 21, 24]; if !valid_counts.contains(&word_count) { return Err(WalletError::KeyError( format!("Invalid word count: {}, expected one of {:?}", word_count, valid_counts) )); } // 验证每个单词 let wordlist = get_wordlist(language); for word in &words { if !wordlist.contains_key(word.as_str()) { return Err(WalletError::KeyError( format!("Invalid word: {}", word) )); } } // 将单词转换为索引 let indices: Vec = words.iter() .map(|w| *wordlist.get(w.as_str()).unwrap()) .collect(); // 从索引恢复熵和校验和 let entropy_bits = word_count * 11; let checksum_bits = entropy_bits / 33; let entropy_length = (entropy_bits - checksum_bits) / 8; let mut bits = Vec::new(); for index in indices { for i in (0..11).rev() { bits.push((index >> i) & 1 == 1); } } // 提取熵 let mut entropy = vec![0u8; entropy_length]; for (i, bit) in bits.iter().take(entropy_length * 8).enumerate() { if *bit { entropy[i / 8] |= 1 << (7 - (i % 8)); } } // 验证校验和 let mut hasher = Sha256::new(); hasher.update(&entropy); let hash = hasher.finalize(); let mut checksum_bits_actual = Vec::new(); for i in 0..checksum_bits { checksum_bits_actual.push((hash[i / 8] >> (7 - (i % 8))) & 1 == 1); } let checksum_bits_expected: Vec = bits.iter() .skip(entropy_length * 8) .copied() .collect(); if checksum_bits_actual != checksum_bits_expected { return Err(WalletError::KeyError( "Invalid checksum".to_string() )); } Ok(Mnemonic { words, language, entropy, }) } /// 从熵创建助记词 pub fn from_entropy(entropy: &[u8], language: Language) -> Result { // 验证熵长度 let entropy_bits = entropy.len() * 8; let valid_bits = [128, 160, 192, 224, 256]; if !valid_bits.contains(&entropy_bits) { return Err(WalletError::KeyError( format!("Invalid entropy length: {} bits", entropy_bits) )); } // 计算校验和 let mut hasher = Sha256::new(); hasher.update(entropy); let hash = hasher.finalize(); let checksum_bits = entropy_bits / 32; // 组合熵和校验和 let mut bits = Vec::new(); for byte in entropy { for i in (0..8).rev() { bits.push((byte >> i) & 1 == 1); } } for i in 0..checksum_bits { bits.push((hash[i / 8] >> (7 - (i % 8))) & 1 == 1); } // 将11位分组转换为单词索引 let wordlist_array = get_wordlist_array(language); let mut words = Vec::new(); for chunk in bits.chunks(11) { let mut index = 0u16; for (i, bit) in chunk.iter().enumerate() { if *bit { index |= 1 << (10 - i); } } words.push(wordlist_array[index as usize].to_string()); } Ok(Mnemonic { words, language, entropy: entropy.to_vec(), }) } /// 获取助记词单词列表 pub fn words(&self) -> &[String] { &self.words } /// 获取助记词字符串 pub fn phrase(&self) -> String { self.words.join(" ") } /// 获取熵 pub fn entropy(&self) -> &[u8] { &self.entropy } /// 获取语言 pub fn language(&self) -> Language { self.language } /// 派生种子(BIP39) pub fn to_seed(&self, passphrase: &str) -> Vec { let mnemonic = self.phrase(); let salt = format!("mnemonic{}", passphrase); // PBKDF2-HMAC-SHA512 pbkdf2_hmac_sha512( mnemonic.as_bytes(), salt.as_bytes(), 2048, 64 ) } } /// PBKDF2-HMAC-SHA512密钥派生 fn pbkdf2_hmac_sha512(password: &[u8], salt: &[u8], iterations: usize, output_len: usize) -> Vec { use hmac::{Hmac, Mac}; type HmacSha512 = Hmac; let mut output = vec![0u8; output_len]; let hlen = 64; // SHA512输出长度 let blocks = (output_len + hlen - 1) / hlen; for i in 1..=blocks { let mut mac = HmacSha512::new_from_slice(password).unwrap(); mac.update(salt); mac.update(&(i as u32).to_be_bytes()); let mut u = mac.finalize().into_bytes().to_vec(); let mut f = u.clone(); for _ in 1..iterations { let mut mac = HmacSha512::new_from_slice(password).unwrap(); mac.update(&u); u = mac.finalize().into_bytes().to_vec(); for (f_byte, u_byte) in f.iter_mut().zip(u.iter()) { *f_byte ^= u_byte; } } let start = (i - 1) * hlen; let end = std::cmp::min(start + hlen, output_len); output[start..end].copy_from_slice(&f[..end - start]); } output } /// 密钥派生路径(BIP32/BIP44) #[derive(Debug, Clone)] pub struct DerivationPath { /// 路径组件 components: Vec, } impl DerivationPath { /// 从字符串解析派生路径 /// 格式: m/44'/60'/0'/0/0 pub fn from_str(path: &str) -> Result { if !path.starts_with("m/") && !path.starts_with("M/") { return Err(WalletError::KeyError( "Derivation path must start with m/ or M/".to_string() )); } let parts: Vec<&str> = path[2..].split('/').collect(); let mut components = Vec::new(); for part in parts { if part.is_empty() { continue; } let (index_str, hardened) = if part.ends_with('\'') || part.ends_with('h') { (&part[..part.len() - 1], true) } else { (part, false) }; let index: u32 = index_str.parse() .map_err(|_| WalletError::KeyError( format!("Invalid index in derivation path: {}", part) ))?; let component = if hardened { index | 0x80000000 } else { index }; components.push(component); } Ok(DerivationPath { components }) } /// 创建标准BIP44路径 /// m/44'/coin_type'/account'/change/address_index pub fn bip44(coin_type: u32, account: u32, change: u32, address_index: u32) -> Self { DerivationPath { components: vec![ 44 | 0x80000000, // purpose: 44' (BIP44) coin_type | 0x80000000, // coin_type: hardened account | 0x80000000, // account: hardened change, // change: 0=external, 1=internal address_index, // address_index ], } } /// 获取路径组件 pub fn components(&self) -> &[u32] { &self.components } /// 转换为字符串 pub fn to_string(&self) -> String { let mut path = String::from("m"); for component in &self.components { let hardened = component & 0x80000000 != 0; let index = component & 0x7fffffff; path.push('/'); path.push_str(&index.to_string()); if hardened { path.push('\''); } } path } } /// 扩展密钥 #[derive(Debug, Clone)] pub struct ExtendedKey { /// 私钥 private_key: Vec, /// 链码 chain_code: Vec, /// 深度 depth: u8, /// 父指纹 parent_fingerprint: [u8; 4], /// 子索引 child_index: u32, } impl ExtendedKey { /// 从种子创建主密钥 pub fn from_seed(seed: &[u8]) -> Result { use hmac::{Hmac, Mac}; type HmacSha512 = Hmac; let mut mac = HmacSha512::new_from_slice(b"Bitcoin seed") .map_err(|e| WalletError::KeyError(e.to_string()))?; mac.update(seed); let result = mac.finalize().into_bytes(); let private_key = result[..32].to_vec(); let chain_code = result[32..].to_vec(); Ok(ExtendedKey { private_key, chain_code, depth: 0, parent_fingerprint: [0; 4], child_index: 0, }) } /// 派生子密钥 pub fn derive(&self, index: u32) -> Result { use hmac::{Hmac, Mac}; type HmacSha512 = Hmac; let hardened = index & 0x80000000 != 0; let mut mac = HmacSha512::new_from_slice(&self.chain_code) .map_err(|e| WalletError::KeyError(e.to_string()))?; if hardened { // 硬化派生: HMAC-SHA512(Key = cpar, Data = 0x00 || ser256(kpar) || ser32(i)) mac.update(&[0]); mac.update(&self.private_key); } else { // 普通派生: HMAC-SHA512(Key = cpar, Data = serP(point(kpar)) || ser32(i)) // 简化实现:使用私钥 mac.update(&self.private_key); } mac.update(&index.to_be_bytes()); let result = mac.finalize().into_bytes(); let child_key = result[..32].to_vec(); let child_chain = result[32..].to_vec(); // 计算父指纹(简化实现) let mut hasher = Sha256::new(); hasher.update(&self.private_key); let hash = hasher.finalize(); let mut parent_fingerprint = [0u8; 4]; parent_fingerprint.copy_from_slice(&hash[..4]); Ok(ExtendedKey { private_key: child_key, chain_code: child_chain, depth: self.depth + 1, parent_fingerprint, child_index: index, }) } /// 按路径派生 pub fn derive_path(&self, path: &DerivationPath) -> Result { let mut key = self.clone(); for &component in path.components() { key = key.derive(component)?; } Ok(key) } /// 获取私钥 pub fn private_key(&self) -> &[u8] { &self.private_key } /// 获取链码 pub fn chain_code(&self) -> &[u8] { &self.chain_code } } /// 地址生成器 pub struct AddressGenerator; impl AddressGenerator { /// 从扩展密钥生成地址 pub fn from_extended_key(key: &ExtendedKey) -> String { // 使用私钥生成地址(简化实现) let mut hasher = Sha256::new(); hasher.update(key.private_key()); let hash = hasher.finalize(); // 转换为十六进制字符串 format!("0x{}", hex::encode(&hash[..20])) } /// 从助记词和路径生成地址 pub fn from_mnemonic(mnemonic: &Mnemonic, path: &DerivationPath, passphrase: &str) -> Result { let seed = mnemonic.to_seed(passphrase); let master_key = ExtendedKey::from_seed(&seed)?; let derived_key = master_key.derive_path(path)?; Ok(Self::from_extended_key(&derived_key)) } /// 批量生成地址 pub fn generate_addresses( mnemonic: &Mnemonic, coin_type: u32, account: u32, count: usize, passphrase: &str ) -> Result, WalletError> { let mut addresses = Vec::new(); let seed = mnemonic.to_seed(passphrase); let master_key = ExtendedKey::from_seed(&seed)?; for i in 0..count { let path = DerivationPath::bip44(coin_type, account, 0, i as u32); let derived_key = master_key.derive_path(&path)?; let address = Self::from_extended_key(&derived_key); addresses.push((address, path)); } Ok(addresses) } } /// 获取单词列表(单词 -> 索引) fn get_wordlist(language: Language) -> HashMap<&'static str, u16> { let words = get_wordlist_array(language); words.iter() .enumerate() .map(|(i, &word)| (word, i as u16)) .collect() } /// 获取单词列表数组(索引 -> 单词) fn get_wordlist_array(language: Language) -> &'static [&'static str] { match language { Language::English => &ENGLISH_WORDLIST, Language::SimplifiedChinese => &CHINESE_SIMPLIFIED_WORDLIST, _ => &ENGLISH_WORDLIST, // 其他语言暂时使用英语 } } /// 英语单词列表(BIP39标准,2048个单词) /// 这里只列出前20个作为示例,实际应包含全部2048个单词 const ENGLISH_WORDLIST: &[&str] = &[ "abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", "abuse", "access", "accident", "account", "accuse", "achieve", "acid", "acoustic", "acquire", "across", "act", // ... 省略其余2028个单词 // 实际使用时应包含完整的2048个BIP39英语单词 ]; /// 简体中文单词列表(BIP39标准,2048个单词) const CHINESE_SIMPLIFIED_WORDLIST: &[&str] = &[ "的", "一", "是", "在", "不", "了", "有", "和", "人", "这", "中", "大", "为", "上", "个", "国", "我", "以", "要", "他", // ... 省略其余2028个单词 ]; #[cfg(test)] mod tests { use super::*; #[test] fn test_mnemonic_from_entropy() { let entropy = vec![0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0]; let mnemonic = Mnemonic::from_entropy(&entropy, Language::English).unwrap(); assert_eq!(mnemonic.words().len(), 12); assert_eq!(mnemonic.entropy(), &entropy); } #[test] fn test_mnemonic_to_seed() { let entropy = vec![0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0]; let mnemonic = Mnemonic::from_entropy(&entropy, Language::English).unwrap(); let seed = mnemonic.to_seed(""); assert_eq!(seed.len(), 64); } #[test] fn test_derivation_path_parse() { let path = DerivationPath::from_str("m/44'/60'/0'/0/0").unwrap(); assert_eq!(path.components().len(), 5); assert_eq!(path.components()[0], 44 | 0x80000000); assert_eq!(path.components()[1], 60 | 0x80000000); assert_eq!(path.components()[4], 0); } #[test] fn test_derivation_path_bip44() { let path = DerivationPath::bip44(60, 0, 0, 0); assert_eq!(path.components().len(), 5); assert_eq!(path.to_string(), "m/44'/60'/0'/0/0"); } #[test] fn test_extended_key_from_seed() { let seed = vec![0u8; 64]; let key = ExtendedKey::from_seed(&seed).unwrap(); assert_eq!(key.private_key().len(), 32); assert_eq!(key.chain_code().len(), 32); assert_eq!(key.depth, 0); } #[test] fn test_extended_key_derive() { let seed = vec![0u8; 64]; let master = ExtendedKey::from_seed(&seed).unwrap(); let child = master.derive(0).unwrap(); assert_eq!(child.depth, 1); assert_eq!(child.child_index, 0); } #[test] fn test_extended_key_derive_path() { let seed = vec![0u8; 64]; let master = ExtendedKey::from_seed(&seed).unwrap(); let path = DerivationPath::bip44(60, 0, 0, 0); let derived = master.derive_path(&path).unwrap(); assert_eq!(derived.depth, 5); } #[test] fn test_address_from_extended_key() { let seed = vec![0u8; 64]; let key = ExtendedKey::from_seed(&seed).unwrap(); let address = AddressGenerator::from_extended_key(&key); assert!(address.starts_with("0x")); assert_eq!(address.len(), 42); // 0x + 40 hex chars } #[test] fn test_address_from_mnemonic() { let entropy = vec![0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0]; let mnemonic = Mnemonic::from_entropy(&entropy, Language::English).unwrap(); let path = DerivationPath::bip44(60, 0, 0, 0); let address = AddressGenerator::from_mnemonic(&mnemonic, &path, "").unwrap(); assert!(address.starts_with("0x")); } #[test] fn test_generate_addresses() { let entropy = vec![0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0]; let mnemonic = Mnemonic::from_entropy(&entropy, Language::English).unwrap(); let addresses = AddressGenerator::generate_addresses(&mnemonic, 60, 0, 5, "").unwrap(); assert_eq!(addresses.len(), 5); for (address, _path) in addresses { assert!(address.starts_with("0x")); } } #[test] fn test_invalid_word_count() { let words = vec!["abandon".to_string(); 11]; // 无效数量 let result = Mnemonic::from_words(words, Language::English); assert!(result.is_err()); } #[test] fn test_invalid_entropy_length() { let entropy = vec![0u8; 15]; // 无效长度 let result = Mnemonic::from_entropy(&entropy, Language::English); assert!(result.is_err()); } }