@@ -61,8 +61,10 @@ impl fmt::Display for DescriptorSecretKey {
6161 maybe_fmt_master_id ( f, & xprv. origin ) ?;
6262 xprv. xkey . fmt ( f) ?;
6363 fmt_derivation_path ( f, & xprv. derivation_path ) ?;
64- if xprv. is_wildcard {
65- write ! ( f, "/*" ) ?;
64+ match xprv. is_wildcard {
65+ Wildcard :: None => { }
66+ Wildcard :: Unhardened => write ! ( f, "/*" ) ?,
67+ Wildcard :: Hardened => write ! ( f, "/*h" ) ?,
6668 }
6769 Ok ( ( ) )
6870 }
@@ -102,6 +104,17 @@ impl InnerXKey for bip32::ExtendedPrivKey {
102104 }
103105}
104106
107+ /// Whether a descriptor has a wildcard in it
108+ #[ derive( Copy , Clone , Debug , Eq , PartialEq , Ord , PartialOrd , Hash ) ]
109+ pub enum Wildcard {
110+ /// No wildcard
111+ None ,
112+ /// Unhardened wildcard, e.g. *
113+ Unhardened ,
114+ /// Unhardened wildcard, e.g. *h
115+ Hardened ,
116+ }
117+
105118/// Instance of an extended key with origin and derivation path
106119#[ derive( Debug , Eq , PartialEq , Clone , Ord , PartialOrd , Hash ) ]
107120pub struct DescriptorXKey < K : InnerXKey > {
@@ -112,7 +125,7 @@ pub struct DescriptorXKey<K: InnerXKey> {
112125 /// The derivation path
113126 pub derivation_path : bip32:: DerivationPath ,
114127 /// Whether the descriptor is wildcard
115- pub is_wildcard : bool ,
128+ pub is_wildcard : Wildcard ,
116129}
117130
118131impl DescriptorSinglePriv {
@@ -206,8 +219,10 @@ impl fmt::Display for DescriptorPublicKey {
206219 maybe_fmt_master_id ( f, & xpub. origin ) ?;
207220 xpub. xkey . fmt ( f) ?;
208221 fmt_derivation_path ( f, & xpub. derivation_path ) ?;
209- if xpub. is_wildcard {
210- write ! ( f, "/*" ) ?;
222+ match xpub. is_wildcard {
223+ Wildcard :: None => { }
224+ Wildcard :: Unhardened => write ! ( f, "/*" ) ?,
225+ Wildcard :: Hardened => write ! ( f, "/*h" ) ?,
211226 }
212227 Ok ( ( ) )
213228 }
@@ -307,25 +322,26 @@ impl FromStr for DescriptorPublicKey {
307322impl DescriptorPublicKey {
308323 /// Derives the specified child key if self is a wildcard xpub. Otherwise returns self.
309324 ///
310- /// Panics if given a hardened child number
311- pub fn derive ( self , child_number : bip32:: ChildNumber ) -> DescriptorPublicKey {
312- debug_assert ! ( child_number. is_normal( ) ) ;
313-
314- match self {
315- DescriptorPublicKey :: SinglePub ( _) => self ,
316- DescriptorPublicKey :: XPub ( xpub) => {
317- if xpub. is_wildcard {
318- DescriptorPublicKey :: XPub ( DescriptorXKey {
319- origin : xpub. origin ,
320- xkey : xpub. xkey ,
321- derivation_path : xpub. derivation_path . into_child ( child_number) ,
322- is_wildcard : false ,
323- } )
324- } else {
325- DescriptorPublicKey :: XPub ( xpub)
325+ /// Panics if given a child number ≥ 2^31
326+ pub fn derive ( mut self , index : u32 ) -> DescriptorPublicKey {
327+ if let DescriptorPublicKey :: XPub ( mut xpub) = self {
328+ match xpub. is_wildcard {
329+ Wildcard :: None => { }
330+ Wildcard :: Unhardened => {
331+ xpub. derivation_path = xpub
332+ . derivation_path
333+ . into_child ( bip32:: ChildNumber :: from_normal_idx ( index) . unwrap ( ) )
334+ }
335+ Wildcard :: Hardened => {
336+ xpub. derivation_path = xpub
337+ . derivation_path
338+ . into_child ( bip32:: ChildNumber :: from_hardened_idx ( index) . unwrap ( ) )
326339 }
327340 }
341+ xpub. is_wildcard = Wildcard :: None ;
342+ self = DescriptorPublicKey :: XPub ( xpub) ;
328343 }
344+ self
329345 }
330346}
331347
@@ -417,25 +433,24 @@ impl<K: InnerXKey> DescriptorXKey<K> {
417433 /// Parse an extended key concatenated to a derivation path.
418434 fn parse_xkey_deriv (
419435 key_deriv : & str ,
420- ) -> Result < ( K , bip32:: DerivationPath , bool ) , DescriptorKeyParseError > {
436+ ) -> Result < ( K , bip32:: DerivationPath , Wildcard ) , DescriptorKeyParseError > {
421437 let mut key_deriv = key_deriv. split ( '/' ) ;
422438 let xkey_str = key_deriv. next ( ) . ok_or ( DescriptorKeyParseError (
423439 "No key found after origin description" ,
424440 ) ) ?;
425441 let xkey = K :: from_str ( xkey_str)
426442 . map_err ( |_| DescriptorKeyParseError ( "Error while parsing xkey." ) ) ?;
427443
428- let mut is_wildcard = false ;
444+ let mut is_wildcard = Wildcard :: None ;
429445 let derivation_path = key_deriv
430446 . filter_map ( |p| {
431- if ! is_wildcard && p == "*" {
432- is_wildcard = true ;
447+ if is_wildcard == Wildcard :: None && p == "*" {
448+ is_wildcard = Wildcard :: Unhardened ;
433449 None
434- } else if !is_wildcard && p == "*'" {
435- Some ( Err ( DescriptorKeyParseError (
436- "Hardened derivation is currently not supported." ,
437- ) ) )
438- } else if is_wildcard {
450+ } else if is_wildcard == Wildcard :: None && ( p == "*'" || p == "*h" ) {
451+ is_wildcard = Wildcard :: Hardened ;
452+ None
453+ } else if is_wildcard != Wildcard :: None {
439454 Some ( Err ( DescriptorKeyParseError (
440455 "'*' may only appear as last element in a derivation path." ,
441456 ) ) )
@@ -507,14 +522,15 @@ impl<K: InnerXKey> DescriptorXKey<K> {
507522 ) ,
508523 } ;
509524
510- let path_excluding_wildcard = if self . is_wildcard && path. as_ref ( ) . len ( ) > 0 {
511- path. into_iter ( )
512- . take ( path. as_ref ( ) . len ( ) - 1 )
513- . cloned ( )
514- . collect ( )
515- } else {
516- path. clone ( )
517- } ;
525+ let path_excluding_wildcard =
526+ if self . is_wildcard != Wildcard :: None && path. as_ref ( ) . len ( ) > 0 {
527+ path. into_iter ( )
528+ . take ( path. as_ref ( ) . len ( ) - 1 )
529+ . cloned ( )
530+ . collect ( )
531+ } else {
532+ path. clone ( )
533+ } ;
518534
519535 if & compare_fingerprint == fingerprint
520536 && compare_path
@@ -542,16 +558,16 @@ impl MiniscriptKey for DescriptorPublicKey {
542558pub struct DescriptorPublicKeyCtx < ' secp , C : ' secp + secp256k1:: Verification > {
543559 /// The underlying secp context
544560 secp_ctx : & ' secp secp256k1:: Secp256k1 < C > ,
545- /// The child_number in case the descriptor is wildcard
546- /// If the DescriptorPublicKey is not wildcard this field is not used.
547- child_number : bip32 :: ChildNumber ,
561+ /// The index in case the descriptor is ranged
562+ /// If the DescriptorPublicKey is unranged this field is not used.
563+ index : u32 ,
548564}
549565
550566impl < ' secp , C : secp256k1:: Verification > Clone for DescriptorPublicKeyCtx < ' secp , C > {
551567 fn clone ( & self ) -> Self {
552568 Self {
553569 secp_ctx : & self . secp_ctx ,
554- child_number : self . child_number . clone ( ) ,
570+ index : self . index ,
555571 }
556572 }
557573}
@@ -560,10 +576,10 @@ impl<'secp, C: secp256k1::Verification> Copy for DescriptorPublicKeyCtx<'secp, C
560576
561577impl < ' secp , C : secp256k1:: Verification > DescriptorPublicKeyCtx < ' secp , C > {
562578 /// Create a new context
563- pub fn new ( secp_ctx : & ' secp secp256k1:: Secp256k1 < C > , child_number : bip32 :: ChildNumber ) -> Self {
579+ pub fn new ( secp_ctx : & ' secp secp256k1:: Secp256k1 < C > , index : u32 ) -> Self {
564580 Self {
565581 secp_ctx : secp_ctx,
566- child_number : child_number ,
582+ index : index ,
567583 }
568584 }
569585}
@@ -572,12 +588,12 @@ impl<'secp, C: secp256k1::Verification> ToPublicKey<DescriptorPublicKeyCtx<'secp
572588 for DescriptorPublicKey
573589{
574590 fn to_public_key ( & self , to_pk_ctx : DescriptorPublicKeyCtx < ' secp , C > ) -> bitcoin:: PublicKey {
575- let xpub = self . clone ( ) . derive ( to_pk_ctx. child_number ) ;
591+ let xpub = self . clone ( ) . derive ( to_pk_ctx. index ) ;
576592 match xpub {
577593 DescriptorPublicKey :: SinglePub ( ref spub) => spub. key . to_public_key ( NullCtx ) ,
578594 DescriptorPublicKey :: XPub ( ref xpub) => {
579595 // derives if wildcard, otherwise returns self
580- debug_assert ! ( ! xpub. is_wildcard) ;
596+ debug_assert ! ( xpub. is_wildcard == Wildcard :: None ) ;
581597 xpub. xkey
582598 . derive_pub ( to_pk_ctx. secp_ctx , & xpub. derivation_path )
583599 . expect ( "Shouldn't fail, only normal derivations" )
@@ -613,15 +629,6 @@ mod test {
613629 ) )
614630 ) ;
615631
616- // And even if they they claim it for the wildcard!
617- let desc = "[78412e3a/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/42/*'" ;
618- assert_eq ! (
619- DescriptorPublicKey :: from_str( desc) ,
620- Err ( DescriptorKeyParseError (
621- "Hardened derivation is currently not supported."
622- ) )
623- ) ;
624-
625632 // And ones with misplaced wildcard
626633 let desc = "[78412e3a/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*/44" ;
627634 assert_eq ! (
0 commit comments