kaspa_bip32/
xprivate_key.rs1use hmac::Mac;
2use std::fmt::{self, Debug};
3use std::str::FromStr;
4use subtle::{Choice, ConstantTimeEq};
5use zeroize::{Zeroize, Zeroizing};
6
7use crate::{
8 ChildNumber, DerivationPath, ExtendedKey, ExtendedKeyAttrs, ExtendedPublicKey, Prefix, PrivateKey, PublicKey, result::Result,
9 types::*,
10};
11
12const BIP39_DOMAIN_SEPARATOR: [u8; 12] = [0x42, 0x69, 0x74, 0x63, 0x6f, 0x69, 0x6e, 0x20, 0x73, 0x65, 0x65, 0x64];
14
15#[derive(Clone)]
19pub struct ExtendedPrivateKey<K: PrivateKey> {
20 private_key: K,
22
23 attrs: ExtendedKeyAttrs,
25}
26
27impl<K> ExtendedPrivateKey<K>
28where
29 K: PrivateKey,
30{
31 pub const MAX_DEPTH: Depth = u8::MAX;
33
34 pub fn new<S>(seed: S) -> Result<Self>
36 where
37 S: AsRef<[u8]>,
38 {
39 if ![16, 32, 64].contains(&seed.as_ref().len()) {
40 return Err(Error::SeedLength);
41 }
42
43 let mut hmac = HmacSha512::new_from_slice(&BIP39_DOMAIN_SEPARATOR)?;
44 hmac.update(seed.as_ref());
45
46 let result = hmac.finalize().into_bytes();
47 let (secret_key, chain_code) = result.split_at(KEY_SIZE);
49 let private_key = PrivateKey::from_bytes(secret_key.try_into()?)?;
50 let attrs = ExtendedKeyAttrs {
51 depth: 0,
52 parent_fingerprint: KeyFingerprint::default(),
53 child_number: ChildNumber::default(),
54 chain_code: chain_code.try_into()?,
55 };
56
57 Ok(ExtendedPrivateKey { private_key, attrs })
58 }
59
60 pub fn derive_child(&self, child_number: ChildNumber) -> Result<Self> {
62 let depth = self.attrs.depth.checked_add(1).ok_or(Error::Depth)?;
63
64 let mut hmac = HmacSha512::new_from_slice(&self.attrs.chain_code).map_err(Error::Hmac)?;
65
66 if child_number.is_hardened() {
67 hmac.update(&[0]);
68 hmac.update(&self.private_key.to_bytes());
69 } else {
70 hmac.update(&self.private_key.public_key().to_bytes());
71 }
72
73 hmac.update(&child_number.to_bytes());
74
75 let result = hmac.finalize().into_bytes();
76 let (child_key, chain_code) = result.split_at(KEY_SIZE);
77
78 let private_key = self.private_key.derive_child(child_key.try_into()?)?;
88
89 let attrs = ExtendedKeyAttrs {
90 parent_fingerprint: self.private_key.public_key().fingerprint(),
91 child_number,
92 chain_code: chain_code.try_into()?,
93 depth,
94 };
95
96 Ok(ExtendedPrivateKey { private_key, attrs })
97 }
98
99 pub fn derive_path(self, path: &DerivationPath) -> Result<Self> {
100 path.iter().try_fold(self, |key, child_num| key.derive_child(child_num))
101 }
102
103 pub fn private_key(&self) -> &K {
105 &self.private_key
106 }
107
108 pub fn public_key(&self) -> ExtendedPublicKey<K::PublicKey> {
110 self.into()
111 }
112
113 pub fn attrs(&self) -> &ExtendedKeyAttrs {
116 &self.attrs
117 }
118
119 pub fn to_bytes(&self) -> PrivateKeyBytes {
121 self.private_key.to_bytes()
122 }
123
124 pub fn to_extended_key(&self, prefix: Prefix) -> ExtendedKey {
126 let mut key_bytes = [0u8; KEY_SIZE + 1];
128 key_bytes[1..].copy_from_slice(&self.to_bytes());
129
130 ExtendedKey { prefix, attrs: self.attrs.clone(), key_bytes }
131 }
132
133 pub fn to_string(&self, prefix: Prefix) -> Zeroizing<String> {
134 Zeroizing::new(self.to_extended_key(prefix).to_string())
135 }
136}
137
138impl<K> ConstantTimeEq for ExtendedPrivateKey<K>
139where
140 K: PrivateKey,
141{
142 fn ct_eq(&self, other: &Self) -> Choice {
143 let mut key_a = self.to_bytes();
144 let mut key_b = other.to_bytes();
145
146 let result = key_a.ct_eq(&key_b)
147 & self.attrs.depth.ct_eq(&other.attrs.depth)
148 & self.attrs.parent_fingerprint.ct_eq(&other.attrs.parent_fingerprint)
149 & self.attrs.child_number.0.ct_eq(&other.attrs.child_number.0)
150 & self.attrs.chain_code.ct_eq(&other.attrs.chain_code);
151
152 key_a.zeroize();
153 key_b.zeroize();
154
155 result
156 }
157}
158
159impl<K> Debug for ExtendedPrivateKey<K>
160where
161 K: PrivateKey,
162{
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 f.debug_struct("ExtendedPrivateKey").field("private_key", &"...").field("attrs", &self.attrs).finish()
166 }
167}
168
169impl<K> Eq for ExtendedPrivateKey<K> where K: PrivateKey {}
171
172impl<K> PartialEq for ExtendedPrivateKey<K>
174where
175 K: PrivateKey,
176{
177 fn eq(&self, other: &Self) -> bool {
178 self.ct_eq(other).into()
179 }
180}
181
182impl<K> FromStr for ExtendedPrivateKey<K>
183where
184 K: PrivateKey,
185{
186 type Err = Error;
187
188 fn from_str(xprv: &str) -> Result<Self> {
189 let key = ExtendedKey::from_str(xprv)?;
190 key.try_into()
191 }
192}
193
194impl<K> TryFrom<ExtendedKey> for ExtendedPrivateKey<K>
195where
196 K: PrivateKey,
197{
198 type Error = Error;
199
200 fn try_from(extended_key: ExtendedKey) -> Result<ExtendedPrivateKey<K>> {
201 if extended_key.prefix.is_private() && extended_key.key_bytes[0] == 0 {
202 Ok(ExtendedPrivateKey {
203 private_key: PrivateKey::from_bytes(extended_key.key_bytes[1..].try_into()?)?,
204 attrs: extended_key.attrs.clone(),
205 })
206 } else {
207 Err(Error::Crypto(secp256k1::Error::InvalidSecretKey))
208 }
209 }
210}