@@ -2,10 +2,9 @@ use std::{error, fmt, str::FromStr};
22
33use bitcoin:: {
44 self ,
5- hashes:: Hash ,
5+ hashes:: { hash160 , Hash } ,
66 hashes:: { hex:: FromHex , HashEngine } ,
7- secp256k1,
8- secp256k1:: { Secp256k1 , Signing } ,
7+ secp256k1:: { Secp256k1 , Signing , Verification } ,
98 util:: bip32,
109 XOnlyPublicKey , XpubIdentifier ,
1110} ;
@@ -58,6 +57,15 @@ pub enum DescriptorSecretKey {
5857 XPrv ( DescriptorXKey < bip32:: ExtendedPrivKey > ) ,
5958}
6059
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+
6169impl fmt:: Display for DescriptorSecretKey {
6270 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
6371 match self {
@@ -438,7 +446,7 @@ impl DescriptorPublicKey {
438446 /// If this public key has a wildcard, replace it by the given index
439447 ///
440448 /// 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 {
442450 if let DescriptorPublicKey :: XPub ( mut xpub) = self {
443451 match xpub. wildcard {
444452 Wildcard :: None => { }
@@ -456,7 +464,9 @@ impl DescriptorPublicKey {
456464 xpub. wildcard = Wildcard :: None ;
457465 self = DescriptorPublicKey :: XPub ( xpub) ;
458466 }
459- self
467+
468+ DerivedDescriptorKey :: new ( self , index)
469+ . expect ( "The key should not contain any wildcards at this point" )
460470 }
461471
462472 /// Computes the public key corresponding to this descriptor key.
@@ -471,7 +481,7 @@ impl DescriptorPublicKey {
471481 /// to avoid hardened derivation steps, start from a `DescriptorSecretKey`
472482 /// and call `as_public`, or call `TranslatePk2::translate_pk2` with
473483 /// 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 > (
475485 & self ,
476486 secp : & Secp256k1 < C > ,
477487 ) -> Result < bitcoin:: PublicKey , ConversionError > {
@@ -717,6 +727,70 @@ impl MiniscriptKey for DescriptorPublicKey {
717727 }
718728}
719729
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+ _ => Some ( DerivedDescriptorKey { key, 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+
720794#[ cfg( test) ]
721795mod test {
722796 use super :: { DescriptorKeyParseError , DescriptorPublicKey , DescriptorSecretKey } ;
0 commit comments