@@ -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) ?;
@@ -432,6 +438,30 @@ fn fmt_derivation_paths(f: &mut fmt::Formatter, paths: &[bip32::DerivationPath])
432438 Ok ( ( ) )
433439}
434440
441+ impl FromStr for DescriptorExtendedPublicKey {
442+ type Err = DescriptorKeyParseError ;
443+
444+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
445+ let ( key_part, origin) = parse_key_origin ( s) ?;
446+
447+ let ( xpub, derivation_paths, wildcard) =
448+ parse_xkey_deriv :: < bip32:: ExtendedPubKey > ( key_part) ?;
449+
450+ if derivation_paths. len ( ) > 1 {
451+ return Err ( DescriptorKeyParseError (
452+ "Multiple derivation paths are not allowed for single extended keys" ,
453+ ) ) ;
454+ }
455+
456+ Ok ( Self {
457+ origin,
458+ xkey : xpub,
459+ derivation_path : derivation_paths. into_iter ( ) . next ( ) . unwrap_or_default ( ) ,
460+ wildcard,
461+ } )
462+ }
463+ }
464+
435465impl FromStr for DescriptorPublicKey {
436466 type Err = DescriptorKeyParseError ;
437467
@@ -456,12 +486,7 @@ impl FromStr for DescriptorPublicKey {
456486 wildcard,
457487 } ) )
458488 } else {
459- Ok ( DescriptorPublicKey :: XPub ( DescriptorXKey {
460- origin,
461- xkey : xpub,
462- derivation_path : derivation_paths. into_iter ( ) . next ( ) . unwrap_or_default ( ) ,
463- wildcard,
464- } ) )
489+ DescriptorExtendedPublicKey :: from_str ( s) . map ( Self :: XPub )
465490 }
466491 } else {
467492 let key = match key_part. len ( ) {
@@ -503,13 +528,16 @@ pub enum ConversionError {
503528 HardenedChild ,
504529 /// Attempted to convert a key with multiple derivation paths to a bitcoin public key
505530 MultiKey ,
531+ /// Attempted to convert a key with a wildcard to a bitcoin public key
532+ Wildcard ,
506533}
507534
508535impl fmt:: Display for ConversionError {
509536 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
510537 f. write_str ( match * self {
511538 ConversionError :: HardenedChild => "hardened child step in bip32 path" ,
512539 ConversionError :: MultiKey => "multiple existing keys" ,
540+ ConversionError :: Wildcard => "wildcard in bip32 path" ,
513541 } )
514542 }
515543}
@@ -520,7 +548,7 @@ impl error::Error for ConversionError {
520548 use self :: ConversionError :: * ;
521549
522550 match self {
523- HardenedChild | MultiKey => None ,
551+ HardenedChild | MultiKey | Wildcard => None ,
524552 }
525553 }
526554}
@@ -572,17 +600,102 @@ pub trait DescriptorKey : Clone + fmt::Debug + fmt::Display + Eq + FromStr + std
572600 secp : & Secp256k1 < C > ,
573601 ) -> Result < bitcoin:: PublicKey , ConversionError > ;
574602}
603+
604+ impl DescriptorKey for DescriptorExtendedPublicKey {
605+ /// The fingerprint of the master key associated with this key, `0x00000000` if none.
606+ fn master_fingerprint ( & self ) -> bip32:: Fingerprint {
607+ if let Some ( ( fingerprint, _) ) = self . origin {
608+ fingerprint
609+ } else {
610+ self . xkey . fingerprint ( )
611+ }
612+ }
613+
614+ /// Full path, from the master key
615+ ///
616+ /// For wildcard keys this will return the path up to the wildcard, so you
617+ /// can get full paths by appending one additional derivation step, according
618+ /// to the wildcard type (hardened or normal).
619+ ///
620+ /// For multipath extended keys, this returns `None`.
621+ fn full_derivation_path ( & self ) -> Option < bip32:: DerivationPath > {
622+ let origin_path = if let Some ( ( _, ref path) ) = self . origin {
623+ path. clone ( )
624+ } else {
625+ bip32:: DerivationPath :: from ( vec ! [ ] )
626+ } ;
627+ Some ( origin_path. extend ( & self . derivation_path ) )
628+ }
629+
630+ /// Whether or not the key has a wildcard
631+ fn has_wildcard ( & self ) -> bool {
632+ self . wildcard != Wildcard :: None
633+ }
634+
635+ /// Replaces any wildcard (i.e. `/*`) in the key with a particular derivation index, turning it into a
636+ /// *definite* key (i.e. one where all the derivation paths are set).
637+ ///
638+ /// # Returns
639+ ///
640+ /// - If this key is not an xpub, returns `self`.
641+ /// - If this key is an xpub but does not have a wildcard, returns `self`.
642+ /// - Otherwise, returns the xpub at derivation `index` (removing the wildcard).
643+ ///
644+ /// # Errors
645+ ///
646+ /// - If `index` is hardened.
647+ fn at_derivation_index ( self , index : u32 ) -> Result < DefiniteDescriptorKey , ConversionError > {
648+ let derivation_path = match self . wildcard {
649+ Wildcard :: None => self . derivation_path ,
650+ Wildcard :: Unhardened => self . derivation_path . into_child (
651+ bip32:: ChildNumber :: from_normal_idx ( index)
652+ . ok ( )
653+ . ok_or ( ConversionError :: HardenedChild ) ?,
654+ ) ,
655+ Wildcard :: Hardened => self . derivation_path . into_child (
656+ bip32:: ChildNumber :: from_hardened_idx ( index)
657+ . ok ( )
658+ . ok_or ( ConversionError :: HardenedChild ) ?,
659+ ) ,
660+ } ;
661+ let definite = DescriptorPublicKey :: XPub ( DescriptorXKey {
662+ origin : self . origin ,
663+ xkey : self . xkey ,
664+ derivation_path,
665+ wildcard : Wildcard :: None ,
666+ } ) ;
667+
668+ Ok ( DefiniteDescriptorKey :: new ( definite)
669+ . expect ( "The key should not contain any wildcards at this point" ) )
670+ }
671+
672+ /// Whether or not this key has multiple derivation paths.
673+ fn is_multipath ( & self ) -> bool {
674+ false
675+ }
676+
677+ fn derive_public_key < C : Verification > (
678+ & self ,
679+ secp : & Secp256k1 < C > ,
680+ ) -> Result < bitcoin:: PublicKey , ConversionError > {
681+ match self . wildcard {
682+ Wildcard :: Unhardened | Wildcard :: Hardened => Err ( ConversionError :: Wildcard ) ,
683+ Wildcard :: None => match self . xkey . derive_pub ( secp, & self . derivation_path . as_ref ( ) ) {
684+ Ok ( xpub) => Ok ( bitcoin:: PublicKey :: new ( xpub. public_key ) ) ,
685+ Err ( bip32:: Error :: CannotDeriveFromHardenedKey ) => {
686+ Err ( ConversionError :: HardenedChild )
687+ }
688+ Err ( e) => unreachable ! ( "cryptographically unreachable: {}" , e) ,
689+ } ,
690+ }
691+ }
692+ }
693+
575694impl DescriptorPublicKey {
576695 /// The fingerprint of the master key associated with this key, `0x00000000` if none.
577696 pub fn master_fingerprint ( & self ) -> bip32:: Fingerprint {
578697 match * self {
579- DescriptorPublicKey :: XPub ( ref xpub) => {
580- if let Some ( ( fingerprint, _) ) = xpub. origin {
581- fingerprint
582- } else {
583- xpub. xkey . fingerprint ( )
584- }
585- }
698+ DescriptorPublicKey :: XPub ( ref xpub) => xpub. master_fingerprint ( ) ,
586699 DescriptorPublicKey :: MultiXPub ( ref xpub) => {
587700 if let Some ( ( fingerprint, _) ) = xpub. origin {
588701 fingerprint
@@ -620,14 +733,7 @@ impl DescriptorPublicKey {
620733 /// For multipath extended keys, this returns `None`.
621734 pub fn full_derivation_path ( & self ) -> Option < bip32:: DerivationPath > {
622735 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- }
736+ DescriptorPublicKey :: XPub ( ref xpub) => xpub. full_derivation_path ( ) ,
631737 DescriptorPublicKey :: Single ( ref single) => {
632738 Some ( if let Some ( ( _, ref path) ) = single. origin {
633739 path. clone ( )
@@ -649,7 +755,7 @@ impl DescriptorPublicKey {
649755 pub fn has_wildcard ( & self ) -> bool {
650756 match * self {
651757 DescriptorPublicKey :: Single ( ..) => false ,
652- DescriptorPublicKey :: XPub ( ref xpub) => xpub. wildcard != Wildcard :: None ,
758+ DescriptorPublicKey :: XPub ( ref xpub) => xpub. has_wildcard ( ) ,
653759 DescriptorPublicKey :: MultiXPub ( ref xpub) => xpub. wildcard != Wildcard :: None ,
654760 }
655761 }
@@ -673,40 +779,19 @@ impl DescriptorPublicKey {
673779 ///
674780 /// - If `index` is hardened.
675781 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" ) )
782+ match self {
783+ DescriptorPublicKey :: Single ( _) => Ok ( DefiniteDescriptorKey :: new ( self )
784+ . expect ( "The key should not contain any wildcards at this point" ) ) ,
785+ DescriptorPublicKey :: XPub ( xpub) => xpub. at_derivation_index ( index) ,
786+ DescriptorPublicKey :: MultiXPub ( _) => Err ( ConversionError :: MultiKey ) ,
787+ }
704788 }
705789
706790 /// Whether or not this key has multiple derivation paths.
707791 pub fn is_multipath ( & self ) -> bool {
708- match * self {
709- DescriptorPublicKey :: Single ( ..) | DescriptorPublicKey :: XPub ( ..) => false ,
792+ match self {
793+ DescriptorPublicKey :: Single ( ..) => false ,
794+ DescriptorPublicKey :: XPub ( xpub) => xpub. is_multipath ( ) ,
710795 DescriptorPublicKey :: MultiXPub ( _) => true ,
711796 }
712797 }
@@ -1083,18 +1168,7 @@ impl DefiniteDescriptorKey {
10831168 SinglePubKey :: FullKey ( pk) => Ok ( pk) ,
10841169 SinglePubKey :: XOnly ( xpk) => Ok ( xpk. to_public_key ( ) ) ,
10851170 } ,
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- } ,
1171+ DescriptorPublicKey :: XPub ( ref xpk) => xpk. derive_public_key ( secp) ,
10981172 DescriptorPublicKey :: MultiXPub ( _) => {
10991173 unreachable ! ( "A definite key cannot contain a multipath key." )
11001174 }
0 commit comments