Skip to content

Commit e619be4

Browse files
committed
Define a new type for derived DescriptorPublicKeys
1 parent d8cc633 commit e619be4

File tree

2 files changed

+92
-18
lines changed

2 files changed

+92
-18
lines changed

src/descriptor/key.rs

+80-6
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ use std::{error, fmt, str::FromStr};
22

33
use bitcoin::{
44
self,
5-
hashes::Hash,
5+
hashes::{hash160, Hash},
66
hashes::{hex::FromHex, HashEngine},
7-
secp256k1,
8-
secp256k1::{Secp256k1, Signing},
7+
secp256k1::{Secp256k1, Signing, Verification},
98
util::bip32,
109
XOnlyPublicKey, XpubIdentifier,
1110
};
@@ -58,6 +57,15 @@ pub enum DescriptorSecretKey {
5857
XPrv(DescriptorXKey<bip32::ExtendedPrivKey>),
5958
}
6059

60+
/// A derived [`DescriptorPublicKey`]
61+
///
62+
/// Derived keys are guaranteed to never contain wildcards
63+
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
64+
pub struct DerivedDescriptorKey {
65+
key: DescriptorPublicKey,
66+
index: u32,
67+
}
68+
6169
impl fmt::Display for DescriptorSecretKey {
6270
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6371
match self {
@@ -438,7 +446,7 @@ impl DescriptorPublicKey {
438446
/// If this public key has a wildcard, replace it by the given index
439447
///
440448
/// Panics if given an index ≥ 2^31
441-
pub fn derive(mut self, index: u32) -> DescriptorPublicKey {
449+
pub fn derive(mut self, index: u32) -> DerivedDescriptorKey {
442450
if let DescriptorPublicKey::XPub(mut xpub) = self {
443451
match xpub.wildcard {
444452
Wildcard::None => {}
@@ -456,7 +464,9 @@ impl DescriptorPublicKey {
456464
xpub.wildcard = Wildcard::None;
457465
self = DescriptorPublicKey::XPub(xpub);
458466
}
459-
self
467+
468+
DerivedDescriptorKey::new(self, index)
469+
.expect("The key should not contain any wildcards at this point")
460470
}
461471

462472
/// Computes the public key corresponding to this descriptor key.
@@ -471,7 +481,7 @@ impl DescriptorPublicKey {
471481
/// to avoid hardened derivation steps, start from a `DescriptorSecretKey`
472482
/// and call `as_public`, or call `TranslatePk2::translate_pk2` with
473483
/// some function which has access to secret key data.
474-
pub fn derive_public_key<C: secp256k1::Verification>(
484+
pub fn derive_public_key<C: Verification>(
475485
&self,
476486
secp: &Secp256k1<C>,
477487
) -> Result<bitcoin::PublicKey, ConversionError> {
@@ -717,6 +727,70 @@ impl MiniscriptKey for DescriptorPublicKey {
717727
}
718728
}
719729

730+
impl DerivedDescriptorKey {
731+
/// Computes the raw [`bitcoin::PublicKey`] for this descriptor key.
732+
///
733+
/// Will return an error if the key has any hardened derivation steps
734+
/// in its path, but unlike [`DescriptorPublicKey::derive_public_key`]
735+
/// this won't error in case of wildcards, because derived keys are
736+
/// guaranteed to never contain one.
737+
pub fn derive_public_key<C: Verification>(
738+
&self,
739+
secp: &Secp256k1<C>,
740+
) -> Result<bitcoin::PublicKey, ConversionError> {
741+
self.key.derive_public_key(secp)
742+
}
743+
744+
/// Return the derivation index of this key
745+
pub fn get_index(&self) -> u32 {
746+
self.index
747+
}
748+
749+
/// Construct an instance from a descriptor key and a derivation index
750+
///
751+
/// Returns `None` if the key contains a wildcard
752+
fn new(key: DescriptorPublicKey, index: u32) -> Option<Self> {
753+
match key {
754+
DescriptorPublicKey::XPub(ref xpk) if xpk.wildcard != Wildcard::None => None,
755+
k => Some(DerivedDescriptorKey { key: k, index }),
756+
}
757+
}
758+
}
759+
760+
impl fmt::Display for DerivedDescriptorKey {
761+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
762+
self.key.fmt(f)
763+
}
764+
}
765+
766+
impl MiniscriptKey for DerivedDescriptorKey {
767+
// This allows us to be able to derive public keys even for PkH s
768+
type Hash = Self;
769+
770+
fn is_uncompressed(&self) -> bool {
771+
self.key.is_uncompressed()
772+
}
773+
774+
fn is_x_only_key(&self) -> bool {
775+
self.key.is_x_only_key()
776+
}
777+
778+
fn to_pubkeyhash(&self) -> Self {
779+
self.clone()
780+
}
781+
}
782+
783+
impl ToPublicKey for DerivedDescriptorKey {
784+
fn to_public_key(&self) -> bitcoin::PublicKey {
785+
let secp = Secp256k1::verification_only();
786+
self.key.derive_public_key(&secp).unwrap()
787+
}
788+
789+
fn hash_to_hash160(hash: &Self) -> hash160::Hash {
790+
hash.to_public_key().to_pubkeyhash()
791+
}
792+
}
793+
720794
#[cfg(test)]
721795
mod test {
722796
use super::{DescriptorKeyParseError, DescriptorPublicKey, DescriptorSecretKey};

src/descriptor/mod.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@ mod checksum;
6161
mod key;
6262

6363
pub use self::key::{
64-
ConversionError, DescriptorKeyParseError, DescriptorPublicKey, DescriptorSecretKey,
65-
DescriptorSinglePriv, DescriptorSinglePub, DescriptorXKey, InnerXKey, SinglePubKey, Wildcard,
64+
ConversionError, DerivedDescriptorKey, DescriptorKeyParseError, DescriptorPublicKey,
65+
DescriptorSecretKey, DescriptorSinglePriv, DescriptorSinglePub, DescriptorXKey, InnerXKey,
66+
SinglePubKey, Wildcard,
6667
};
6768

6869
/// Alias type for a map of public key to secret key
@@ -653,7 +654,7 @@ impl Descriptor<DescriptorPublicKey> {
653654
///
654655
/// In most cases, you would want to use [`Self::derived_descriptor`] directly to obtain
655656
/// a [`Descriptor<bitcoin::PublicKey>`]
656-
pub fn derive(&self, index: u32) -> Descriptor<DescriptorPublicKey> {
657+
pub fn derive(&self, index: u32) -> Descriptor<DerivedDescriptorKey> {
657658
self.translate_pk2_infallible(|pk| pk.clone().derive(index))
658659
}
659660

@@ -842,7 +843,7 @@ mod tests {
842843
use std::cmp;
843844
use std::collections::HashMap;
844845
use std::str::FromStr;
845-
use {Descriptor, DummyKey, Error, Miniscript, Satisfier, TranslatePk2};
846+
use {Descriptor, DummyKey, Error, Miniscript, Satisfier};
846847

847848
#[cfg(feature = "compiler")]
848849
use policy;
@@ -1586,18 +1587,17 @@ mod tests {
15861587
let index = 5;
15871588

15881589
// Parse descriptor
1589-
let mut desc_one = Descriptor::<DescriptorPublicKey>::from_str(raw_desc_one).unwrap();
1590-
let mut desc_two = Descriptor::<DescriptorPublicKey>::from_str(raw_desc_two).unwrap();
1590+
let desc_one = Descriptor::<DescriptorPublicKey>::from_str(raw_desc_one).unwrap();
1591+
let desc_two = Descriptor::<DescriptorPublicKey>::from_str(raw_desc_two).unwrap();
15911592

15921593
// Same string formatting
15931594
assert_eq!(desc_one.to_string(), raw_desc_one);
15941595
assert_eq!(desc_two.to_string(), raw_desc_two);
15951596

1596-
// Derive a child if the descriptor is ranged
1597-
if raw_desc_one.contains("*") && raw_desc_two.contains("*") {
1598-
desc_one = desc_one.derive(index);
1599-
desc_two = desc_two.derive(index);
1600-
}
1597+
// Derive a child in case the descriptor is ranged. If it's not this won't have any
1598+
// effect
1599+
let desc_one = desc_one.derive(index);
1600+
let desc_two = desc_two.derive(index);
16011601

16021602
// Same address
16031603
let addr_one = desc_one
@@ -1693,7 +1693,7 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
16931693
res_descriptor_str.parse().unwrap();
16941694
let res_descriptor = Descriptor::new_sh(res_policy.compile().unwrap()).unwrap();
16951695

1696-
assert_eq!(res_descriptor, derived_descriptor);
1696+
assert_eq!(res_descriptor.to_string(), derived_descriptor.to_string());
16971697
}
16981698

16991699
#[test]

0 commit comments

Comments
 (0)