coins_bip32/
derived.rs

1use k256::ecdsa;
2
3use coins_core::prelude::{Hash160, Hash160Digest, MarkedDigest, MarkedDigestOutput};
4
5use crate::{
6    path::{DerivationPath, KeyDerivation},
7    primitives::{Hint, KeyFingerprint, XKeyInfo},
8    xkeys::{Parent, XPriv, XPub, SEED},
9    Bip32Error,
10};
11
12/// Derived keys are keys coupled with their derivation. We use this trait to
13/// check ancestry relationships between keys.
14pub trait DerivedKey {
15    /// Return this key's derivation
16    fn derivation(&self) -> &KeyDerivation;
17
18    /// `true` if the keys share a root fingerprint, `false` otherwise. Note that on key
19    /// fingerprints, which may collide accidentally, or be intentionally collided.
20    fn same_root<K: DerivedKey>(&self, other: &K) -> bool {
21        self.derivation().same_root(other.derivation())
22    }
23
24    /// `true` if this key is a possible ancestor of the argument, `false` otherwise.
25    ///
26    /// Warning: this check is cheap, but imprecise. It simply compares the root fingerprints
27    /// (which may collide) and checks that `self.path` is a prefix of `other.path`. This may be
28    /// deliberately foold by an attacker. For a precise check, use
29    /// `DerivedXPriv::is_private_ancestor_of()` or
30    /// `DerivedXPub::is_public_ancestor_of()`
31    fn is_possible_ancestor_of<K: DerivedKey>(&self, other: &K) -> bool {
32        self.derivation()
33            .is_possible_ancestor_of(other.derivation())
34    }
35
36    /// Returns the path to the descendant, or `None` if the argument is definitely not a
37    /// descendant.
38    ///
39    /// This is useful for determining the path to reach some descendant from some ancestor.
40    fn path_to_descendant<K: DerivedKey>(&self, other: &K) -> Option<DerivationPath> {
41        self.derivation().path_to_descendant(other.derivation())
42    }
43}
44
45/// An XPriv with its derivation.
46#[derive(Debug, Clone)]
47#[cfg_attr(
48    any(feature = "mainnet", feature = "testnet"),
49    derive(serde::Serialize, serde::Deserialize)
50)]
51pub struct DerivedXPriv {
52    xpriv: XPriv,
53    derivation: KeyDerivation,
54}
55
56inherit_signer!(DerivedXPriv.xpriv);
57
58impl AsRef<XPriv> for DerivedXPriv {
59    fn as_ref(&self) -> &XPriv {
60        &self.xpriv
61    }
62}
63
64impl AsRef<XKeyInfo> for DerivedXPriv {
65    fn as_ref(&self) -> &XKeyInfo {
66        &self.xpriv.xkey_info
67    }
68}
69
70impl AsRef<ecdsa::SigningKey> for DerivedXPriv {
71    fn as_ref(&self) -> &ecdsa::SigningKey {
72        &self.xpriv.key
73    }
74}
75
76impl DerivedKey for DerivedXPriv {
77    fn derivation(&self) -> &KeyDerivation {
78        &self.derivation
79    }
80}
81
82impl DerivedXPriv {
83    /// Instantiate a derived XPub from the XPub and derivatin. This usually
84    /// should not be called directly. Prefer deriving keys from parents.
85    pub const fn new(xpriv: XPriv, derivation: KeyDerivation) -> Self {
86        Self { xpriv, derivation }
87    }
88
89    /// Check if this XPriv is the private ancestor of some other derived key.
90    /// To check ancestry of another private key, derive its public key first
91    pub fn is_private_ancestor_of(&self, other: &DerivedXPub) -> Result<bool, Bip32Error> {
92        if let Some(path) = self.path_to_descendant(other) {
93            let descendant = self.derive_path(path)?;
94            dbg!(descendant.verify_key());
95            dbg!(&other);
96            Ok(descendant.verify_key() == *other)
97        } else {
98            Ok(false)
99        }
100    }
101
102    /// Generate a customized root node using the stati
103    pub fn root_node(
104        hmac_key: &[u8],
105        data: &[u8],
106        hint: Option<Hint>,
107    ) -> Result<DerivedXPriv, Bip32Error> {
108        Self::custom_root_node(hmac_key, data, hint)
109    }
110
111    /// Generate a root node from some seed data. Uses the BIP32-standard hmac key.
112    ///
113    ///
114    /// # Important:
115    ///
116    /// Use a seed of AT LEAST 128 bits.
117    pub fn root_from_seed(data: &[u8], hint: Option<Hint>) -> Result<DerivedXPriv, Bip32Error> {
118        Self::custom_root_from_seed(data, hint)
119    }
120
121    /// Instantiate a root node using a custom HMAC key.
122    pub fn custom_root_node(
123        hmac_key: &[u8],
124        data: &[u8],
125        hint: Option<Hint>,
126    ) -> Result<DerivedXPriv, Bip32Error> {
127        let xpriv = XPriv::custom_root_node(hmac_key, data, hint)?;
128
129        let derivation = KeyDerivation {
130            root: xpriv.fingerprint(),
131            path: vec![].into(),
132        };
133
134        Ok(DerivedXPriv { xpriv, derivation })
135    }
136
137    /// Generate a root node from some seed data. Uses the BIP32-standard hmac key.
138    ///
139    ///
140    /// # Important:
141    ///
142    /// Use a seed of AT LEAST 128 bits.
143    pub fn custom_root_from_seed(
144        data: &[u8],
145        hint: Option<Hint>,
146    ) -> Result<DerivedXPriv, Bip32Error> {
147        Self::custom_root_node(SEED, data, hint)
148    }
149
150    /// Derive the corresponding xpub
151    pub fn verify_key(&self) -> DerivedXPub {
152        DerivedXPub {
153            xpub: self.xpriv.verify_key(),
154            derivation: self.derivation.clone(),
155        }
156    }
157}
158
159impl Parent for DerivedXPriv {
160    fn derive_child(&self, index: u32) -> Result<Self, Bip32Error> {
161        Ok(Self {
162            xpriv: self.xpriv.derive_child(index)?,
163            derivation: self.derivation.extended(index),
164        })
165    }
166}
167
168/// An XPub with its derivation.
169#[derive(Debug, Clone, PartialEq)]
170#[cfg_attr(
171    any(feature = "mainnet", feature = "testnet"),
172    derive(serde::Serialize, serde::Deserialize)
173)]
174pub struct DerivedXPub {
175    xpub: XPub,
176    derivation: KeyDerivation,
177}
178
179inherit_verifier!(DerivedXPub.xpub);
180
181impl AsRef<XPub> for DerivedXPub {
182    fn as_ref(&self) -> &XPub {
183        &self.xpub
184    }
185}
186
187impl AsRef<XKeyInfo> for DerivedXPub {
188    fn as_ref(&self) -> &XKeyInfo {
189        &self.xpub.xkey_info
190    }
191}
192
193impl AsRef<ecdsa::VerifyingKey> for DerivedXPub {
194    fn as_ref(&self) -> &ecdsa::VerifyingKey {
195        &self.xpub.key
196    }
197}
198
199impl Parent for DerivedXPub {
200    fn derive_child(&self, index: u32) -> Result<Self, Bip32Error> {
201        Ok(Self {
202            xpub: self.xpub.derive_child(index)?,
203            derivation: self.derivation.extended(index),
204        })
205    }
206}
207
208impl DerivedKey for DerivedXPub {
209    fn derivation(&self) -> &KeyDerivation {
210        &self.derivation
211    }
212}
213
214impl DerivedXPub {
215    /// Instantiate a derived XPub from the XPub and derivatin. This usually
216    /// should not be called directly. Prefer deriving keys from parents.
217    pub const fn new(xpub: XPub, derivation: KeyDerivation) -> Self {
218        Self { xpub, derivation }
219    }
220
221    /// Check if this XPriv is the private ancestor of some other derived key
222    pub fn is_public_ancestor_of(&self, other: &DerivedXPub) -> Result<bool, Bip32Error> {
223        if let Some(path) = self.path_to_descendant(other) {
224            let descendant = self.derive_path(path)?;
225            Ok(descendant == *other)
226        } else {
227            Ok(false)
228        }
229    }
230}
231
232/// A Pubkey with its derivation. Primarily used by PSBT.
233pub struct DerivedPubkey {
234    key: ecdsa::VerifyingKey,
235    derivation: KeyDerivation,
236}
237
238impl std::fmt::Debug for DerivedPubkey {
239    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
240        f.debug_struct("DerivedPubkey")
241            .field("public key", &self.key.to_sec1_bytes())
242            .field("key fingerprint", &self.fingerprint())
243            .field("derivation", &self.derivation)
244            .finish()
245    }
246}
247
248inherit_verifier!(DerivedPubkey.key);
249
250impl DerivedKey for DerivedPubkey {
251    fn derivation(&self) -> &KeyDerivation {
252        &self.derivation
253    }
254}
255
256impl AsRef<ecdsa::VerifyingKey> for DerivedPubkey {
257    fn as_ref(&self) -> &ecdsa::VerifyingKey {
258        &self.key
259    }
260}
261
262impl DerivedPubkey {
263    /// Instantiate a new `DerivedPubkey`
264    pub const fn new(key: ecdsa::VerifyingKey, derivation: KeyDerivation) -> Self {
265        Self { key, derivation }
266    }
267
268    /// Return the hash of the compressed (Sec1) pubkey.
269    pub fn pubkey_hash160(&self) -> Hash160Digest {
270        Hash160::digest_marked(self.key.to_sec1_bytes().as_ref())
271    }
272
273    /// The fingerprint is the first 4 bytes of the HASH160 of the serialized
274    /// public key.
275    pub fn fingerprint(&self) -> KeyFingerprint {
276        let digest = self.pubkey_hash160();
277        let mut buf = [0u8; 4];
278        buf.copy_from_slice(&digest.as_slice()[..4]);
279        buf.into()
280    }
281}
282
283#[cfg(test)]
284mod test {
285    use super::*;
286    use crate::{
287        enc::{MainnetEncoder, XKeyEncoder},
288        path::DerivationPath,
289        prelude::*,
290        primitives::*,
291        BIP32_HARDEN,
292    };
293    use coins_core::hashes::*;
294    use k256::ecdsa::signature::{DigestSigner, DigestVerifier};
295
296    use hex;
297
298    struct KeyDeriv<'a> {
299        pub(crate) path: &'a [u32],
300    }
301
302    fn validate_descendant(d: &KeyDeriv, m: &DerivedXPriv) {
303        let path: DerivationPath = d.path.into();
304
305        let m_pub = m.verify_key();
306
307        let xpriv = m.derive_path(&path).unwrap();
308        let xpub = xpriv.verify_key();
309        assert!(m.same_root(&xpriv));
310        assert!(m.same_root(&xpub));
311        assert!(m.is_possible_ancestor_of(&xpriv));
312        assert!(m.is_possible_ancestor_of(&xpub));
313
314        let result = m.is_private_ancestor_of(&xpub).expect("should work");
315
316        if !result {
317            panic!("failed validate_descendant is_private_ancestor_of");
318        }
319
320        let result = m_pub.is_public_ancestor_of(&xpub);
321
322        match result {
323            Ok(true) => {}
324            Ok(false) => panic!("failed validate_descendant is_public_ancestor_of"),
325            Err(_) => {
326                let path: DerivationPath = d.path.into();
327                assert!(
328                    path.last_hardened().1.is_some(),
329                    "is_public_ancestor_of failed for unhardened path"
330                )
331            }
332        }
333
334        let derived_path = m
335            .path_to_descendant(&xpriv)
336            .expect("expected a path to descendant");
337        assert_eq!(&path, &derived_path, "derived path is not as expected");
338    }
339
340    #[test]
341    fn bip32_vector_1() {
342        let seed: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
343
344        let xpriv = DerivedXPriv::root_from_seed(&seed, Some(Hint::Legacy)).unwrap();
345
346        let descendants = [
347            KeyDeriv {
348                path: &[BIP32_HARDEN],
349            },
350            KeyDeriv {
351                path: &[BIP32_HARDEN, 1],
352            },
353            KeyDeriv {
354                path: &[BIP32_HARDEN, 1, 2 + BIP32_HARDEN],
355            },
356            KeyDeriv {
357                path: &[BIP32_HARDEN, 1, 2 + BIP32_HARDEN, 2],
358            },
359            KeyDeriv {
360                path: &[BIP32_HARDEN, 1, 2 + BIP32_HARDEN, 2, 1000000000],
361            },
362        ];
363
364        for case in descendants.iter() {
365            validate_descendant(case, &xpriv);
366        }
367    }
368
369    #[test]
370    fn bip32_vector_2() {
371        let seed = hex::decode("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542").unwrap();
372
373        let xpriv = DerivedXPriv::root_from_seed(&seed, Some(Hint::Legacy)).unwrap();
374
375        let descendants = [
376            KeyDeriv { path: &[0] },
377            KeyDeriv {
378                path: &[0, 2147483647 + BIP32_HARDEN],
379            },
380            KeyDeriv {
381                path: &[0, 2147483647 + BIP32_HARDEN, 1],
382            },
383            KeyDeriv {
384                path: &[0, 2147483647 + BIP32_HARDEN, 1, 2147483646 + BIP32_HARDEN],
385            },
386            KeyDeriv {
387                path: &[
388                    0,
389                    2147483647 + BIP32_HARDEN,
390                    1,
391                    2147483646 + BIP32_HARDEN,
392                    2,
393                ],
394            },
395        ];
396
397        for case in descendants.iter() {
398            validate_descendant(case, &xpriv);
399        }
400    }
401
402    #[test]
403    fn bip32_vector_3() {
404        let seed = hex::decode("4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be").unwrap();
405
406        let xpriv = DerivedXPriv::root_from_seed(&seed, Some(Hint::Legacy)).unwrap();
407
408        let descendants = [KeyDeriv {
409            path: &[BIP32_HARDEN],
410        }];
411
412        for case in descendants.iter() {
413            validate_descendant(case, &xpriv);
414        }
415    }
416
417    #[test]
418    fn it_can_sign_and_verify() {
419        let digest = Hash256::default();
420        let mut wrong_digest = Hash256::default();
421        wrong_digest.update([0u8]);
422
423        let xpriv_str = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi".to_owned();
424        let xpriv = MainnetEncoder::xpriv_from_base58(&xpriv_str).unwrap();
425        let fake_deriv = KeyDerivation {
426            root: [0, 0, 0, 0].into(),
427            path: (0..0).collect(),
428        };
429
430        let key = DerivedXPriv::new(xpriv, fake_deriv);
431        let key_pub = key.verify_key();
432
433        // sign_digest + verify_digest
434        let sig: Signature = key.sign_digest(digest.clone());
435        key_pub.verify_digest(digest.clone(), &sig).unwrap();
436
437        let err_bad_sig = key_pub.verify_digest(wrong_digest.clone(), &sig);
438        match err_bad_sig {
439            Err(_) => {}
440            _ => panic!("expected signature validation error"),
441        }
442
443        let (sig, _): (Signature, RecoveryId) = key.sign_digest(digest.clone());
444        key_pub.verify_digest(digest, &sig).unwrap();
445
446        let err_bad_sig = key_pub.verify_digest(wrong_digest.clone(), &sig);
447        match err_bad_sig {
448            Err(_) => {}
449            _ => panic!("expected signature validation error"),
450        }
451    }
452
453    #[test]
454    fn it_can_descendant_sign_and_verify() {
455        let digest = Hash256::default();
456        let mut wrong_digest = Hash256::default();
457        wrong_digest.update([0u8]);
458
459        let path = vec![0u32, 1, 2];
460
461        let xpriv_str = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi".to_owned();
462        let xpriv = MainnetEncoder::xpriv_from_base58(&xpriv_str).unwrap();
463        let fake_deriv = KeyDerivation {
464            root: [0, 0, 0, 0].into(),
465            path: (0..0).collect(),
466        };
467
468        let key = DerivedXPriv::new(xpriv, fake_deriv.clone());
469        let key_pub = key.verify_key();
470        assert_eq!(key.derivation(), &fake_deriv);
471
472        // sign_digest + verify_digest
473        let sig: Signature = key.derive_path(&path).unwrap().sign_digest(digest.clone());
474        key_pub
475            .derive_path(&path)
476            .unwrap()
477            .verify_digest(digest.clone(), &sig)
478            .unwrap();
479
480        let err_bad_sig = key_pub
481            .derive_path(&path)
482            .unwrap()
483            .verify_digest(wrong_digest.clone(), &sig);
484        match err_bad_sig {
485            Err(_) => {}
486            _ => panic!("expected signature validation error"),
487        }
488
489        let (sig, _): (Signature, RecoveryId) =
490            key.derive_path(&path).unwrap().sign_digest(digest.clone());
491        key_pub
492            .derive_path(&path)
493            .unwrap()
494            .verify_digest(digest.clone(), &sig)
495            .unwrap();
496
497        let err_bad_sig = key_pub
498            .derive_path(&path)
499            .unwrap()
500            .verify_digest(wrong_digest.clone(), &sig);
501        match err_bad_sig {
502            Err(_) => {}
503            _ => panic!("expected signature validation error"),
504        }
505
506        // sign + verify
507        let sig: Signature = key.derive_path(&path).unwrap().sign_digest(digest.clone());
508        key_pub
509            .derive_path(&path)
510            .unwrap()
511            .verify_digest(digest.clone(), &sig)
512            .unwrap();
513
514        let err_bad_sig = key_pub
515            .derive_path(&path)
516            .unwrap()
517            .verify_digest(wrong_digest.clone(), &sig);
518        match err_bad_sig {
519            Err(_) => {}
520            _ => panic!("expected signature validation error"),
521        }
522
523        // sign_recoverable + verify_recoverable
524        let (sig, recovery_id): (Signature, RecoveryId) =
525            key.derive_path(&path).unwrap().sign_digest(digest.clone());
526        key_pub
527            .derive_path(&path)
528            .unwrap()
529            .verify_digest(digest, &sig)
530            .unwrap();
531
532        let err_bad_sig = key_pub
533            .derive_path(&path)
534            .unwrap()
535            .verify_digest(wrong_digest.clone(), &sig);
536        match err_bad_sig {
537            Err(_) => {}
538            _ => panic!("expected signature validation error"),
539        }
540
541        // Sig serialize/deserialize
542        let der_sig = hex::decode("304402200cc613393c11889ed1384388c9213b7778cfa0c7c2b6fcc080f0296fc8ac87d202205788d8994d61ce901d1ee22c5210994c235f17ddb3c31e0fc0ec9730ecf084ce").unwrap();
543        let rsv: [u8; 65] = [
544            12, 198, 19, 57, 60, 17, 136, 158, 209, 56, 67, 136, 201, 33, 59, 119, 120, 207, 160,
545            199, 194, 182, 252, 192, 128, 240, 41, 111, 200, 172, 135, 210, 87, 136, 216, 153, 77,
546            97, 206, 144, 29, 30, 226, 44, 82, 16, 153, 76, 35, 95, 23, 221, 179, 195, 30, 15, 192,
547            236, 151, 48, 236, 240, 132, 206, 1,
548        ];
549        assert_eq!(sig.to_der().as_bytes(), der_sig);
550        assert_eq!(&sig, &Signature::from_der(&der_sig).unwrap());
551        assert_eq!(sig.r().to_bytes().as_slice(), &rsv[..32]);
552        assert_eq!(sig.s().to_bytes().as_slice(), &rsv[32..64]);
553        assert_eq!(recovery_id.to_byte(), rsv[64]);
554    }
555
556    #[test]
557    fn it_instantiates_derived_xprivs_from_seeds() {
558        DerivedXPriv::custom_root_from_seed(&[0u8; 32][..], None).unwrap();
559
560        let err_too_short = DerivedXPriv::custom_root_from_seed(&[0u8; 2][..], None);
561        match err_too_short {
562            Err(Bip32Error::SeedTooShort) => {}
563            _ => panic!("expected err too short"),
564        }
565
566        let err_too_short = DerivedXPriv::custom_root_from_seed(&[0u8; 2][..], None);
567        match err_too_short {
568            Err(Bip32Error::SeedTooShort) => {}
569            _ => panic!("expected err too short"),
570        }
571    }
572
573    #[test]
574    fn it_checks_ancestry() {
575        let m = DerivedXPriv::custom_root_from_seed(&[0u8; 32][..], None).unwrap();
576        let m2 = DerivedXPriv::custom_root_from_seed(&[1u8; 32][..], None).unwrap();
577        let m_pub = m.verify_key();
578        let cases = [
579            (&m, &m_pub, true),
580            (&m2, &m_pub, false),
581            (&m, &m2.verify_key(), false),
582            (&m, &m.derive_child(33).unwrap().verify_key(), true),
583            (&m, &m_pub.derive_child(33).unwrap(), true),
584            (&m, &m2.derive_child(33).unwrap().verify_key(), false),
585        ];
586        for (i, case) in cases.iter().enumerate() {
587            dbg!(i);
588            assert_eq!(case.0.is_private_ancestor_of(case.1).unwrap(), case.2);
589        }
590    }
591}