@@ -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} ;
@@ -70,6 +69,15 @@ pub enum SinglePubKey {
7069 XOnly ( XOnlyPublicKey ) ,
7170}
7271
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+
7381impl fmt:: Display for DescriptorSecretKey {
7482 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
7583 match self {
@@ -437,11 +445,14 @@ impl DescriptorPublicKey {
437445 /// - If this key is an xpub but does not have a wildcard, returns `self`.
438446 /// - Otherwise, returns the derived xpub at `index` (removing the wildcard).
439447 ///
448+ /// Since it's guaranteed that extended keys won't have wildcards, the key is returned as
449+ /// [`DerivedDescriptorKey`].
450+ ///
440451 /// # Panics
441452 ///
442453 /// 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 {
445456 DescriptorPublicKey :: Single ( _) => self ,
446457 DescriptorPublicKey :: XPub ( xpub) => {
447458 let derivation_path = match xpub. wildcard {
@@ -460,7 +471,10 @@ impl DescriptorPublicKey {
460471 wildcard : Wildcard :: None ,
461472 } )
462473 }
463- }
474+ } ;
475+
476+ DerivedDescriptorKey :: new ( derived, index)
477+ . expect ( "The key should not contain any wildcards at this point" )
464478 }
465479
466480 /// Computes the public key corresponding to this descriptor key.
@@ -475,7 +489,7 @@ impl DescriptorPublicKey {
475489 /// to avoid hardened derivation steps, start from a `DescriptorSecretKey`
476490 /// and call `to_public`, or call `TranslatePk2::translate_pk2` with
477491 /// 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 > (
479493 & self ,
480494 secp : & Secp256k1 < C > ,
481495 ) -> Result < bitcoin:: PublicKey , ConversionError > {
@@ -720,6 +734,70 @@ impl MiniscriptKey for DescriptorPublicKey {
720734 }
721735}
722736
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+
723801#[ cfg( test) ]
724802mod test {
725803 use super :: { DescriptorKeyParseError , DescriptorPublicKey , DescriptorSecretKey } ;
0 commit comments