@@ -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) ?;
@@ -503,13 +509,16 @@ pub enum ConversionError {
503
509
HardenedChild ,
504
510
/// Attempted to convert a key with multiple derivation paths to a bitcoin public key
505
511
MultiKey ,
512
+ /// Attempted to convert a key with a wildcard to a bitcoin public key
513
+ Wildcard ,
506
514
}
507
515
508
516
impl fmt:: Display for ConversionError {
509
517
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
510
518
f. write_str ( match * self {
511
519
ConversionError :: HardenedChild => "hardened child step in bip32 path" ,
512
520
ConversionError :: MultiKey => "multiple existing keys" ,
521
+ ConversionError :: Wildcard => "wildcard in bip32 path" ,
513
522
} )
514
523
}
515
524
}
@@ -520,7 +529,7 @@ impl error::Error for ConversionError {
520
529
use self :: ConversionError :: * ;
521
530
522
531
match self {
523
- HardenedChild | MultiKey => None ,
532
+ HardenedChild | MultiKey | Wildcard => None ,
524
533
}
525
534
}
526
535
}
@@ -572,17 +581,102 @@ pub trait DescriptorInnerKey {
572
581
secp : & Secp256k1 < C > ,
573
582
) -> Result < bitcoin:: PublicKey , ConversionError > ;
574
583
}
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
+
575
675
impl DescriptorPublicKey {
576
676
/// The fingerprint of the master key associated with this key, `0x00000000` if none.
577
677
pub fn master_fingerprint ( & self ) -> bip32:: Fingerprint {
578
678
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 ( ) ,
586
680
DescriptorPublicKey :: MultiXPub ( ref xpub) => {
587
681
if let Some ( ( fingerprint, _) ) = xpub. origin {
588
682
fingerprint
@@ -620,14 +714,7 @@ impl DescriptorPublicKey {
620
714
/// For multipath extended keys, this returns `None`.
621
715
pub fn full_derivation_path ( & self ) -> Option < bip32:: DerivationPath > {
622
716
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 ( ) ,
631
718
DescriptorPublicKey :: Single ( ref single) => {
632
719
Some ( if let Some ( ( _, ref path) ) = single. origin {
633
720
path. clone ( )
@@ -649,7 +736,7 @@ impl DescriptorPublicKey {
649
736
pub fn has_wildcard ( & self ) -> bool {
650
737
match * self {
651
738
DescriptorPublicKey :: Single ( ..) => false ,
652
- DescriptorPublicKey :: XPub ( ref xpub) => xpub. wildcard != Wildcard :: None ,
739
+ DescriptorPublicKey :: XPub ( ref xpub) => xpub. has_wildcard ( ) ,
653
740
DescriptorPublicKey :: MultiXPub ( ref xpub) => xpub. wildcard != Wildcard :: None ,
654
741
}
655
742
}
@@ -673,40 +760,19 @@ impl DescriptorPublicKey {
673
760
///
674
761
/// - If `index` is hardened.
675
762
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" ) )
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
+ }
704
769
}
705
770
706
771
/// Whether or not this key has multiple derivation paths.
707
772
pub 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 ( ) ,
710
776
DescriptorPublicKey :: MultiXPub ( _) => true ,
711
777
}
712
778
}
@@ -1083,18 +1149,7 @@ impl DefiniteDescriptorKey {
1083
1149
SinglePubKey :: FullKey ( pk) => Ok ( pk) ,
1084
1150
SinglePubKey :: XOnly ( xpk) => Ok ( xpk. to_public_key ( ) ) ,
1085
1151
} ,
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) ,
1098
1153
DescriptorPublicKey :: MultiXPub ( _) => {
1099
1154
unreachable ! ( "A definite key cannot contain a multipath key." )
1100
1155
}
0 commit comments