@@ -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. 
2527Single ( SinglePub ) , 
2628    /// Extended public key (xpub). 
27- XPub ( DescriptorXKey < bip32 :: ExtendedPubKey > ) , 
29+ XPub ( DescriptorExtendedPublicKey ) , 
2830    /// Multiple extended public keys. 
2931MultiXPub ( 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 {
503509HardenedChild , 
504510    /// Attempted to convert a key with multiple derivation paths to a bitcoin public key 
505511MultiKey , 
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 DescriptorKey : Clone + fmt::Debug + fmt::Display + Eq + FromStr + std
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. 
577677pub  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`. 
621715pub  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 {
649736pub  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. 
675762pub  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. 
707772pub  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