@@ -18,13 +18,15 @@ use crate::prelude::*;
18
18
use crate :: serde:: { Deserialize , Deserializer , Serialize , Serializer } ;
19
19
use crate :: { hash256, MiniscriptKey , ToPublicKey } ;
20
20
21
+ type DescriptorExtendedPublicKey = DescriptorXKey < bip32:: ExtendedPubKey > ;
22
+
21
23
/// The descriptor pubkey, either a single pubkey or an xpub.
22
24
#[ derive( Debug , Eq , PartialEq , Clone , Ord , PartialOrd , Hash ) ]
23
25
pub enum DescriptorPublicKey {
24
26
/// Single public key.
25
27
Single ( SinglePub ) ,
26
28
/// Extended public key (xpub).
27
- XPub ( DescriptorXKey < bip32 :: ExtendedPubKey > ) ,
29
+ XPub ( DescriptorExtendedPublicKey ) ,
28
30
/// Multiple extended public keys.
29
31
MultiXPub ( DescriptorMultiXKey < bip32:: ExtendedPubKey > ) ,
30
32
}
@@ -283,6 +285,20 @@ impl error::Error for DescriptorKeyParseError {
283
285
}
284
286
}
285
287
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
+
286
302
impl fmt:: Display for DescriptorPublicKey {
287
303
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
288
304
match * self {
@@ -294,17 +310,7 @@ impl fmt::Display for DescriptorPublicKey {
294
310
} ?;
295
311
Ok ( ( ) )
296
312
}
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) ,
308
314
DescriptorPublicKey :: MultiXPub ( ref xpub) => {
309
315
maybe_fmt_master_id ( f, & xpub. origin ) ?;
310
316
xpub. xkey . fmt ( f) ?;
@@ -432,6 +438,30 @@ fn fmt_derivation_paths(f: &mut fmt::Formatter, paths: &[bip32::DerivationPath])
432
438
Ok ( ( ) )
433
439
}
434
440
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
+
435
465
impl FromStr for DescriptorPublicKey {
436
466
type Err = DescriptorKeyParseError ;
437
467
@@ -456,12 +486,7 @@ impl FromStr for DescriptorPublicKey {
456
486
wildcard,
457
487
} ) )
458
488
} 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 )
465
490
}
466
491
} else {
467
492
let key = match key_part. len ( ) {
@@ -503,13 +528,16 @@ pub enum ConversionError {
503
528
HardenedChild ,
504
529
/// Attempted to convert a key with multiple derivation paths to a bitcoin public key
505
530
MultiKey ,
531
+ /// Attempted to convert a key with a wildcard to a bitcoin public key
532
+ Wildcard ,
506
533
}
507
534
508
535
impl fmt:: Display for ConversionError {
509
536
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
510
537
f. write_str ( match * self {
511
538
ConversionError :: HardenedChild => "hardened child step in bip32 path" ,
512
539
ConversionError :: MultiKey => "multiple existing keys" ,
540
+ ConversionError :: Wildcard => "wildcard in bip32 path" ,
513
541
} )
514
542
}
515
543
}
@@ -520,7 +548,7 @@ impl error::Error for ConversionError {
520
548
use self :: ConversionError :: * ;
521
549
522
550
match self {
523
- HardenedChild | MultiKey => None ,
551
+ HardenedChild | MultiKey | Wildcard => None ,
524
552
}
525
553
}
526
554
}
@@ -572,17 +600,102 @@ pub trait DescriptorKey : Clone + fmt::Debug + fmt::Display + Eq + FromStr + std
572
600
secp : & Secp256k1 < C > ,
573
601
) -> Result < bitcoin:: PublicKey , ConversionError > ;
574
602
}
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
+
575
694
impl DescriptorPublicKey {
576
695
/// The fingerprint of the master key associated with this key, `0x00000000` if none.
577
696
pub fn master_fingerprint ( & self ) -> bip32:: Fingerprint {
578
697
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 ( ) ,
586
699
DescriptorPublicKey :: MultiXPub ( ref xpub) => {
587
700
if let Some ( ( fingerprint, _) ) = xpub. origin {
588
701
fingerprint
@@ -620,14 +733,7 @@ impl DescriptorPublicKey {
620
733
/// For multipath extended keys, this returns `None`.
621
734
pub fn full_derivation_path ( & self ) -> Option < bip32:: DerivationPath > {
622
735
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 ( ) ,
631
737
DescriptorPublicKey :: Single ( ref single) => {
632
738
Some ( if let Some ( ( _, ref path) ) = single. origin {
633
739
path. clone ( )
@@ -649,7 +755,7 @@ impl DescriptorPublicKey {
649
755
pub fn has_wildcard ( & self ) -> bool {
650
756
match * self {
651
757
DescriptorPublicKey :: Single ( ..) => false ,
652
- DescriptorPublicKey :: XPub ( ref xpub) => xpub. wildcard != Wildcard :: None ,
758
+ DescriptorPublicKey :: XPub ( ref xpub) => xpub. has_wildcard ( ) ,
653
759
DescriptorPublicKey :: MultiXPub ( ref xpub) => xpub. wildcard != Wildcard :: None ,
654
760
}
655
761
}
@@ -673,40 +779,19 @@ impl DescriptorPublicKey {
673
779
///
674
780
/// - If `index` is hardened.
675
781
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
+ }
704
788
}
705
789
706
790
/// Whether or not this key has multiple derivation paths.
707
791
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 ( ) ,
710
795
DescriptorPublicKey :: MultiXPub ( _) => true ,
711
796
}
712
797
}
@@ -1083,18 +1168,7 @@ impl DefiniteDescriptorKey {
1083
1168
SinglePubKey :: FullKey ( pk) => Ok ( pk) ,
1084
1169
SinglePubKey :: XOnly ( xpk) => Ok ( xpk. to_public_key ( ) ) ,
1085
1170
} ,
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) ,
1098
1172
DescriptorPublicKey :: MultiXPub ( _) => {
1099
1173
unreachable ! ( "A definite key cannot contain a multipath key." )
1100
1174
}
0 commit comments