@@ -18,13 +18,15 @@ use crate::prelude::*;
1818use crate :: serde:: { Deserialize , Deserializer , Serialize , Serializer } ;
1919use crate :: { hash256, MiniscriptKey , ToPublicKey } ;
2020
21+ type DescriptorExtendedPublicKey = DescriptorXKey < bip32:: ExtendedPubKey > ;
22+
2123/// The descriptor pubkey, either a single pubkey or an xpub.
2224#[ derive( Debug , Eq , PartialEq , Clone , Ord , PartialOrd , Hash ) ]
2325pub enum DescriptorPublicKey {
2426 /// Single public key.
2527 Single ( SinglePub ) ,
2628 /// Extended public key (xpub).
27- XPub ( DescriptorXKey < bip32 :: ExtendedPubKey > ) ,
29+ XPub ( DescriptorExtendedPublicKey ) ,
2830 /// Multiple extended public keys.
2931 MultiXPub ( DescriptorMultiXKey < bip32:: ExtendedPubKey > ) ,
3032}
@@ -283,6 +285,20 @@ impl error::Error for DescriptorKeyParseError {
283285 }
284286}
285287
288+ impl fmt:: Display for DescriptorExtendedPublicKey {
289+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
290+ maybe_fmt_master_id ( f, & self . origin ) ?;
291+ self . xkey . fmt ( f) ?;
292+ fmt_derivation_path ( f, & self . derivation_path ) ?;
293+ match self . wildcard {
294+ Wildcard :: None => { }
295+ Wildcard :: Unhardened => write ! ( f, "/*" ) ?,
296+ Wildcard :: Hardened => write ! ( f, "/*h" ) ?,
297+ }
298+ Ok ( ( ) )
299+ }
300+ }
301+
286302impl fmt:: Display for DescriptorPublicKey {
287303 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
288304 match * self {
@@ -294,17 +310,7 @@ impl fmt::Display for DescriptorPublicKey {
294310 } ?;
295311 Ok ( ( ) )
296312 }
297- DescriptorPublicKey :: XPub ( ref xpub) => {
298- maybe_fmt_master_id ( f, & xpub. origin ) ?;
299- xpub. xkey . fmt ( f) ?;
300- fmt_derivation_path ( f, & xpub. derivation_path ) ?;
301- match xpub. wildcard {
302- Wildcard :: None => { }
303- Wildcard :: Unhardened => write ! ( f, "/*" ) ?,
304- Wildcard :: Hardened => write ! ( f, "/*h" ) ?,
305- }
306- Ok ( ( ) )
307- }
313+ DescriptorPublicKey :: XPub ( ref xpub) => xpub. fmt ( f) ,
308314 DescriptorPublicKey :: MultiXPub ( ref xpub) => {
309315 maybe_fmt_master_id ( f, & xpub. origin ) ?;
310316 xpub. xkey . fmt ( f) ?;
@@ -503,13 +509,16 @@ pub enum ConversionError {
503509 HardenedChild ,
504510 /// Attempted to convert a key with multiple derivation paths to a bitcoin public key
505511 MultiKey ,
512+ /// Attempted to convert a key with a wildcard to a bitcoin public key
513+ Wildcard ,
506514}
507515
508516impl fmt:: Display for ConversionError {
509517 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
510518 f. write_str ( match * self {
511519 ConversionError :: HardenedChild => "hardened child step in bip32 path" ,
512520 ConversionError :: MultiKey => "multiple existing keys" ,
521+ ConversionError :: Wildcard => "wildcard in bip32 path" ,
513522 } )
514523 }
515524}
@@ -520,7 +529,7 @@ impl error::Error for ConversionError {
520529 use self :: ConversionError :: * ;
521530
522531 match self {
523- HardenedChild | MultiKey => None ,
532+ HardenedChild | MultiKey | Wildcard => None ,
524533 }
525534 }
526535}
@@ -572,17 +581,102 @@ pub trait DescriptorInnerKey {
572581 secp : & Secp256k1 < C > ,
573582 ) -> Result < bitcoin:: PublicKey , ConversionError > ;
574583}
584+
585+ impl DescriptorInnerKey for DescriptorExtendedPublicKey {
586+ /// The fingerprint of the master key associated with this key, `0x00000000` if none.
587+ fn master_fingerprint ( & self ) -> bip32:: Fingerprint {
588+ if let Some ( ( fingerprint, _) ) = self . origin {
589+ fingerprint
590+ } else {
591+ self . xkey . fingerprint ( )
592+ }
593+ }
594+
595+ /// Full path, from the master key
596+ ///
597+ /// For wildcard keys this will return the path up to the wildcard, so you
598+ /// can get full paths by appending one additional derivation step, according
599+ /// to the wildcard type (hardened or normal).
600+ ///
601+ /// For multipath extended keys, this returns `None`.
602+ fn full_derivation_path ( & self ) -> Option < bip32:: DerivationPath > {
603+ let origin_path = if let Some ( ( _, ref path) ) = self . origin {
604+ path. clone ( )
605+ } else {
606+ bip32:: DerivationPath :: from ( vec ! [ ] )
607+ } ;
608+ Some ( origin_path. extend ( & self . derivation_path ) )
609+ }
610+
611+ /// Whether or not the key has a wildcard
612+ fn has_wildcard ( & self ) -> bool {
613+ self . wildcard != Wildcard :: None
614+ }
615+
616+ /// Replaces any wildcard (i.e. `/*`) in the key with a particular derivation index, turning it into a
617+ /// *definite* key (i.e. one where all the derivation paths are set).
618+ ///
619+ /// # Returns
620+ ///
621+ /// - If this key is not an xpub, returns `self`.
622+ /// - If this key is an xpub but does not have a wildcard, returns `self`.
623+ /// - Otherwise, returns the xpub at derivation `index` (removing the wildcard).
624+ ///
625+ /// # Errors
626+ ///
627+ /// - If `index` is hardened.
628+ fn at_derivation_index ( self , index : u32 ) -> Result < DefiniteDescriptorKey , ConversionError > {
629+ let derivation_path = match self . wildcard {
630+ Wildcard :: None => self . derivation_path ,
631+ Wildcard :: Unhardened => self . derivation_path . into_child (
632+ bip32:: ChildNumber :: from_normal_idx ( index)
633+ . ok ( )
634+ . ok_or ( ConversionError :: HardenedChild ) ?,
635+ ) ,
636+ Wildcard :: Hardened => self . derivation_path . into_child (
637+ bip32:: ChildNumber :: from_hardened_idx ( index)
638+ . ok ( )
639+ . ok_or ( ConversionError :: HardenedChild ) ?,
640+ ) ,
641+ } ;
642+ let definite = DescriptorPublicKey :: XPub ( DescriptorXKey {
643+ origin : self . origin ,
644+ xkey : self . xkey ,
645+ derivation_path,
646+ wildcard : Wildcard :: None ,
647+ } ) ;
648+
649+ Ok ( DefiniteDescriptorKey :: new ( definite)
650+ . expect ( "The key should not contain any wildcards at this point" ) )
651+ }
652+
653+ /// Whether or not this key has multiple derivation paths.
654+ fn is_multipath ( & self ) -> bool {
655+ false
656+ }
657+
658+ fn derive_public_key < C : Verification > (
659+ & self ,
660+ secp : & Secp256k1 < C > ,
661+ ) -> Result < bitcoin:: PublicKey , ConversionError > {
662+ match self . wildcard {
663+ Wildcard :: Unhardened | Wildcard :: Hardened => Err ( ConversionError :: Wildcard ) ,
664+ Wildcard :: None => match self . xkey . derive_pub ( secp, & self . derivation_path . as_ref ( ) ) {
665+ Ok ( xpub) => Ok ( bitcoin:: PublicKey :: new ( xpub. public_key ) ) ,
666+ Err ( bip32:: Error :: CannotDeriveFromHardenedKey ) => {
667+ Err ( ConversionError :: HardenedChild )
668+ }
669+ Err ( e) => unreachable ! ( "cryptographically unreachable: {}" , e) ,
670+ } ,
671+ }
672+ }
673+ }
674+
575675impl DescriptorPublicKey {
576676 /// The fingerprint of the master key associated with this key, `0x00000000` if none.
577677 pub fn master_fingerprint ( & self ) -> bip32:: Fingerprint {
578678 match * self {
579- DescriptorPublicKey :: XPub ( ref xpub) => {
580- if let Some ( ( fingerprint, _) ) = xpub. origin {
581- fingerprint
582- } else {
583- xpub. xkey . fingerprint ( )
584- }
585- }
679+ DescriptorPublicKey :: XPub ( ref xpub) => xpub. master_fingerprint ( ) ,
586680 DescriptorPublicKey :: MultiXPub ( ref xpub) => {
587681 if let Some ( ( fingerprint, _) ) = xpub. origin {
588682 fingerprint
@@ -620,14 +714,7 @@ impl DescriptorPublicKey {
620714 /// For multipath extended keys, this returns `None`.
621715 pub fn full_derivation_path ( & self ) -> Option < bip32:: DerivationPath > {
622716 match * self {
623- DescriptorPublicKey :: XPub ( ref xpub) => {
624- let origin_path = if let Some ( ( _, ref path) ) = xpub. origin {
625- path. clone ( )
626- } else {
627- bip32:: DerivationPath :: from ( vec ! [ ] )
628- } ;
629- Some ( origin_path. extend ( & xpub. derivation_path ) )
630- }
717+ DescriptorPublicKey :: XPub ( ref xpub) => xpub. full_derivation_path ( ) ,
631718 DescriptorPublicKey :: Single ( ref single) => {
632719 Some ( if let Some ( ( _, ref path) ) = single. origin {
633720 path. clone ( )
@@ -649,7 +736,7 @@ impl DescriptorPublicKey {
649736 pub fn has_wildcard ( & self ) -> bool {
650737 match * self {
651738 DescriptorPublicKey :: Single ( ..) => false ,
652- DescriptorPublicKey :: XPub ( ref xpub) => xpub. wildcard != Wildcard :: None ,
739+ DescriptorPublicKey :: XPub ( ref xpub) => xpub. has_wildcard ( ) ,
653740 DescriptorPublicKey :: MultiXPub ( ref xpub) => xpub. wildcard != Wildcard :: None ,
654741 }
655742 }
@@ -673,40 +760,19 @@ impl DescriptorPublicKey {
673760 ///
674761 /// - If `index` is hardened.
675762 pub fn at_derivation_index ( self , index : u32 ) -> Result < DefiniteDescriptorKey , ConversionError > {
676- let definite = match self {
677- DescriptorPublicKey :: Single ( _) => self ,
678- DescriptorPublicKey :: XPub ( xpub) => {
679- let derivation_path = match xpub. wildcard {
680- Wildcard :: None => xpub. derivation_path ,
681- Wildcard :: Unhardened => xpub. derivation_path . into_child (
682- bip32:: ChildNumber :: from_normal_idx ( index)
683- . ok ( )
684- . ok_or ( ConversionError :: HardenedChild ) ?,
685- ) ,
686- Wildcard :: Hardened => xpub. derivation_path . into_child (
687- bip32:: ChildNumber :: from_hardened_idx ( index)
688- . ok ( )
689- . ok_or ( ConversionError :: HardenedChild ) ?,
690- ) ,
691- } ;
692- DescriptorPublicKey :: XPub ( DescriptorXKey {
693- origin : xpub. origin ,
694- xkey : xpub. xkey ,
695- derivation_path,
696- wildcard : Wildcard :: None ,
697- } )
698- }
699- DescriptorPublicKey :: MultiXPub ( _) => return Err ( ConversionError :: MultiKey ) ,
700- } ;
701-
702- Ok ( DefiniteDescriptorKey :: new ( definite)
703- . expect ( "The key should not contain any wildcards at this point" ) )
763+ match self {
764+ DescriptorPublicKey :: Single ( _) => Ok ( DefiniteDescriptorKey :: new ( self )
765+ . expect ( "The key should not contain any wildcards at this point" ) ) ,
766+ DescriptorPublicKey :: XPub ( xpub) => xpub. at_derivation_index ( index) ,
767+ DescriptorPublicKey :: MultiXPub ( _) => Err ( ConversionError :: MultiKey ) ,
768+ }
704769 }
705770
706771 /// Whether or not this key has multiple derivation paths.
707772 pub fn is_multipath ( & self ) -> bool {
708- match * self {
709- DescriptorPublicKey :: Single ( ..) | DescriptorPublicKey :: XPub ( ..) => false ,
773+ match self {
774+ DescriptorPublicKey :: Single ( ..) => false ,
775+ DescriptorPublicKey :: XPub ( xpub) => xpub. is_multipath ( ) ,
710776 DescriptorPublicKey :: MultiXPub ( _) => true ,
711777 }
712778 }
@@ -1083,18 +1149,7 @@ impl DefiniteDescriptorKey {
10831149 SinglePubKey :: FullKey ( pk) => Ok ( pk) ,
10841150 SinglePubKey :: XOnly ( xpk) => Ok ( xpk. to_public_key ( ) ) ,
10851151 } ,
1086- DescriptorPublicKey :: XPub ( ref xpk) => match xpk. wildcard {
1087- Wildcard :: Unhardened | Wildcard :: Hardened => {
1088- unreachable ! ( "we've excluded this error case" )
1089- }
1090- Wildcard :: None => match xpk. xkey . derive_pub ( secp, & xpk. derivation_path . as_ref ( ) ) {
1091- Ok ( xpub) => Ok ( bitcoin:: PublicKey :: new ( xpub. public_key ) ) ,
1092- Err ( bip32:: Error :: CannotDeriveFromHardenedKey ) => {
1093- Err ( ConversionError :: HardenedChild )
1094- }
1095- Err ( e) => unreachable ! ( "cryptographically unreachable: {}" , e) ,
1096- } ,
1097- } ,
1152+ DescriptorPublicKey :: XPub ( ref xpk) => xpk. derive_public_key ( secp) ,
10981153 DescriptorPublicKey :: MultiXPub ( _) => {
10991154 unreachable ! ( "A definite key cannot contain a multipath key." )
11001155 }
0 commit comments