1use alloc::vec;
10use alloc::vec::Vec;
11use core::fmt;
12
13use bip39::Mnemonic;
14use secp256k1::{Secp256k1, Signing};
15
16mod bip32;
17
18use self::bip32::{ChildNumber, Xpriv};
19#[cfg(feature = "std")]
20use crate::SECP256K1;
21use crate::{Keys, SecretKey};
22
23const PURPOSE: u32 = 44;
24const COIN: u32 = 1237;
25
26#[derive(Debug, Eq, PartialEq)]
28pub enum Error {
29 BIP32(bip32::Error),
31 BIP39(bip39::Error),
33}
34
35#[cfg(feature = "std")]
36impl std::error::Error for Error {}
37
38impl fmt::Display for Error {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 match self {
41 Self::BIP32(e) => e.fmt(f),
42 Self::BIP39(e) => e.fmt(f),
43 }
44 }
45}
46
47impl From<bip32::Error> for Error {
48 fn from(e: bip32::Error) -> Self {
49 Self::BIP32(e)
50 }
51}
52
53impl From<bip39::Error> for Error {
54 fn from(e: bip39::Error) -> Self {
55 Self::BIP39(e)
56 }
57}
58
59pub trait FromMnemonic: Sized {
63 type Err;
65
66 #[inline]
70 #[cfg(feature = "std")]
71 fn from_mnemonic<S>(mnemonic: S, passphrase: Option<S>) -> Result<Self, Self::Err>
72 where
73 S: AsRef<str>,
74 {
75 Self::from_mnemonic_with_account(mnemonic, passphrase, None)
76 }
77
78 #[inline]
82 #[cfg(feature = "std")]
83 fn from_mnemonic_with_account<S>(
84 mnemonic: S,
85 passphrase: Option<S>,
86 account: Option<u32>,
87 ) -> Result<Self, Self::Err>
88 where
89 S: AsRef<str>,
90 {
91 Self::from_mnemonic_advanced(mnemonic, passphrase, account, None, None)
92 }
93
94 #[inline]
98 #[cfg(feature = "std")]
99 fn from_mnemonic_advanced<S>(
100 mnemonic: S,
101 passphrase: Option<S>,
102 account: Option<u32>,
103 r#type: Option<u32>,
104 index: Option<u32>,
105 ) -> Result<Self, Self::Err>
106 where
107 S: AsRef<str>,
108 {
109 Self::from_mnemonic_with_ctx(SECP256K1, mnemonic, passphrase, account, r#type, index)
110 }
111
112 fn from_mnemonic_with_ctx<C, S>(
118 secp: &Secp256k1<C>,
119 mnemonic: S,
120 passphrase: Option<S>,
121 account: Option<u32>,
122 r#type: Option<u32>,
123 index: Option<u32>,
124 ) -> Result<Self, Self::Err>
125 where
126 C: Signing,
127 S: AsRef<str>;
128}
129
130impl FromMnemonic for Keys {
131 type Err = Error;
132
133 fn from_mnemonic_with_ctx<C, S>(
134 secp: &Secp256k1<C>,
135 mnemonic: S,
136 passphrase: Option<S>,
137 account: Option<u32>,
138 r#type: Option<u32>,
139 index: Option<u32>,
140 ) -> Result<Self, Self::Err>
141 where
142 C: Signing,
143 S: AsRef<str>,
144 {
145 let mnemonic: Mnemonic = Mnemonic::parse_normalized(mnemonic.as_ref())?;
147
148 let seed: [u8; 64] = mnemonic
150 .to_seed_normalized(passphrase.as_ref().map(|s| s.as_ref()).unwrap_or_default());
151
152 let root_key: Xpriv = Xpriv::new_master(&seed)?;
154
155 let account: u32 = account.unwrap_or_default();
157 let _type: u32 = r#type.unwrap_or_default();
158 let index: u32 = index.unwrap_or_default();
159
160 let path: Vec<ChildNumber> = vec![
162 ChildNumber::from_hardened_idx(PURPOSE)?,
163 ChildNumber::from_hardened_idx(COIN)?,
164 ChildNumber::from_hardened_idx(account)?,
165 ChildNumber::from_normal_idx(_type)?,
166 ChildNumber::from_normal_idx(index)?,
167 ];
168
169 let child_xprv = root_key.derive_xpriv(secp, path);
171 let secret_key = SecretKey::from(child_xprv.private_key);
172
173 Ok(Self::new_with_ctx(secp, secret_key))
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use core::str::FromStr;
181
182 use super::*;
183
184 #[test]
185 fn test_nip06() {
186 let secp = Secp256k1::new();
187
188 let list = vec![
189 ("equal dragon fabric refuse stable cherry smoke allow alley easy never medal attend together lumber movie what sad siege weather matrix buffalo state shoot", "06992419a8fe821dd8de03d4c300614e8feefb5ea936b76f89976dcace8aebee"),
190 ("leader monkey parrot ring guide accident before fence cannon height naive bean", "7f7ff03d123792d6ac594bfa67bf6d0c0ab55b6b1fdb6249303fe861f1ccba9a"),
191 ("what bleak badge arrange retreat wolf trade produce cricket blur garlic valid proud rude strong choose busy staff weather area salt hollow arm fade", "c15d739894c81a2fcfd3a2df85a0d2c0dbc47a280d092799f144d73d7ae78add"),
192 ];
193
194 for (mnemonic, expected_secret_key) in list.into_iter() {
195 let keys =
196 Keys::from_mnemonic_with_ctx(&secp, mnemonic, None, None, None, None).unwrap();
197 assert_eq!(
198 keys.secret_key(),
199 &SecretKey::from_str(expected_secret_key).unwrap()
200 );
201 }
202 }
203}