@@ -61,8 +61,10 @@ impl fmt::Display for DescriptorSecretKey {
61
61
maybe_fmt_master_id ( f, & xprv. origin ) ?;
62
62
xprv. xkey . fmt ( f) ?;
63
63
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" ) ?,
66
68
}
67
69
Ok ( ( ) )
68
70
}
@@ -102,6 +104,17 @@ impl InnerXKey for bip32::ExtendedPrivKey {
102
104
}
103
105
}
104
106
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
+
105
118
/// Instance of an extended key with origin and derivation path
106
119
#[ derive( Debug , Eq , PartialEq , Clone , Ord , PartialOrd , Hash ) ]
107
120
pub struct DescriptorXKey < K : InnerXKey > {
@@ -112,7 +125,7 @@ pub struct DescriptorXKey<K: InnerXKey> {
112
125
/// The derivation path
113
126
pub derivation_path : bip32:: DerivationPath ,
114
127
/// Whether the descriptor is wildcard
115
- pub is_wildcard : bool ,
128
+ pub is_wildcard : Wildcard ,
116
129
}
117
130
118
131
impl DescriptorSinglePriv {
@@ -206,8 +219,10 @@ impl fmt::Display for DescriptorPublicKey {
206
219
maybe_fmt_master_id ( f, & xpub. origin ) ?;
207
220
xpub. xkey . fmt ( f) ?;
208
221
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" ) ?,
211
226
}
212
227
Ok ( ( ) )
213
228
}
@@ -307,25 +322,26 @@ impl FromStr for DescriptorPublicKey {
307
322
impl DescriptorPublicKey {
308
323
/// Derives the specified child key if self is a wildcard xpub. Otherwise returns self.
309
324
///
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 ( ) )
326
339
}
327
340
}
341
+ xpub. is_wildcard = Wildcard :: None ;
342
+ self = DescriptorPublicKey :: XPub ( xpub) ;
328
343
}
344
+ self
329
345
}
330
346
}
331
347
@@ -417,25 +433,24 @@ impl<K: InnerXKey> DescriptorXKey<K> {
417
433
/// Parse an extended key concatenated to a derivation path.
418
434
fn parse_xkey_deriv (
419
435
key_deriv : & str ,
420
- ) -> Result < ( K , bip32:: DerivationPath , bool ) , DescriptorKeyParseError > {
436
+ ) -> Result < ( K , bip32:: DerivationPath , Wildcard ) , DescriptorKeyParseError > {
421
437
let mut key_deriv = key_deriv. split ( '/' ) ;
422
438
let xkey_str = key_deriv. next ( ) . ok_or ( DescriptorKeyParseError (
423
439
"No key found after origin description" ,
424
440
) ) ?;
425
441
let xkey = K :: from_str ( xkey_str)
426
442
. map_err ( |_| DescriptorKeyParseError ( "Error while parsing xkey." ) ) ?;
427
443
428
- let mut is_wildcard = false ;
444
+ let mut is_wildcard = Wildcard :: None ;
429
445
let derivation_path = key_deriv
430
446
. filter_map ( |p| {
431
- if ! is_wildcard && p == "*" {
432
- is_wildcard = true ;
447
+ if is_wildcard == Wildcard :: None && p == "*" {
448
+ is_wildcard = Wildcard :: Unhardened ;
433
449
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 {
439
454
Some ( Err ( DescriptorKeyParseError (
440
455
"'*' may only appear as last element in a derivation path." ,
441
456
) ) )
@@ -507,14 +522,15 @@ impl<K: InnerXKey> DescriptorXKey<K> {
507
522
) ,
508
523
} ;
509
524
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
+ } ;
518
534
519
535
if & compare_fingerprint == fingerprint
520
536
&& compare_path
@@ -542,16 +558,16 @@ impl MiniscriptKey for DescriptorPublicKey {
542
558
pub struct DescriptorPublicKeyCtx < ' secp , C : ' secp + secp256k1:: Verification > {
543
559
/// The underlying secp context
544
560
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 ,
548
564
}
549
565
550
566
impl < ' secp , C : secp256k1:: Verification > Clone for DescriptorPublicKeyCtx < ' secp , C > {
551
567
fn clone ( & self ) -> Self {
552
568
Self {
553
569
secp_ctx : & self . secp_ctx ,
554
- child_number : self . child_number . clone ( ) ,
570
+ index : self . index ,
555
571
}
556
572
}
557
573
}
@@ -560,10 +576,10 @@ impl<'secp, C: secp256k1::Verification> Copy for DescriptorPublicKeyCtx<'secp, C
560
576
561
577
impl < ' secp , C : secp256k1:: Verification > DescriptorPublicKeyCtx < ' secp , C > {
562
578
/// 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 {
564
580
Self {
565
581
secp_ctx : secp_ctx,
566
- child_number : child_number ,
582
+ index : index ,
567
583
}
568
584
}
569
585
}
@@ -572,12 +588,12 @@ impl<'secp, C: secp256k1::Verification> ToPublicKey<DescriptorPublicKeyCtx<'secp
572
588
for DescriptorPublicKey
573
589
{
574
590
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 ) ;
576
592
match xpub {
577
593
DescriptorPublicKey :: SinglePub ( ref spub) => spub. key . to_public_key ( NullCtx ) ,
578
594
DescriptorPublicKey :: XPub ( ref xpub) => {
579
595
// derives if wildcard, otherwise returns self
580
- debug_assert ! ( ! xpub. is_wildcard) ;
596
+ debug_assert ! ( xpub. is_wildcard == Wildcard :: None ) ;
581
597
xpub. xkey
582
598
. derive_pub ( to_pk_ctx. secp_ctx , & xpub. derivation_path )
583
599
. expect ( "Shouldn't fail, only normal derivations" )
@@ -613,15 +629,6 @@ mod test {
613
629
) )
614
630
) ;
615
631
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
-
625
632
// And ones with misplaced wildcard
626
633
let desc = "[78412e3a/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*/44" ;
627
634
assert_eq ! (
0 commit comments