@@ -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,8 @@ impl DescriptorPublicKey {
456
464
xpub. wildcard = Wildcard :: None ;
457
465
self = DescriptorPublicKey :: XPub ( xpub) ;
458
466
}
459
- self
467
+
468
+ DerivedDescriptorKey :: new ( self , index)
460
469
}
461
470
462
471
/// Computes the public key corresponding to this descriptor key.
@@ -471,7 +480,7 @@ impl DescriptorPublicKey {
471
480
/// to avoid hardened derivation steps, start from a `DescriptorSecretKey`
472
481
/// and call `as_public`, or call `TranslatePk2::translate_pk2` with
473
482
/// some function which has access to secret key data.
474
- pub fn derive_public_key < C : secp256k1 :: Verification > (
483
+ pub fn derive_public_key < C : Verification > (
475
484
& self ,
476
485
secp : & Secp256k1 < C > ,
477
486
) -> Result < bitcoin:: PublicKey , ConversionError > {
@@ -717,6 +726,74 @@ impl MiniscriptKey for DescriptorPublicKey {
717
726
}
718
727
}
719
728
729
+ impl DerivedDescriptorKey {
730
+ /// Computes the raw [`bitcoin::PublicKey`] for this descriptor key.
731
+ ///
732
+ /// Will return an error if the key has any hardened derivation steps
733
+ /// in its path, but unlike [`DescriptorPublicKey::derive_public_key`]
734
+ /// this won't error in case of wildcards, because derived keys are
735
+ /// guaranteed to never contain one.
736
+ pub fn derive_public_key < C : Verification > (
737
+ & self ,
738
+ secp : & Secp256k1 < C > ,
739
+ ) -> Result < bitcoin:: PublicKey , ConversionError > {
740
+ self . key . derive_public_key ( secp)
741
+ }
742
+
743
+ /// Return the derivation index of this key
744
+ pub fn get_index ( & self ) -> u32 {
745
+ self . index
746
+ }
747
+
748
+ /// Construct an instance from a descriptor key and a derivation index
749
+ ///
750
+ /// Panics if the key contains a wildcard
751
+ fn new ( key : DescriptorPublicKey , index : u32 ) -> Self {
752
+ if let DescriptorPublicKey :: XPub ( ref xpk) = & key {
753
+ assert ! (
754
+ xpk. wildcard == Wildcard :: None ,
755
+ "Derived descriptor keys cannot contain any wildcards"
756
+ ) ;
757
+ }
758
+
759
+ DerivedDescriptorKey { key, index }
760
+ }
761
+ }
762
+
763
+ impl fmt:: Display for DerivedDescriptorKey {
764
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
765
+ self . key . fmt ( f)
766
+ }
767
+ }
768
+
769
+ impl MiniscriptKey for DerivedDescriptorKey {
770
+ // This allows us to be able to derive public keys even for PkH s
771
+ type Hash = Self ;
772
+
773
+ fn is_uncompressed ( & self ) -> bool {
774
+ self . key . is_uncompressed ( )
775
+ }
776
+
777
+ fn is_x_only_key ( & self ) -> bool {
778
+ self . key . is_x_only_key ( )
779
+ }
780
+
781
+ fn to_pubkeyhash ( & self ) -> Self {
782
+ self . clone ( )
783
+ }
784
+ }
785
+
786
+ impl ToPublicKey for DerivedDescriptorKey {
787
+ fn to_public_key ( & self ) -> bitcoin:: PublicKey {
788
+ let secp = Secp256k1 :: verification_only ( ) ;
789
+ self . key . derive_public_key ( & secp) . unwrap ( )
790
+ }
791
+
792
+ fn hash_to_hash160 ( hash : & Self ) -> hash160:: Hash {
793
+ hash. to_public_key ( ) . to_pubkeyhash ( )
794
+ }
795
+ }
796
+
720
797
#[ cfg( test) ]
721
798
mod test {
722
799
use super :: { DescriptorKeyParseError , DescriptorPublicKey , DescriptorSecretKey } ;
0 commit comments