@@ -2,15 +2,13 @@ use std::{error, fmt, str::FromStr};
2
2
3
3
use bitcoin:: {
4
4
self ,
5
- hashes:: { hash160 , hex:: FromHex } ,
5
+ hashes:: hex:: FromHex ,
6
6
secp256k1,
7
7
secp256k1:: { Secp256k1 , Signing } ,
8
8
util:: bip32,
9
9
} ;
10
10
11
11
use MiniscriptKey ;
12
- use NullCtx ;
13
- use ToPublicKey ;
14
12
15
13
/// The MiniscriptKey corresponding to Descriptors. This can
16
14
/// either be Single public key or a Xpub
@@ -319,10 +317,35 @@ impl FromStr for DescriptorPublicKey {
319
317
}
320
318
}
321
319
320
+ /// Descriptor key conversion error
321
+ #[ derive( Debug , PartialEq , Clone , Copy ) ]
322
+ pub enum ConversionError {
323
+ /// Attempted to convert a key with a wildcard to a bitcoin public key
324
+ Wildcard ,
325
+ /// Attempted to convert a key with hardened derivations to a bitcoin public key
326
+ HardenedChild ,
327
+ /// Attempted to convert a key with a hardened wildcard to a bitcoin public key
328
+ HardenedWildcard ,
329
+ }
330
+
331
+ impl fmt:: Display for ConversionError {
332
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
333
+ f. write_str ( match * self {
334
+ ConversionError :: Wildcard => "uninstantiated wildcard in bip32 path" ,
335
+ ConversionError :: HardenedChild => "hardened child step in bip32 path" ,
336
+ ConversionError :: HardenedWildcard => {
337
+ "hardened and uninstantiated wildcard in bip32 path"
338
+ }
339
+ } )
340
+ }
341
+ }
342
+
343
+ impl error:: Error for ConversionError { }
344
+
322
345
impl DescriptorPublicKey {
323
- /// Derives the specified child key if self is a wildcard xpub. Otherwise returns self.
346
+ /// If this public key has a wildcard, replace it by the given index
324
347
///
325
- /// Panics if given a child number ≥ 2^31
348
+ /// Panics if given an index ≥ 2^31
326
349
pub fn derive ( mut self , index : u32 ) -> DescriptorPublicKey {
327
350
if let DescriptorPublicKey :: XPub ( mut xpub) = self {
328
351
match xpub. is_wildcard {
@@ -343,6 +366,35 @@ impl DescriptorPublicKey {
343
366
}
344
367
self
345
368
}
369
+
370
+ /// Computes the public key corresponding to this descriptor key
371
+ ///
372
+ /// Will return an error if the descriptor key has any hardened
373
+ /// derivation steps in its path, or if the key has any wildcards.
374
+ ///
375
+ /// To ensure there are no wildcards, call `.derive(0)` or similar;
376
+ /// to avoid hardened derivation steps, start from a `DescriptorSecretKey`
377
+ /// and call `as_public`, or call `TranslatePk2::translate_pk2` with
378
+ /// some function which has access to secret key data.
379
+ pub fn derive_public_key < C : secp256k1:: Verification > (
380
+ & self ,
381
+ secp : & Secp256k1 < C > ,
382
+ ) -> Result < bitcoin:: PublicKey , ConversionError > {
383
+ match * self {
384
+ DescriptorPublicKey :: SinglePub ( ref pk) => Ok ( pk. key ) ,
385
+ DescriptorPublicKey :: XPub ( ref xpk) => match xpk. is_wildcard {
386
+ Wildcard :: Unhardened => Err ( ConversionError :: Wildcard ) ,
387
+ Wildcard :: Hardened => Err ( ConversionError :: HardenedWildcard ) ,
388
+ Wildcard :: None => match xpk. xkey . derive_pub ( secp, & xpk. derivation_path . as_ref ( ) ) {
389
+ Ok ( xpub) => Ok ( xpub. public_key ) ,
390
+ Err ( bip32:: Error :: CannotDeriveFromHardenedKey ) => {
391
+ Err ( ConversionError :: HardenedChild )
392
+ }
393
+ Err ( e) => unreachable ! ( "cryptographically unreachable: {}" , e) ,
394
+ } ,
395
+ } ,
396
+ }
397
+ }
346
398
}
347
399
348
400
impl FromStr for DescriptorSecretKey {
@@ -584,32 +636,6 @@ impl<'secp, C: secp256k1::Verification> DescriptorPublicKeyCtx<'secp, C> {
584
636
}
585
637
}
586
638
587
- impl < ' secp , C : secp256k1:: Verification > ToPublicKey < DescriptorPublicKeyCtx < ' secp , C > >
588
- for DescriptorPublicKey
589
- {
590
- fn to_public_key ( & self , to_pk_ctx : DescriptorPublicKeyCtx < ' secp , C > ) -> bitcoin:: PublicKey {
591
- let xpub = self . clone ( ) . derive ( to_pk_ctx. index ) ;
592
- match xpub {
593
- DescriptorPublicKey :: SinglePub ( ref spub) => spub. key . to_public_key ( NullCtx ) ,
594
- DescriptorPublicKey :: XPub ( ref xpub) => {
595
- // derives if wildcard, otherwise returns self
596
- debug_assert ! ( xpub. is_wildcard == Wildcard :: None ) ;
597
- xpub. xkey
598
- . derive_pub ( to_pk_ctx. secp_ctx , & xpub. derivation_path )
599
- . expect ( "Shouldn't fail, only normal derivations" )
600
- . public_key
601
- }
602
- }
603
- }
604
-
605
- fn hash_to_hash160 (
606
- hash : & Self :: Hash ,
607
- to_pk_ctx : DescriptorPublicKeyCtx < ' secp , C > ,
608
- ) -> hash160:: Hash {
609
- hash. to_public_key ( to_pk_ctx) . to_pubkeyhash ( )
610
- }
611
- }
612
-
613
639
#[ cfg( test) ]
614
640
mod test {
615
641
use super :: { DescriptorKeyParseError , DescriptorPublicKey , DescriptorSecretKey } ;
0 commit comments