1use crate::error::HdError;
4use crate::network::Network;
5use crate::path::{DerivationPath, HARDENED_BIT};
6use hmac::{Hmac, Mac};
7use ripemd::Ripemd160;
8use rustywallet_keys::private_key::PrivateKey;
9use rustywallet_keys::public_key::PublicKey;
10use secp256k1::{Secp256k1, SecretKey};
11use sha2::{Digest, Sha256, Sha512};
12use std::fmt;
13use zeroize::Zeroizing;
14
15type HmacSha512 = Hmac<Sha512>;
16
17pub struct ExtendedPrivateKey {
38 private_key: Zeroizing<[u8; 32]>,
40 chain_code: Zeroizing<[u8; 32]>,
42 depth: u8,
44 parent_fingerprint: [u8; 4],
46 child_number: u32,
48 network: Network,
50}
51
52impl ExtendedPrivateKey {
53 pub fn from_seed(seed: &[u8], network: Network) -> Result<Self, HdError> {
57 if seed.len() != 64 {
58 return Err(HdError::InvalidSeedLength(seed.len()));
59 }
60
61 let mut mac =
63 HmacSha512::new_from_slice(b"Bitcoin seed").expect("HMAC can take key of any size");
64 mac.update(seed);
65 let result = mac.finalize().into_bytes();
66
67 let mut private_key = [0u8; 32];
68 let mut chain_code = [0u8; 32];
69 private_key.copy_from_slice(&result[..32]);
70 chain_code.copy_from_slice(&result[32..]);
71
72 SecretKey::from_slice(&private_key).map_err(|_| HdError::InvalidDerivedKey)?;
74
75 Ok(Self {
76 private_key: Zeroizing::new(private_key),
77 chain_code: Zeroizing::new(chain_code),
78 depth: 0,
79 parent_fingerprint: [0; 4],
80 child_number: 0,
81 network,
82 })
83 }
84
85 pub fn derive_child(&self, index: u32) -> Result<Self, HdError> {
89 let secp = Secp256k1::new();
90 let parent_key =
91 SecretKey::from_slice(&*self.private_key).map_err(|_| HdError::InvalidDerivedKey)?;
92
93 let mut mac =
94 HmacSha512::new_from_slice(&*self.chain_code).expect("HMAC can take key of any size");
95
96 if index >= HARDENED_BIT {
97 mac.update(&[0x00]);
99 mac.update(&*self.private_key);
100 } else {
101 let public_key = secp256k1::PublicKey::from_secret_key(&secp, &parent_key);
103 mac.update(&public_key.serialize());
104 }
105 mac.update(&index.to_be_bytes());
106
107 let result = mac.finalize().into_bytes();
108
109 let mut child_key_bytes = [0u8; 32];
110 let mut child_chain_code = [0u8; 32];
111 child_key_bytes.copy_from_slice(&result[..32]);
112 child_chain_code.copy_from_slice(&result[32..]);
113
114 let tweak =
116 SecretKey::from_slice(&child_key_bytes).map_err(|_| HdError::InvalidDerivedKey)?;
117 let child_key = parent_key
118 .add_tweak(&tweak.into())
119 .map_err(|_| HdError::InvalidDerivedKey)?;
120
121 let mut final_key = [0u8; 32];
122 final_key.copy_from_slice(&child_key.secret_bytes());
123
124 Ok(Self {
125 private_key: Zeroizing::new(final_key),
126 chain_code: Zeroizing::new(child_chain_code),
127 depth: self.depth.saturating_add(1),
128 parent_fingerprint: self.fingerprint(),
129 child_number: index,
130 network: self.network,
131 })
132 }
133
134 pub fn derive_hardened(&self, index: u32) -> Result<Self, HdError> {
136 if index >= HARDENED_BIT {
137 return Err(HdError::InvalidChildNumber(index));
138 }
139 self.derive_child(index | HARDENED_BIT)
140 }
141
142 pub fn derive_path(&self, path: &DerivationPath) -> Result<Self, HdError> {
144 let mut current = self.clone();
145 for child in path.components() {
146 current = current.derive_child(child.raw_index())?;
147 }
148 Ok(current)
149 }
150
151 pub fn extended_public_key(&self) -> ExtendedPublicKey {
153 let secp = Secp256k1::new();
154 let secret_key =
155 SecretKey::from_slice(&*self.private_key).expect("Private key should be valid");
156 let public_key = secp256k1::PublicKey::from_secret_key(&secp, &secret_key);
157
158 ExtendedPublicKey {
159 public_key: public_key.serialize(),
160 chain_code: *self.chain_code,
161 depth: self.depth,
162 parent_fingerprint: self.parent_fingerprint,
163 child_number: self.child_number,
164 network: self.network,
165 }
166 }
167
168 pub fn private_key(&self) -> Result<PrivateKey, HdError> {
170 PrivateKey::from_bytes(*self.private_key).map_err(|_| HdError::InvalidDerivedKey)
171 }
172
173 pub fn public_key(&self) -> PublicKey {
175 self.private_key()
176 .expect("Private key should be valid")
177 .public_key()
178 }
179
180 pub fn fingerprint(&self) -> [u8; 4] {
182 let secp = Secp256k1::new();
183 let secret_key =
184 SecretKey::from_slice(&*self.private_key).expect("Private key should be valid");
185 let public_key = secp256k1::PublicKey::from_secret_key(&secp, &secret_key);
186
187 let sha256 = Sha256::digest(public_key.serialize());
188 let hash160 = Ripemd160::digest(sha256);
189
190 let mut fingerprint = [0u8; 4];
191 fingerprint.copy_from_slice(&hash160[..4]);
192 fingerprint
193 }
194
195 pub fn depth(&self) -> u8 {
197 self.depth
198 }
199
200 pub fn chain_code(&self) -> &[u8; 32] {
202 &self.chain_code
203 }
204
205 pub fn network(&self) -> Network {
207 self.network
208 }
209
210 pub fn to_xprv(&self) -> String {
212 let mut data = Vec::with_capacity(78);
213
214 data.extend_from_slice(&self.network.xprv_version());
216 data.push(self.depth);
218 data.extend_from_slice(&self.parent_fingerprint);
220 data.extend_from_slice(&self.child_number.to_be_bytes());
222 data.extend_from_slice(&*self.chain_code);
224 data.push(0x00);
226 data.extend_from_slice(&*self.private_key);
227
228 bs58::encode(data).with_check().into_string()
229 }
230
231 pub fn from_xprv(xprv: &str) -> Result<Self, HdError> {
233 let data = bs58::decode(xprv)
234 .with_check(None)
235 .into_vec()
236 .map_err(|_| HdError::InvalidChecksum)?;
237
238 if data.len() != 78 {
239 return Err(HdError::InvalidExtendedKey);
240 }
241
242 let mut version = [0u8; 4];
243 version.copy_from_slice(&data[0..4]);
244
245 let (network, is_private) =
246 Network::from_version(&version).ok_or(HdError::InvalidVersion)?;
247
248 if !is_private {
249 return Err(HdError::InvalidExtendedKey);
250 }
251
252 let depth = data[4];
253
254 let mut parent_fingerprint = [0u8; 4];
255 parent_fingerprint.copy_from_slice(&data[5..9]);
256
257 let child_number = u32::from_be_bytes([data[9], data[10], data[11], data[12]]);
258
259 let mut chain_code = [0u8; 32];
260 chain_code.copy_from_slice(&data[13..45]);
261
262 if data[45] != 0x00 {
264 return Err(HdError::InvalidExtendedKey);
265 }
266
267 let mut private_key = [0u8; 32];
268 private_key.copy_from_slice(&data[46..78]);
269
270 SecretKey::from_slice(&private_key).map_err(|_| HdError::InvalidDerivedKey)?;
272
273 Ok(Self {
274 private_key: Zeroizing::new(private_key),
275 chain_code: Zeroizing::new(chain_code),
276 depth,
277 parent_fingerprint,
278 child_number,
279 network,
280 })
281 }
282}
283
284
285impl Clone for ExtendedPrivateKey {
286 fn clone(&self) -> Self {
287 Self {
288 private_key: Zeroizing::new(*self.private_key),
289 chain_code: Zeroizing::new(*self.chain_code),
290 depth: self.depth,
291 parent_fingerprint: self.parent_fingerprint,
292 child_number: self.child_number,
293 network: self.network,
294 }
295 }
296}
297
298impl fmt::Display for ExtendedPrivateKey {
299 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300 write!(f, "{}", self.to_xprv())
301 }
302}
303
304impl fmt::Debug for ExtendedPrivateKey {
305 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
306 write!(
307 f,
308 "ExtendedPrivateKey {{ depth: {}, fingerprint: {:02x}{:02x}{:02x}{:02x}, key: **** }}",
309 self.depth,
310 self.parent_fingerprint[0],
311 self.parent_fingerprint[1],
312 self.parent_fingerprint[2],
313 self.parent_fingerprint[3]
314 )
315 }
316}
317
318impl Drop for ExtendedPrivateKey {
319 fn drop(&mut self) {
320 }
322}
323
324#[derive(Clone)]
328pub struct ExtendedPublicKey {
329 public_key: [u8; 33],
331 chain_code: [u8; 32],
333 depth: u8,
335 parent_fingerprint: [u8; 4],
337 child_number: u32,
339 network: Network,
341}
342
343impl ExtendedPublicKey {
344 pub fn derive_child(&self, index: u32) -> Result<Self, HdError> {
348 if index >= HARDENED_BIT {
349 return Err(HdError::HardenedFromPublic);
350 }
351
352 let secp = Secp256k1::new();
353 let parent_key = secp256k1::PublicKey::from_slice(&self.public_key)
354 .map_err(|_| HdError::InvalidDerivedKey)?;
355
356 let mut mac =
357 HmacSha512::new_from_slice(&self.chain_code).expect("HMAC can take key of any size");
358 mac.update(&self.public_key);
359 mac.update(&index.to_be_bytes());
360
361 let result = mac.finalize().into_bytes();
362
363 let mut tweak_bytes = [0u8; 32];
364 let mut child_chain_code = [0u8; 32];
365 tweak_bytes.copy_from_slice(&result[..32]);
366 child_chain_code.copy_from_slice(&result[32..]);
367
368 let tweak = SecretKey::from_slice(&tweak_bytes).map_err(|_| HdError::InvalidDerivedKey)?;
370 let child_key = parent_key
371 .add_exp_tweak(&secp, &tweak.into())
372 .map_err(|_| HdError::InvalidDerivedKey)?;
373
374 Ok(Self {
375 public_key: child_key.serialize(),
376 chain_code: child_chain_code,
377 depth: self.depth.saturating_add(1),
378 parent_fingerprint: self.fingerprint(),
379 child_number: index,
380 network: self.network,
381 })
382 }
383
384 pub fn derive_path(&self, path: &DerivationPath) -> Result<Self, HdError> {
386 if path.has_hardened() {
387 return Err(HdError::HardenedFromPublic);
388 }
389
390 let mut current = self.clone();
391 for child in path.components() {
392 current = current.derive_child(child.raw_index())?;
393 }
394 Ok(current)
395 }
396
397 pub fn public_key(&self) -> PublicKey {
399 PublicKey::from_compressed(&self.public_key).expect("Public key should be valid")
400 }
401
402 pub fn fingerprint(&self) -> [u8; 4] {
404 let sha256 = Sha256::digest(self.public_key);
405 let hash160 = Ripemd160::digest(sha256);
406
407 let mut fingerprint = [0u8; 4];
408 fingerprint.copy_from_slice(&hash160[..4]);
409 fingerprint
410 }
411
412 pub fn depth(&self) -> u8 {
414 self.depth
415 }
416
417 pub fn chain_code(&self) -> &[u8; 32] {
419 &self.chain_code
420 }
421
422 pub fn network(&self) -> Network {
424 self.network
425 }
426
427 pub fn to_xpub(&self) -> String {
429 let mut data = Vec::with_capacity(78);
430
431 data.extend_from_slice(&self.network.xpub_version());
433 data.push(self.depth);
435 data.extend_from_slice(&self.parent_fingerprint);
437 data.extend_from_slice(&self.child_number.to_be_bytes());
439 data.extend_from_slice(&self.chain_code);
441 data.extend_from_slice(&self.public_key);
443
444 bs58::encode(data).with_check().into_string()
445 }
446
447 pub fn from_xpub(xpub: &str) -> Result<Self, HdError> {
449 let data = bs58::decode(xpub)
450 .with_check(None)
451 .into_vec()
452 .map_err(|_| HdError::InvalidChecksum)?;
453
454 if data.len() != 78 {
455 return Err(HdError::InvalidExtendedKey);
456 }
457
458 let mut version = [0u8; 4];
459 version.copy_from_slice(&data[0..4]);
460
461 let (network, is_private) =
462 Network::from_version(&version).ok_or(HdError::InvalidVersion)?;
463
464 if is_private {
465 return Err(HdError::InvalidExtendedKey);
466 }
467
468 let depth = data[4];
469
470 let mut parent_fingerprint = [0u8; 4];
471 parent_fingerprint.copy_from_slice(&data[5..9]);
472
473 let child_number = u32::from_be_bytes([data[9], data[10], data[11], data[12]]);
474
475 let mut chain_code = [0u8; 32];
476 chain_code.copy_from_slice(&data[13..45]);
477
478 let mut public_key = [0u8; 33];
479 public_key.copy_from_slice(&data[45..78]);
480
481 secp256k1::PublicKey::from_slice(&public_key).map_err(|_| HdError::InvalidDerivedKey)?;
483
484 Ok(Self {
485 public_key,
486 chain_code,
487 depth,
488 parent_fingerprint,
489 child_number,
490 network,
491 })
492 }
493}
494
495impl fmt::Display for ExtendedPublicKey {
496 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
497 write!(f, "{}", self.to_xpub())
498 }
499}
500
501impl fmt::Debug for ExtendedPublicKey {
502 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
503 write!(
504 f,
505 "ExtendedPublicKey {{ depth: {}, fingerprint: {:02x}{:02x}{:02x}{:02x} }}",
506 self.depth,
507 self.parent_fingerprint[0],
508 self.parent_fingerprint[1],
509 self.parent_fingerprint[2],
510 self.parent_fingerprint[3]
511 )
512 }
513}
514
515#[cfg(test)]
516mod tests {
517 use super::*;
518
519 const TEST_SEED_2: &str = "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542";
521 const TEST_XPRV_M2: &str = "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U";
522 const TEST_XPUB_M2: &str = "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB";
523
524 fn get_test_seed_64() -> Vec<u8> {
525 hex::decode(TEST_SEED_2).unwrap()
526 }
527
528 #[test]
529 fn test_master_from_seed() {
530 let seed = get_test_seed_64();
531 let master = ExtendedPrivateKey::from_seed(&seed, Network::Mainnet).unwrap();
532 assert_eq!(master.depth(), 0);
533 assert_eq!(master.to_xprv(), TEST_XPRV_M2);
534 }
535
536 #[test]
537 fn test_master_xpub() {
538 let seed = get_test_seed_64();
539 let master = ExtendedPrivateKey::from_seed(&seed, Network::Mainnet).unwrap();
540 let xpub = master.extended_public_key();
541 assert_eq!(xpub.to_xpub(), TEST_XPUB_M2);
542 }
543
544 #[test]
545 fn test_xprv_roundtrip() {
546 let seed = get_test_seed_64();
547 let master = ExtendedPrivateKey::from_seed(&seed, Network::Mainnet).unwrap();
548 let xprv = master.to_xprv();
549 let parsed = ExtendedPrivateKey::from_xprv(&xprv).unwrap();
550 assert_eq!(parsed.to_xprv(), xprv);
551 }
552
553 #[test]
554 fn test_xpub_roundtrip() {
555 let seed = get_test_seed_64();
556 let master = ExtendedPrivateKey::from_seed(&seed, Network::Mainnet).unwrap();
557 let xpub = master.extended_public_key();
558 let xpub_str = xpub.to_xpub();
559 let parsed = ExtendedPublicKey::from_xpub(&xpub_str).unwrap();
560 assert_eq!(parsed.to_xpub(), xpub_str);
561 }
562
563 #[test]
564 fn test_hardened_from_public_fails() {
565 let seed = get_test_seed_64();
566 let master = ExtendedPrivateKey::from_seed(&seed, Network::Mainnet).unwrap();
567 let xpub = master.extended_public_key();
568 let result = xpub.derive_child(HARDENED_BIT);
569 assert!(matches!(result, Err(HdError::HardenedFromPublic)));
570 }
571
572 #[test]
573 fn test_derive_path() {
574 let seed = get_test_seed_64();
575 let master = ExtendedPrivateKey::from_seed(&seed, Network::Mainnet).unwrap();
576 let path = DerivationPath::parse("m/0'").unwrap();
577 let child = master.derive_path(&path).unwrap();
578 assert_eq!(child.depth(), 1);
579 }
580
581 #[test]
582 fn test_debug_masked() {
583 let seed = get_test_seed_64();
584 let master = ExtendedPrivateKey::from_seed(&seed, Network::Mainnet).unwrap();
585 let debug = format!("{:?}", master);
586 assert!(debug.contains("****"));
587 assert!(!debug.contains(&master.to_xprv()));
588 }
589
590 #[test]
591 fn test_bip44_derivation() {
592 let seed = get_test_seed_64();
593 let master = ExtendedPrivateKey::from_seed(&seed, Network::Mainnet).unwrap();
594 let path = DerivationPath::bip44_bitcoin(0, 0, 0);
595 let child = master.derive_path(&path).unwrap();
596 assert_eq!(child.depth(), 5);
597 }
598
599 #[test]
600 fn test_public_key_derivation_consistency() {
601 let seed = get_test_seed_64();
602 let master = ExtendedPrivateKey::from_seed(&seed, Network::Mainnet).unwrap();
603
604 let child_priv = master.derive_child(0).unwrap();
606 let pub_from_priv = child_priv.extended_public_key();
607
608 let master_pub = master.extended_public_key();
610 let pub_direct = master_pub.derive_child(0).unwrap();
611
612 assert_eq!(pub_from_priv.to_xpub(), pub_direct.to_xpub());
613 }
614}