@@ -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 {
@@ -437,11 +445,14 @@ impl DescriptorPublicKey {
437
445
/// - If this key is an xpub but does not have a wildcard, returns `self`.
438
446
/// - Otherwise, returns the derived xpub at `index` (removing the wildcard).
439
447
///
448
+ /// Since it's guaranteed that extended keys won't have wildcards, the key is returned as
449
+ /// [`DerivedDescriptorKey`].
450
+ ///
440
451
/// # Panics
441
452
///
442
453
/// If `index` ≥ 2^31
443
- pub fn derive ( self , index : u32 ) -> DescriptorPublicKey {
444
- match self {
454
+ pub fn derive ( self , index : u32 ) -> DerivedDescriptorKey {
455
+ let derived = match self {
445
456
DescriptorPublicKey :: Single ( _) => self ,
446
457
DescriptorPublicKey :: XPub ( xpub) => {
447
458
let derivation_path = match xpub. wildcard {
@@ -460,7 +471,10 @@ impl DescriptorPublicKey {
460
471
wildcard : Wildcard :: None ,
461
472
} )
462
473
}
463
- }
474
+ } ;
475
+
476
+ DerivedDescriptorKey :: new ( derived, index)
477
+ . expect ( "The key should not contain any wildcards at this point" )
464
478
}
465
479
466
480
/// Computes the public key corresponding to this descriptor key.
@@ -475,7 +489,7 @@ impl DescriptorPublicKey {
475
489
/// to avoid hardened derivation steps, start from a `DescriptorSecretKey`
476
490
/// and call `to_public`, or call `TranslatePk2::translate_pk2` with
477
491
/// some function which has access to secret key data.
478
- pub fn derive_public_key < C : secp256k1 :: Verification > (
492
+ pub fn derive_public_key < C : Verification > (
479
493
& self ,
480
494
secp : & Secp256k1 < C > ,
481
495
) -> Result < bitcoin:: PublicKey , ConversionError > {
@@ -720,6 +734,70 @@ impl MiniscriptKey for DescriptorPublicKey {
720
734
}
721
735
}
722
736
737
+ impl DerivedDescriptorKey {
738
+ /// Computes the raw [`bitcoin::PublicKey`] for this descriptor key.
739
+ ///
740
+ /// Will return an error if the key has any hardened derivation steps
741
+ /// in its path, but unlike [`DescriptorPublicKey::derive_public_key`]
742
+ /// this won't error in case of wildcards, because derived keys are
743
+ /// guaranteed to never contain one.
744
+ pub fn derive_public_key < C : Verification > (
745
+ & self ,
746
+ secp : & Secp256k1 < C > ,
747
+ ) -> Result < bitcoin:: PublicKey , ConversionError > {
748
+ self . key . derive_public_key ( secp)
749
+ }
750
+
751
+ /// Return the derivation index of this key
752
+ pub fn index ( & self ) -> u32 {
753
+ self . index
754
+ }
755
+
756
+ /// Construct an instance from a descriptor key and a derivation index
757
+ ///
758
+ /// Returns `None` if the key contains a wildcard
759
+ fn new ( key : DescriptorPublicKey , index : u32 ) -> Option < Self > {
760
+ match key {
761
+ DescriptorPublicKey :: XPub ( ref xpk) if xpk. wildcard != Wildcard :: None => None ,
762
+ k => Some ( DerivedDescriptorKey { key : k, index } ) ,
763
+ }
764
+ }
765
+ }
766
+
767
+ impl fmt:: Display for DerivedDescriptorKey {
768
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
769
+ self . key . fmt ( f)
770
+ }
771
+ }
772
+
773
+ impl MiniscriptKey for DerivedDescriptorKey {
774
+ // This allows us to be able to derive public keys even for PkH s
775
+ type Hash = Self ;
776
+
777
+ fn is_uncompressed ( & self ) -> bool {
778
+ self . key . is_uncompressed ( )
779
+ }
780
+
781
+ fn is_x_only_key ( & self ) -> bool {
782
+ self . key . is_x_only_key ( )
783
+ }
784
+
785
+ fn to_pubkeyhash ( & self ) -> Self {
786
+ self . clone ( )
787
+ }
788
+ }
789
+
790
+ impl ToPublicKey for DerivedDescriptorKey {
791
+ fn to_public_key ( & self ) -> bitcoin:: PublicKey {
792
+ let secp = Secp256k1 :: verification_only ( ) ;
793
+ self . key . derive_public_key ( & secp) . unwrap ( )
794
+ }
795
+
796
+ fn hash_to_hash160 ( hash : & Self ) -> hash160:: Hash {
797
+ hash. to_public_key ( ) . to_pubkeyhash ( )
798
+ }
799
+ }
800
+
723
801
#[ cfg( test) ]
724
802
mod test {
725
803
use super :: { DescriptorKeyParseError , DescriptorPublicKey , DescriptorSecretKey } ;
0 commit comments