@@ -2,10 +2,9 @@ use std::{error, fmt, str::FromStr};
2
2
3
3
use bitcoin:: {
4
4
self ,
5
- hashes:: Hash ,
5
+ hashes:: { hash160 , Hash } ,
6
6
hashes:: { hex:: FromHex , HashEngine } ,
7
- secp256k1,
8
- secp256k1:: { Secp256k1 , Signing } ,
7
+ secp256k1:: { Secp256k1 , Signing , Verification } ,
9
8
util:: bip32,
10
9
XOnlyPublicKey , XpubIdentifier ,
11
10
} ;
@@ -58,6 +57,15 @@ pub enum DescriptorSecretKey {
58
57
XPrv ( DescriptorXKey < bip32:: ExtendedPrivKey > ) ,
59
58
}
60
59
60
+ /// A derived [`DescriptorPublicKey`]
61
+ ///
62
+ /// Derived keys are guaranteed to never contain wildcards
63
+ #[ derive( Debug , Eq , PartialEq , Clone , Ord , PartialOrd , Hash ) ]
64
+ pub struct DerivedDescriptorKey {
65
+ key : DescriptorPublicKey ,
66
+ index : u32 ,
67
+ }
68
+
61
69
impl fmt:: Display for DescriptorSecretKey {
62
70
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
63
71
match self {
@@ -438,7 +446,7 @@ impl DescriptorPublicKey {
438
446
/// If this public key has a wildcard, replace it by the given index
439
447
///
440
448
/// Panics if given an index ≥ 2^31
441
- pub fn derive ( mut self , index : u32 ) -> DescriptorPublicKey {
449
+ pub fn derive ( mut self , index : u32 ) -> DerivedDescriptorKey {
442
450
if let DescriptorPublicKey :: XPub ( mut xpub) = self {
443
451
match xpub. wildcard {
444
452
Wildcard :: None => { }
@@ -456,7 +464,9 @@ impl DescriptorPublicKey {
456
464
xpub. wildcard = Wildcard :: None ;
457
465
self = DescriptorPublicKey :: XPub ( xpub) ;
458
466
}
459
- self
467
+
468
+ DerivedDescriptorKey :: new ( self , index)
469
+ . expect ( "The key should not contain any wildcards at this point" )
460
470
}
461
471
462
472
/// Computes the public key corresponding to this descriptor key.
@@ -471,7 +481,7 @@ impl DescriptorPublicKey {
471
481
/// to avoid hardened derivation steps, start from a `DescriptorSecretKey`
472
482
/// and call `as_public`, or call `TranslatePk2::translate_pk2` with
473
483
/// some function which has access to secret key data.
474
- pub fn derive_public_key < C : secp256k1 :: Verification > (
484
+ pub fn derive_public_key < C : Verification > (
475
485
& self ,
476
486
secp : & Secp256k1 < C > ,
477
487
) -> Result < bitcoin:: PublicKey , ConversionError > {
@@ -717,6 +727,70 @@ impl MiniscriptKey for DescriptorPublicKey {
717
727
}
718
728
}
719
729
730
+ impl DerivedDescriptorKey {
731
+ /// Computes the raw [`bitcoin::PublicKey`] for this descriptor key.
732
+ ///
733
+ /// Will return an error if the key has any hardened derivation steps
734
+ /// in its path, but unlike [`DescriptorPublicKey::derive_public_key`]
735
+ /// this won't error in case of wildcards, because derived keys are
736
+ /// guaranteed to never contain one.
737
+ pub fn derive_public_key < C : Verification > (
738
+ & self ,
739
+ secp : & Secp256k1 < C > ,
740
+ ) -> Result < bitcoin:: PublicKey , ConversionError > {
741
+ self . key . derive_public_key ( secp)
742
+ }
743
+
744
+ /// Return the derivation index of this key
745
+ pub fn get_index ( & self ) -> u32 {
746
+ self . index
747
+ }
748
+
749
+ /// Construct an instance from a descriptor key and a derivation index
750
+ ///
751
+ /// Returns `None` if the key contains a wildcard
752
+ fn new ( key : DescriptorPublicKey , index : u32 ) -> Option < Self > {
753
+ match key {
754
+ DescriptorPublicKey :: XPub ( ref xpk) if xpk. wildcard != Wildcard :: None => None ,
755
+ k => Some ( DerivedDescriptorKey { key : k, index } ) ,
756
+ }
757
+ }
758
+ }
759
+
760
+ impl fmt:: Display for DerivedDescriptorKey {
761
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
762
+ self . key . fmt ( f)
763
+ }
764
+ }
765
+
766
+ impl MiniscriptKey for DerivedDescriptorKey {
767
+ // This allows us to be able to derive public keys even for PkH s
768
+ type Hash = Self ;
769
+
770
+ fn is_uncompressed ( & self ) -> bool {
771
+ self . key . is_uncompressed ( )
772
+ }
773
+
774
+ fn is_x_only_key ( & self ) -> bool {
775
+ self . key . is_x_only_key ( )
776
+ }
777
+
778
+ fn to_pubkeyhash ( & self ) -> Self {
779
+ self . clone ( )
780
+ }
781
+ }
782
+
783
+ impl ToPublicKey for DerivedDescriptorKey {
784
+ fn to_public_key ( & self ) -> bitcoin:: PublicKey {
785
+ let secp = Secp256k1 :: verification_only ( ) ;
786
+ self . key . derive_public_key ( & secp) . unwrap ( )
787
+ }
788
+
789
+ fn hash_to_hash160 ( hash : & Self ) -> hash160:: Hash {
790
+ hash. to_public_key ( ) . to_pubkeyhash ( )
791
+ }
792
+ }
793
+
720
794
#[ cfg( test) ]
721
795
mod test {
722
796
use super :: { DescriptorKeyParseError , DescriptorPublicKey , DescriptorSecretKey } ;
0 commit comments