1use bip32::{
10 ChainCode, ChildNumber, DerivationPath, ExtendedKey, ExtendedKeyAttrs, ExtendedPrivateKey,
11 ExtendedPublicKey, Prefix,
12};
13pub use bip39::{Language, Mnemonic};
14use secp256k1::{PublicKey, SecretKey as PrivateKey};
15
16pub const VET_EXTERNAL_PATH: &str = "m/44'/818'/0'/0";
18
19#[derive(Clone, Debug, Eq, PartialEq)]
22enum HDNodeVariant {
23 Full(ExtendedPrivateKey<PrivateKey>),
24 Restricted(ExtendedPublicKey<PublicKey>),
25}
26use HDNodeVariant::{Full, Restricted};
27
28#[derive(Clone, Debug, Eq, PartialEq)]
33pub struct HDNode(HDNodeVariant);
34
35impl HDNode {
36 pub fn build<'a>() -> HDNodeBuilder<'a> {
37 HDNodeBuilder::default()
39 }
40
41 pub fn derive(&self, index: u32) -> Result<Self, HDNodeError> {
42 let child = match &self.0 {
44 Full(privkey) => Self(Full(privkey.derive_child(ChildNumber(index))?)),
45 Restricted(pubkey) => Self(Restricted(pubkey.derive_child(ChildNumber(index))?)),
46 };
47 Ok(child)
48 }
49
50 pub fn public_key(&self) -> ExtendedPublicKey<PublicKey> {
51 match &self.0 {
53 Full(privkey) => privkey.public_key(),
54 Restricted(pubkey) => pubkey.clone(),
55 }
56 }
57 pub fn private_key(&self) -> Result<ExtendedPrivateKey<PrivateKey>, HDNodeError> {
58 match &self.0 {
60 Full(privkey) => Ok(privkey.clone()),
61 Restricted(_) => Err(HDNodeError::Crypto),
62 }
63 }
64 pub fn chain_code(&self) -> ChainCode {
65 match &self.0 {
67 Full(privkey) => privkey.attrs().chain_code,
68 Restricted(pubkey) => pubkey.attrs().chain_code,
69 }
70 }
71 pub fn parent_fingerprint(&self) -> [u8; 4] {
72 match &self.0 {
74 Full(privkey) => privkey.attrs().parent_fingerprint,
75 Restricted(pubkey) => pubkey.attrs().parent_fingerprint,
76 }
77 }
78 pub fn child_number(&self) -> ChildNumber {
79 match &self.0 {
81 Full(privkey) => privkey.attrs().child_number,
82 Restricted(pubkey) => pubkey.attrs().child_number,
83 }
84 }
85 pub fn depth(&self) -> u8 {
86 match &self.0 {
88 Full(privkey) => privkey.attrs().depth,
89 Restricted(pubkey) => pubkey.attrs().depth,
90 }
91 }
92 pub fn address(&self) -> crate::address::Address {
93 use crate::address::AddressConvertible;
95
96 match &self.0 {
97 Full(privkey) => privkey.public_key().public_key().address(),
98 Restricted(pubkey) => pubkey.public_key().address(),
99 }
100 }
101}
102
103#[derive(Clone, Debug, PartialEq, Eq)]
105pub enum HDNodeError {
106 Crypto,
108 Parse,
110 WrongChildNumber,
112 Unbuildable(String),
114 Custom(String),
116}
117
118#[cfg(not(tarpaulin_include))]
119impl std::fmt::Display for HDNodeError {
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 match self {
122 Self::Crypto => f.write_str("cryptography error"),
123 Self::Parse => f.write_str("decoding error"),
124 Self::WrongChildNumber => {
125 f.write_str("cannot derive hardened children from public key")
126 }
127 Self::Unbuildable(msg) => {
128 f.write_str("cannot build HDNode:")?;
129 f.write_str(msg)
130 }
131 Self::Custom(msg) => f.write_str(msg),
132 }
133 }
134}
135impl std::error::Error for HDNodeError {}
136
137#[cfg(not(tarpaulin_include))]
138impl From<bip32::Error> for HDNodeError {
139 fn from(err: bip32::Error) -> HDNodeError {
140 match err {
141 bip32::Error::Crypto => HDNodeError::Crypto,
142 bip32::Error::Decode => HDNodeError::Parse,
143 bip32::Error::ChildNumber => HDNodeError::WrongChildNumber,
144 err => HDNodeError::Custom(format!("{:?}", err)),
145 }
146 }
147}
148
149#[derive(Clone, Default)]
180pub struct HDNodeBuilder<'a> {
181 path: Option<DerivationPath>,
182 seed: Option<[u8; 64]>,
183 mnemonic: Option<Mnemonic>,
184 password: Option<&'a str>,
185 ext_privkey: Option<ExtendedKey>,
186 ext_pubkey: Option<ExtendedKey>,
187}
188
189impl<'a> HDNodeBuilder<'a> {
190 pub fn path(mut self, path: DerivationPath) -> Self {
191 self.path = Some(path);
195 self
196 }
197 pub const fn seed(mut self, seed: [u8; 64]) -> Self {
198 self.seed = Some(seed);
200 self
201 }
202
203 pub fn mnemonic(mut self, mnemonic: Mnemonic) -> Self {
204 self.mnemonic = Some(mnemonic);
208 self
209 }
210 pub fn mnemonic_with_password(mut self, mnemonic: Mnemonic, password: &'a str) -> Self {
211 self.mnemonic = Some(mnemonic);
215 self.password = Some(password);
216 self
217 }
218
219 pub fn master_private_key_bytes<T: Into<ChainCode>>(
220 mut self,
221 key: [u8; 33],
222 chain_code: T,
223 ) -> Self {
224 self.ext_privkey = Some(ExtendedKey {
226 prefix: Prefix::XPRV,
227 attrs: ExtendedKeyAttrs {
228 depth: 0,
229 parent_fingerprint: [0; 4],
230 child_number: ChildNumber(0u32),
231 chain_code: chain_code.into(),
232 },
233 key_bytes: key,
234 });
235 self
236 }
237 pub fn private_key(mut self, ext_key: ExtendedKey) -> Self {
238 self.ext_privkey = Some(ext_key);
240 self
241 }
242
243 pub fn master_public_key_bytes<T: Into<ChainCode>>(
244 mut self,
245 key: [u8; 33],
246 chain_code: T,
247 ) -> Self {
248 self.ext_pubkey = Some(ExtendedKey {
254 prefix: Prefix::XPUB,
255 attrs: ExtendedKeyAttrs {
256 depth: 0,
257 parent_fingerprint: [0; 4],
258 child_number: ChildNumber(0u32),
259 chain_code: chain_code.into(),
260 },
261 key_bytes: key,
262 });
263 self
264 }
265 pub fn public_key(mut self, ext_key: ExtendedKey) -> Self {
266 self.ext_pubkey = Some(ext_key);
272 self
273 }
274
275 pub fn build(self) -> Result<HDNode, HDNodeError> {
276 match (self.seed, self.mnemonic, self.ext_privkey, self.ext_pubkey) {
278 (Some(seed), None, None, None) => {
279 let path = self.path.unwrap_or_else(|| {
280 VET_EXTERNAL_PATH
281 .parse()
282 .expect("hardcoded path must be valid")
283 });
284 Ok(ExtendedPrivateKey::derive_from_path(seed, &path).map(|k| HDNode(Full(k)))?)
285 }
286 (None, Some(mnemonic), None, None) => {
287 let path = self.path.unwrap_or_else(|| {
288 VET_EXTERNAL_PATH
289 .parse()
290 .expect("hardcoded path must be valid")
291 });
292 Ok(ExtendedPrivateKey::derive_from_path(
293 bip39::Seed::new(&mnemonic, self.password.unwrap_or("")),
294 &path,
295 )
296 .map(|k| HDNode(Full(k)))?)
297 }
298 (None, None, Some(ext_key), None) => Ok(HDNode(Full(ext_key.try_into()?))),
299 (None, None, None, Some(ext_key)) => Ok(HDNode(Restricted(ext_key.try_into()?))),
300 (None, None, None, None) => Err(HDNodeError::Unbuildable(
301 "no parameters provided".to_string(),
302 )),
303 _ => Err(HDNodeError::Unbuildable(
304 "incompatible parameters".to_string(),
305 )),
306 }
307 }
308}