keynesis_core/key/
ed25519_hd.rs

1use crate::{
2    key::{ed25519_extended, SharedSecret},
3    memsec::Scrubbed as _,
4};
5use cryptoxide::{
6    curve25519::{Ge, Scalar},
7    hmac::Hmac,
8    mac::Mac,
9    sha2::Sha512,
10};
11use packtool::Packed;
12use rand_core::{CryptoRng, RngCore};
13use std::{
14    convert::TryFrom,
15    fmt::{self, Debug, Display, Formatter},
16    ops::Deref,
17    str::FromStr,
18};
19use thiserror::Error;
20
21#[derive(Packed, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)]
22pub struct ChainCode(
23    // hide the inner structure of the chaincode
24    #[packed(accessor = false)] [u8; Self::SIZE],
25);
26
27#[derive(Clone, Eq, PartialEq, Hash)]
28pub struct SecretKey {
29    key: ed25519_extended::SecretKey,
30    chain_code: ChainCode,
31}
32
33#[derive(Packed, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
34pub struct PublicKey {
35    #[packed(accessor = "public_key")]
36    key: ed25519_extended::PublicKey,
37    // hide the chain code from the HD public key view
38    #[packed(accessor = false)]
39    chain_code: ChainCode,
40}
41
42pub use crate::key::ed25519::Signature;
43
44impl ChainCode {
45    pub const SIZE: usize = 32;
46
47    /// create a dummy instance of the object but filled with zeroes
48    #[inline(always)]
49    const fn zero() -> Self {
50        Self([0; Self::SIZE])
51    }
52
53    /// generate a new `SecretKey` with the given random number generator
54    ///
55    fn new<Rng>(mut rng: Rng) -> Self
56    where
57        Rng: RngCore + CryptoRng,
58    {
59        let mut s = Self::zero();
60        rng.fill_bytes(&mut s.0);
61        s
62    }
63}
64
65impl SecretKey {
66    pub const SIZE: usize = ed25519_extended::SecretKey::SIZE + ChainCode::SIZE;
67
68    /// generate a new `SecretKey` with the given random number generator
69    ///
70    pub fn new<Rng>(mut rng: Rng) -> Self
71    where
72        Rng: RngCore + CryptoRng,
73    {
74        let mut key = ed25519_extended::SecretKey::new(&mut rng);
75        let chain_code = ChainCode::new(rng);
76
77        key.clear_3rd_highest_bit();
78
79        let s = Self { key, chain_code };
80
81        debug_assert!(
82            s.key.is_3rd_highest_bit_clear(),
83            "checking we properly set the bit tweaks for the extended Ed25519 BIP32"
84        );
85
86        s
87    }
88
89    #[inline]
90    pub fn is_3rd_highest_bit_clear(&self) -> bool {
91        self.key.is_3rd_highest_bit_clear()
92    }
93
94    /// get the `PublicKey` associated to this key
95    ///
96    /// Unlike the `SecretKey`, the `PublicKey` can be safely
97    /// publicly shared. The key can then be used to verify any
98    /// `Signature` generated with this `SecretKey` and the original
99    /// message.
100    pub fn public_key(&self) -> PublicKey {
101        let key = self.key.public_key();
102        let chain_code = self.chain_code;
103
104        PublicKey { key, chain_code }
105    }
106
107    pub fn chain(&self) -> &ChainCode {
108        &self.chain_code
109    }
110
111    /// Access the actual secret key to do key exchange or signing
112    ///
113    /// HD Secret keys are composed of both an extended secret key and
114    /// a chain code. This function gives access to the secret key without
115    /// the chaincode
116    pub fn key(&self) -> &ed25519_extended::SecretKey {
117        &self.key
118    }
119
120    pub fn into_key(self) -> ed25519_extended::SecretKey {
121        self.key
122    }
123
124    /// generate a shared secret between the owner of the given public key and
125    /// ourselves.
126    ///
127    pub fn exchange<P>(&self, public_key: &P) -> SharedSecret
128    where
129        P: AsRef<ed25519_extended::PublicKey>,
130    {
131        self.key.exchange(public_key.as_ref())
132    }
133
134    /// create a `Signature` for the given message with this `SecretKey`.
135    ///
136    /// The `Signature` can then be verified against the associated `PublicKey`
137    /// and the original message.
138    pub fn sign<T: AsRef<[u8]>>(&self, msg: T) -> Signature {
139        self.key.sign(msg)
140    }
141
142    pub fn derive<P>(&self, path: P) -> Self
143    where
144        P: AsRef<[u8]>,
145    {
146        let e_key = &self.key.leak_as_ref()[0..64];
147        let kl = &e_key[0..32];
148        let kr = &e_key[32..64];
149        let chaincode = self.chain_code.as_ref();
150
151        let mut z_mac = Hmac::new(Sha512::new(), chaincode);
152        let mut i_mac = Hmac::new(Sha512::new(), chaincode);
153        let pk = self.public_key();
154        let pk = pk.key().as_ref();
155        z_mac.input(&[0x2]);
156        z_mac.input(pk);
157        z_mac.input(path.as_ref());
158        i_mac.input(&[0x3]);
159        i_mac.input(pk);
160        i_mac.input(path.as_ref());
161
162        let mut z_out = [0u8; 64];
163        z_mac.raw_result(&mut z_out);
164        let zl = &z_out[0..32];
165        let zr = &z_out[32..64];
166
167        // left = kl + 8 * trunc28(zl)
168        let mut left = add_28_mul8(kl, zl);
169        // right = zr + kr
170        let mut right = add_256bits(kr.try_into().unwrap(), zr.try_into().unwrap());
171
172        let mut i_out = [0u8; 64];
173        i_mac.raw_result(&mut i_out);
174        let cc = &i_out[32..];
175
176        let mut out = [0u8; Self::SIZE];
177        out[0..32].clone_from_slice(&left);
178        out[32..64].clone_from_slice(&right);
179        out[64..96].clone_from_slice(cc);
180
181        i_mac.reset();
182        z_mac.reset();
183
184        z_out.scrub();
185        left.scrub();
186        right.scrub();
187
188        Self::try_from(out).unwrap()
189    }
190}
191
192impl PublicKey {
193    pub const SIZE: usize = ed25519_extended::PublicKey::SIZE + ChainCode::SIZE;
194
195    pub fn from_parts(key: ed25519_extended::PublicKey, chain_code: ChainCode) -> Self {
196        Self { key, chain_code }
197    }
198
199    pub fn key(&self) -> &ed25519_extended::PublicKey {
200        &self.key
201    }
202
203    pub fn into_key(self) -> ed25519_extended::PublicKey {
204        self.key
205    }
206
207    pub fn chain_code(&self) -> &ChainCode {
208        &self.chain_code
209    }
210
211    pub fn derive<P>(&self, path: P) -> Option<Self>
212    where
213        P: AsRef<[u8]>,
214    {
215        let pk = self.key().bytes();
216        let chaincode = self.chain_code().as_ref();
217
218        let mut z_mac = Hmac::new(Sha512::new(), chaincode);
219        let mut i_mac = Hmac::new(Sha512::new(), chaincode);
220        z_mac.input(&[0x2]);
221        z_mac.input(pk);
222        z_mac.input(path.as_ref());
223        i_mac.input(&[0x3]);
224        i_mac.input(pk);
225        i_mac.input(path.as_ref());
226
227        let mut z_out = [0u8; 64];
228        z_mac.raw_result(&mut z_out);
229        let zl = &z_out[0..32];
230        let _zr = &z_out[32..64];
231
232        // left = kl + 8 * trunc28(zl)
233        let left = point_plus(pk, &point_of_trunc28_mul8(zl.try_into().unwrap()))?;
234
235        let mut i_out = [0u8; 64];
236        i_mac.raw_result(&mut i_out);
237        let cc = &i_out[32..];
238
239        let mut out = [0u8; Self::SIZE];
240        out[..ed25519_extended::PublicKey::SIZE].copy_from_slice(&left);
241        out[ed25519_extended::PublicKey::SIZE..].copy_from_slice(cc);
242
243        i_mac.reset();
244        z_mac.reset();
245
246        Some(Self::from(out))
247    }
248}
249
250/* *************************************************************** */
251
252fn point_of_trunc28_mul8(sk: &[u8; 32]) -> [u8; 32] {
253    let copy = add_28_mul8(&[0u8; 32], sk);
254    let scalar = Scalar::from_bytes(&copy);
255    let a = Ge::scalarmult_base(&scalar);
256    a.to_bytes()
257}
258
259fn point_plus(p1: &[u8; 32], p2: &[u8; 32]) -> Option<[u8; 32]> {
260    let a = Ge::from_bytes(p1)?;
261    let b = Ge::from_bytes(p2)?;
262    let r = &a + &b.to_cached();
263    let mut r = r.to_partial().to_bytes();
264    r[31] ^= 0x80;
265    Some(r)
266}
267
268fn add_28_mul8(x: &[u8], y: &[u8]) -> [u8; 32] {
269    assert!(x.len() == 32);
270    assert!(y.len() == 32);
271
272    let mut carry: u16 = 0;
273    let mut out = [0u8; 32];
274
275    for i in 0..28 {
276        let r = x[i] as u16 + ((y[i] as u16) << 3) + carry;
277        out[i] = (r & 0xff) as u8;
278        carry = r >> 8;
279    }
280    for i in 28..32 {
281        let r = x[i] as u16 + carry;
282        out[i] = (r & 0xff) as u8;
283        carry = r >> 8;
284    }
285    out
286}
287
288fn add_256bits(x: &[u8; 32], y: &[u8; 32]) -> [u8; 32] {
289    let mut carry: u16 = 0;
290    let mut out = [0u8; 32];
291    for i in 0..32 {
292        let r = (x[i] as u16) + (y[i] as u16) + carry;
293        out[i] = r as u8;
294        carry = r >> 8;
295    }
296    out
297}
298
299/* Deref ******************************************************************* */
300
301impl Deref for PublicKey {
302    type Target = ed25519_extended::PublicKey;
303    fn deref(&self) -> &Self::Target {
304        self.key()
305    }
306}
307
308/* Format ****************************************************************** */
309
310impl Debug for ChainCode {
311    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
312        f.debug_tuple("ChainCode")
313            .field(&hex::encode(&self.0))
314            .finish()
315    }
316}
317
318impl Debug for SecretKey {
319    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
320        f.debug_struct("SecretKey<Ed25519BIP32>")
321            .field("key", &self.key)
322            .field("chain_code", &self.chain_code)
323            .finish()
324    }
325}
326
327impl Debug for PublicKey {
328    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
329        f.debug_struct("PublicKey<Ed25519BIP32>")
330            .field("key", &self.key)
331            .field("chain_code", &self.chain_code)
332            .finish()
333    }
334}
335
336impl Display for ChainCode {
337    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
338        Display::fmt(&hex::encode(&self.0), f)
339    }
340}
341
342impl Display for PublicKey {
343    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
344        write!(f, "{}", self.key())?;
345        write!(f, "{}", self.chain_code())
346    }
347}
348
349/* Conversion ************************************************************** */
350
351impl From<[u8; Self::SIZE]> for ChainCode {
352    fn from(bytes: [u8; Self::SIZE]) -> Self {
353        Self(bytes)
354    }
355}
356
357impl From<[u8; Self::SIZE]> for PublicKey {
358    fn from(bytes: [u8; Self::SIZE]) -> Self {
359        let mut key = [0; ed25519_extended::PublicKey::SIZE];
360        let mut chain_code = [0; ChainCode::SIZE];
361        key.copy_from_slice(&bytes[..ed25519_extended::PublicKey::SIZE]);
362        chain_code.copy_from_slice(&bytes[ed25519_extended::PublicKey::SIZE..]);
363        Self {
364            key: ed25519_extended::PublicKey::from(key),
365            chain_code: ChainCode::from(chain_code),
366        }
367    }
368}
369
370#[derive(Debug, Error)]
371pub enum ChainCodeError {
372    #[error("Invalid size, expecting {}", ChainCode::SIZE)]
373    InvalidSize,
374}
375
376impl<'a> TryFrom<&'a [u8]> for ChainCode {
377    type Error = ChainCodeError;
378
379    fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
380        if bytes.len() != Self::SIZE {
381            return Err(Self::Error::InvalidSize);
382        }
383        let mut chain_code = ChainCode::zero();
384        chain_code.0.copy_from_slice(bytes);
385        Ok(chain_code)
386    }
387}
388
389#[derive(Debug, Error)]
390pub enum PublicKeyError {
391    #[error("Invalid size, expecting {}", PublicKey::SIZE)]
392    InvalidSize,
393    #[error("Invalid verify key")]
394    InvalidPublicKey(
395        #[from]
396        #[source]
397        ed25519_extended::PublicKeyError,
398    ),
399    #[error("Invalid chain code")]
400    InvalidChainCode(
401        #[from]
402        #[source]
403        ChainCodeError,
404    ),
405}
406
407impl<'a> TryFrom<&'a [u8]> for PublicKey {
408    type Error = PublicKeyError;
409
410    fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
411        if bytes.len() != Self::SIZE {
412            return Err(Self::Error::InvalidSize);
413        }
414
415        let key =
416            ed25519_extended::PublicKey::try_from(&bytes[..ed25519_extended::PublicKey::SIZE])?;
417        let chain_code = ChainCode::try_from(&bytes[ed25519_extended::PublicKey::SIZE..])?;
418
419        Ok(Self { key, chain_code })
420    }
421}
422
423#[derive(Debug, Error)]
424pub enum SecretKeyError {
425    #[error("Invalid size, expecting {}", SecretKey::SIZE)]
426    InvalidSize,
427    #[error("Invalid chain code")]
428    InvalidChainCode(
429        #[from]
430        #[source]
431        ChainCodeError,
432    ),
433    #[error("Invalid structure")]
434    InvalidStructure,
435    #[error("Invalid hexadecimal string")]
436    InvalidHexadecimal(
437        #[source]
438        #[from]
439        hex::FromHexError,
440    ),
441}
442
443impl TryFrom<[u8; Self::SIZE]> for SecretKey {
444    type Error = SecretKeyError;
445
446    fn try_from(bytes: [u8; Self::SIZE]) -> Result<Self, Self::Error> {
447        Self::try_from(&bytes[..])
448    }
449}
450
451impl<'a> TryFrom<&'a [u8]> for SecretKey {
452    type Error = SecretKeyError;
453    fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
454        if bytes.len() != Self::SIZE {
455            return Err(Self::Error::InvalidSize);
456        }
457
458        match ed25519_extended::SecretKey::try_from(&bytes[..ed25519_extended::SecretKey::SIZE]) {
459            Ok(key) => {
460                // we do not check the 3rd highest bit is cleared here as potentially
461                // derived keys may overflow as per the bip32 paper. However if the
462                // key is expected to be a root key, the check_3rd_highest_bit function
463                // needs called to make sure the structure is valid.
464                let chain_code = ChainCode::try_from(&bytes[ed25519_extended::SecretKey::SIZE..])?;
465                Ok(Self { key, chain_code })
466            }
467            Err(ed25519_extended::SecretKeyError::InvalidSize) => {
468                unreachable!("The Size({}) is already checked, expecting an extended key of {} and a chain code of {}", SecretKey::SIZE, ed25519_extended::SecretKey::SIZE, ChainCode::SIZE)
469            }
470            Err(ed25519_extended::SecretKeyError::InvalidStructure) => {
471                Err(Self::Error::InvalidStructure)
472            }
473        }
474    }
475}
476
477impl FromStr for SecretKey {
478    type Err = SecretKeyError;
479    fn from_str(s: &str) -> Result<Self, Self::Err> {
480        let mut r = [0; Self::SIZE];
481        hex::decode_to_slice(s, &mut r)?;
482
483        let sk = Self::try_from(&r[..])?;
484
485        r.scrub();
486
487        Ok(sk)
488    }
489}
490
491impl FromStr for PublicKey {
492    type Err = hex::FromHexError;
493    fn from_str(s: &str) -> Result<Self, Self::Err> {
494        let mut r = [0; Self::SIZE];
495        hex::decode_to_slice(s, &mut r)?;
496        Ok(Self::from(r))
497    }
498}
499
500impl FromStr for ChainCode {
501    type Err = hex::FromHexError;
502    fn from_str(s: &str) -> Result<Self, Self::Err> {
503        let mut r = [0; Self::SIZE];
504        hex::decode_to_slice(s, &mut r)?;
505        Ok(Self::from(r))
506    }
507}
508
509/* AsRef ******************************************************************* */
510
511impl AsRef<[u8]> for ChainCode {
512    fn as_ref(&self) -> &[u8] {
513        &self.0
514    }
515}
516
517impl AsRef<ed25519_extended::PublicKey> for PublicKey {
518    fn as_ref(&self) -> &ed25519_extended::PublicKey {
519        self.key()
520    }
521}
522
523#[cfg(test)]
524mod tests {
525    use super::*;
526    use quickcheck::{Arbitrary, Gen, TestResult};
527
528    impl Arbitrary for ChainCode {
529        fn arbitrary(g: &mut Gen) -> Self {
530            let mut s = Self::zero();
531            s.0.iter_mut().for_each(|byte| {
532                *byte = u8::arbitrary(g);
533            });
534            s
535        }
536    }
537
538    impl Arbitrary for PublicKey {
539        fn arbitrary(g: &mut Gen) -> Self {
540            SecretKey::arbitrary(g).public_key()
541        }
542    }
543
544    impl Arbitrary for SecretKey {
545        fn arbitrary(g: &mut Gen) -> Self {
546            let key = ed25519_extended::SecretKey::arbitrary(g);
547            let chain_code = ChainCode::arbitrary(g);
548
549            // NOTE:
550            //   we actually don't call this one function on purpose
551            //   as it may be that the highest bit is not set and that
552            //   the derived key overflew
553            //
554            // key.clear_3rd_highest_bit();
555
556            Self { key, chain_code }
557        }
558    }
559
560    #[quickcheck]
561    fn verify_exchange_works(alice: SecretKey, bob: SecretKey) -> bool {
562        let alice_pk = alice.public_key();
563        let bob_pk = bob.public_key();
564
565        alice.exchange(&bob_pk) == bob.exchange(&alice_pk)
566    }
567
568    #[quickcheck]
569    fn signing_verify_works(signing_key: SecretKey, message: Vec<u8>) -> bool {
570        let public_key = signing_key.public_key();
571        let signature = signing_key.sign(&message);
572
573        public_key.verify(message, &signature)
574    }
575
576    #[quickcheck]
577    fn signing_key_try_from_correct_size(signing_key: SecretKey) -> TestResult {
578        let mut bytes = signing_key.key.leak_as_ref().to_vec();
579        bytes.extend(&signing_key.chain_code.0);
580        match SecretKey::try_from(bytes.as_slice()) {
581            Ok(_) => TestResult::passed(),
582            Err(SecretKeyError::InvalidSize) => {
583                TestResult::error("was expecting the test to pass, not an invalid size")
584            }
585            Err(SecretKeyError::InvalidChainCode(ChainCodeError::InvalidSize)) => {
586                unreachable!("The total size of the key is already being checked")
587            }
588            Err(SecretKeyError::InvalidStructure) => {
589                TestResult::error("was expecting the test to pass, not an invalid structure")
590            }
591            Err(SecretKeyError::InvalidHexadecimal(_)) => {
592                unreachable!("We should not see an hexadecimal error at all in this test")
593            }
594        }
595    }
596
597    #[quickcheck]
598    fn signing_key_try_from_incorrect_size(bytes: Vec<u8>) -> TestResult {
599        if bytes.len() == SecretKey::SIZE {
600            return TestResult::discard();
601        }
602        match SecretKey::try_from(bytes.as_slice()) {
603            Ok(_) => TestResult::error(
604                "Expecting to fail with invalid size instead of having a valid value",
605            ),
606            Err(SecretKeyError::InvalidSize) => TestResult::passed(),
607            Err(SecretKeyError::InvalidChainCode(ChainCodeError::InvalidSize)) => {
608                unreachable!("The total size of the key is already being checked")
609            }
610            Err(SecretKeyError::InvalidStructure) => {
611                TestResult::error("was expecting an invalid size error, not an invalid structure")
612            }
613            Err(SecretKeyError::InvalidHexadecimal(_)) => {
614                unreachable!("We should not see an hexadecimal error at all in this test")
615            }
616        }
617    }
618
619    #[quickcheck]
620    fn public_key_try_from_correct_size(public_key: PublicKey) -> TestResult {
621        let mut bytes = public_key.key.as_ref().to_vec();
622        bytes.extend(&public_key.chain_code.0);
623        match PublicKey::try_from(bytes.as_slice()) {
624            Ok(_) => TestResult::passed(),
625            Err(PublicKeyError::InvalidSize) => {
626                TestResult::error("was expecting the test to pass, not an invalid size")
627            }
628            Err(PublicKeyError::InvalidPublicKey(
629                ed25519_extended::PublicKeyError::InvalidSize,
630            )) => unreachable!("The total size of the key is already being checked"),
631            Err(PublicKeyError::InvalidChainCode(ChainCodeError::InvalidSize)) => {
632                unreachable!("The total size of the key is already being checked")
633            }
634        }
635    }
636
637    #[quickcheck]
638    fn public_key_try_from_incorrect_size(bytes: Vec<u8>) -> TestResult {
639        if bytes.len() == PublicKey::SIZE {
640            return TestResult::discard();
641        }
642        match PublicKey::try_from(bytes.as_slice()) {
643            Ok(_) => TestResult::error(
644                "Expecting to fail with invalid size instead of having a valid value",
645            ),
646            Err(PublicKeyError::InvalidSize) => TestResult::passed(),
647            Err(PublicKeyError::InvalidPublicKey(
648                ed25519_extended::PublicKeyError::InvalidSize,
649            )) => unreachable!("The total size of the key is already being checked"),
650            Err(PublicKeyError::InvalidChainCode(ChainCodeError::InvalidSize)) => {
651                unreachable!("The total size of the key is already being checked")
652            }
653        }
654    }
655
656    #[quickcheck]
657    fn chain_code_try_from_correct_size(chain_code: ChainCode) -> TestResult {
658        match ChainCode::try_from(chain_code.0.as_ref()) {
659            Ok(_) => TestResult::passed(),
660            Err(ChainCodeError::InvalidSize) => {
661                TestResult::error("was expecting the test to pass, not an invalid size")
662            }
663        }
664    }
665
666    #[quickcheck]
667    fn chain_code_try_from_incorrect_size(bytes: Vec<u8>) -> TestResult {
668        if bytes.len() == ChainCode::SIZE {
669            return TestResult::discard();
670        }
671        match ChainCode::try_from(bytes.as_slice()) {
672            Ok(_) => TestResult::error(
673                "Expecting to fail with invalid size instead of having a valid value",
674            ),
675            Err(ChainCodeError::InvalidSize) => TestResult::passed(),
676        }
677    }
678
679    #[quickcheck]
680    fn public_key_from_str(public_key: PublicKey) -> TestResult {
681        let mut bytes = public_key.key.as_ref().to_vec();
682        bytes.extend(&public_key.chain_code.0);
683        let s = hex::encode(bytes);
684
685        match s.parse::<PublicKey>() {
686            Ok(decoded) => {
687                if decoded == public_key {
688                    TestResult::passed()
689                } else {
690                    TestResult::error("the decoded key is not equal")
691                }
692            }
693            Err(error) => TestResult::error(error.to_string()),
694        }
695    }
696
697    #[quickcheck]
698    fn chain_code_from_str(chain_code: ChainCode) -> TestResult {
699        let s = hex::encode(&chain_code);
700
701        match s.parse::<ChainCode>() {
702            Ok(decoded) => {
703                if decoded == chain_code {
704                    TestResult::passed()
705                } else {
706                    TestResult::error("the decoded chain_code is not equal")
707                }
708            }
709            Err(error) => TestResult::error(error.to_string()),
710        }
711    }
712
713    #[quickcheck]
714    fn derivation_from_signing_and_public_key(root_key: SecretKey, path: Vec<u8>) -> TestResult {
715        let root_public_key = root_key.public_key();
716
717        let d1 = root_key.derive(&path);
718        let d2 = root_public_key.derive(path).unwrap();
719
720        TestResult::from_bool(Some(d1.public_key()) == Some(d2))
721    }
722
723    #[quickcheck]
724    fn different_derivation_from_signing_key(
725        root_key: SecretKey,
726        path1: Vec<u8>,
727        path2: Vec<u8>,
728    ) -> TestResult {
729        if path1 == path2 {
730            return TestResult::discard();
731        }
732
733        let dp1 = root_key.derive(&path1);
734        let dp2 = root_key.derive(&path2);
735
736        TestResult::from_bool(dp1 != dp2)
737    }
738
739    #[quickcheck]
740    fn different_derivation_from_public_key(
741        root_key: PublicKey,
742        path1: Vec<u8>,
743        path2: Vec<u8>,
744    ) -> TestResult {
745        if path1 == path2 {
746            return TestResult::discard();
747        }
748
749        let dp1 = root_key.derive(&path1).unwrap();
750        let dp2 = root_key.derive(&path2).unwrap();
751
752        dbg!(hex::encode(&path2));
753        dbg!(hex::encode(&path1));
754        dbg!(&dp1);
755        dbg!(&dp2);
756        TestResult::from_bool(dp1 != dp2)
757    }
758}