Skip to content

Commit e37a3cb

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

File tree

2 files changed

+95
-18
lines changed

2 files changed

+95
-18
lines changed

src/descriptor/key.rs

Lines changed: 83 additions & 6 deletions
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,8 @@ impl DescriptorPublicKey {
456464
xpub.wildcard = Wildcard::None;
457465
self = DescriptorPublicKey::XPub(xpub);
458466
}
459-
self
467+
468+
DerivedDescriptorKey::new(self, index)
460469
}
461470

462471
/// Computes the public key corresponding to this descriptor key.
@@ -471,7 +480,7 @@ impl DescriptorPublicKey {
471480
/// to avoid hardened derivation steps, start from a `DescriptorSecretKey`
472481
/// and call `as_public`, or call `TranslatePk2::translate_pk2` with
473482
/// some function which has access to secret key data.
474-
pub fn derive_public_key<C: secp256k1::Verification>(
483+
pub fn derive_public_key<C: Verification>(
475484
&self,
476485
secp: &Secp256k1<C>,
477486
) -> Result<bitcoin::PublicKey, ConversionError> {
@@ -717,6 +726,74 @@ impl MiniscriptKey for DescriptorPublicKey {
717726
}
718727
}
719728

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

src/descriptor/mod.rs

Lines changed: 12 additions & 12 deletions
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)