@@ -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
} ;
@@ -70,6 +69,15 @@ pub enum SinglePubKey {
70
69
XOnly ( XOnlyPublicKey ) ,
71
70
}
72
71
72
+ /// A derived [`DescriptorPublicKey`]
73
+ ///
74
+ /// Derived keys are guaranteed to never contain wildcards
75
+ #[ derive( Debug , Eq , PartialEq , Clone , Ord , PartialOrd , Hash ) ]
76
+ pub struct DerivedDescriptorKey {
77
+ key : DescriptorPublicKey ,
78
+ index : u32 ,
79
+ }
80
+
73
81
impl fmt:: Display for DescriptorSecretKey {
74
82
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
75
83
match self {
@@ -434,7 +442,7 @@ impl DescriptorPublicKey {
434
442
/// If this public key has a wildcard, replace it by the given index
435
443
///
436
444
/// Panics if given an index ≥ 2^31
437
- pub fn derive ( mut self , index : u32 ) -> DescriptorPublicKey {
445
+ pub fn derive ( mut self , index : u32 ) -> DerivedDescriptorKey {
438
446
if let DescriptorPublicKey :: XPub ( mut xpub) = self {
439
447
match xpub. wildcard {
440
448
Wildcard :: None => { }
@@ -452,7 +460,9 @@ impl DescriptorPublicKey {
452
460
xpub. wildcard = Wildcard :: None ;
453
461
self = DescriptorPublicKey :: XPub ( xpub) ;
454
462
}
455
- self
463
+
464
+ DerivedDescriptorKey :: new ( self , index)
465
+ . expect ( "The key should not contain any wildcards at this point" )
456
466
}
457
467
458
468
/// Computes the public key corresponding to this descriptor key.
@@ -467,7 +477,7 @@ impl DescriptorPublicKey {
467
477
/// to avoid hardened derivation steps, start from a `DescriptorSecretKey`
468
478
/// and call `as_public`, or call `TranslatePk2::translate_pk2` with
469
479
/// some function which has access to secret key data.
470
- pub fn derive_public_key < C : secp256k1 :: Verification > (
480
+ pub fn derive_public_key < C : Verification > (
471
481
& self ,
472
482
secp : & Secp256k1 < C > ,
473
483
) -> Result < bitcoin:: PublicKey , ConversionError > {
@@ -713,6 +723,70 @@ impl MiniscriptKey for DescriptorPublicKey {
713
723
}
714
724
}
715
725
726
+ impl DerivedDescriptorKey {
727
+ /// Computes the raw [`bitcoin::PublicKey`] for this descriptor key.
728
+ ///
729
+ /// Will return an error if the key has any hardened derivation steps
730
+ /// in its path, but unlike [`DescriptorPublicKey::derive_public_key`]
731
+ /// this won't error in case of wildcards, because derived keys are
732
+ /// guaranteed to never contain one.
733
+ pub fn derive_public_key < C : Verification > (
734
+ & self ,
735
+ secp : & Secp256k1 < C > ,
736
+ ) -> Result < bitcoin:: PublicKey , ConversionError > {
737
+ self . key . derive_public_key ( secp)
738
+ }
739
+
740
+ /// Return the derivation index of this key
741
+ pub fn get_index ( & self ) -> u32 {
742
+ self . index
743
+ }
744
+
745
+ /// Construct an instance from a descriptor key and a derivation index
746
+ ///
747
+ /// Returns `None` if the key contains a wildcard
748
+ fn new ( key : DescriptorPublicKey , index : u32 ) -> Option < Self > {
749
+ match key {
750
+ DescriptorPublicKey :: XPub ( ref xpk) if xpk. wildcard != Wildcard :: None => None ,
751
+ k => Some ( DerivedDescriptorKey { key : k, index } ) ,
752
+ }
753
+ }
754
+ }
755
+
756
+ impl fmt:: Display for DerivedDescriptorKey {
757
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
758
+ self . key . fmt ( f)
759
+ }
760
+ }
761
+
762
+ impl MiniscriptKey for DerivedDescriptorKey {
763
+ // This allows us to be able to derive public keys even for PkH s
764
+ type Hash = Self ;
765
+
766
+ fn is_uncompressed ( & self ) -> bool {
767
+ self . key . is_uncompressed ( )
768
+ }
769
+
770
+ fn is_x_only_key ( & self ) -> bool {
771
+ self . key . is_x_only_key ( )
772
+ }
773
+
774
+ fn to_pubkeyhash ( & self ) -> Self {
775
+ self . clone ( )
776
+ }
777
+ }
778
+
779
+ impl ToPublicKey for DerivedDescriptorKey {
780
+ fn to_public_key ( & self ) -> bitcoin:: PublicKey {
781
+ let secp = Secp256k1 :: verification_only ( ) ;
782
+ self . key . derive_public_key ( & secp) . unwrap ( )
783
+ }
784
+
785
+ fn hash_to_hash160 ( hash : & Self ) -> hash160:: Hash {
786
+ hash. to_public_key ( ) . to_pubkeyhash ( )
787
+ }
788
+ }
789
+
716
790
#[ cfg( test) ]
717
791
mod test {
718
792
use super :: { DescriptorKeyParseError , DescriptorPublicKey , DescriptorSecretKey } ;
0 commit comments