Skip to content

Commit 0ccd830

Browse files
committed
Merge commit 'c7c39f1e' into 2022-10--update-elements (PR #448)
PR 448: DerivedDescriptor unfinished business
2 parents db36800 + c7c39f1 commit 0ccd830

File tree

11 files changed

+254
-181
lines changed

11 files changed

+254
-181
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ rand = ["bitcoin/rand"]
1818
[dependencies]
1919
bitcoin = "0.28.1"
2020
elements = "0.19.0"
21-
bitcoin-miniscript = {package = "miniscript", git = "https://github.com/rust-bitcoin/rust-miniscript", rev = "f6dc945848d11e2da328acc2f02957ea35ac56fe"}
21+
bitcoin-miniscript = {package = "miniscript", git = "https://github.com/rust-bitcoin/rust-miniscript", rev = "c7c39f1e9d1b8da9e2c9318a61fb508553619e6c"}
2222

2323
[dev-dependencies]
2424
serde_json = "<=1.0.44"

examples/taproot.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use std::str::FromStr;
55

66
use bitcoin::hashes::{hash160, ripemd160, sha256};
77
use bitcoin::util::address::WitnessVersion;
8-
use bitcoin::Network;
98
use miniscript::descriptor::DescriptorType;
109
use miniscript::policy::Concrete;
1110
use miniscript::{hash256, Descriptor, Miniscript, NoExt, Tap, TranslatePk, Translator};
@@ -125,7 +124,6 @@ fn main() {
125124
assert_eq!(max_sat_wt, 273);
126125

127126
// Compute the bitcoin address and check if it matches
128-
let network = Network::Bitcoin;
129127
let addr = real_desc.address(&elements::AddressParams::ELEMENTS).unwrap();
130128
let expected_addr = elements::Address::from_str(
131129
"ert1pxx6wkfdnnx97akwws8l8xdmx5n03qftvx2t269k4sn9adm2emz0sdnytn4",

examples/xpub_descriptors.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use std::str::FromStr;
2121
use elements::Address;
2222

2323
use crate::miniscript::elements::secp256k1_zkp::{Secp256k1, Verification};
24-
use crate::miniscript::{Descriptor, DescriptorPublicKey};
24+
use crate::miniscript::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey};
2525

2626
const XPUB_1: &str = "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB";
2727
const XPUB_2: &str = "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH";
@@ -43,9 +43,9 @@ fn p2wsh<C: Verification>(secp: &Secp256k1<C>) -> Address {
4343
let s = format!("elwsh(sortedmulti(1,{},{}))", XPUB_1, XPUB_2);
4444
// let s = format!("wsh(sortedmulti(1,{},{}))", XPUB_2, XPUB_1);
4545

46-
let address = Descriptor::<DescriptorPublicKey>::from_str(&s)
46+
let address = Descriptor::<DefiniteDescriptorKey>::from_str(&s)
4747
.unwrap()
48-
.derived_descriptor(&secp, 0) // dummy index value if it not a wildcard
48+
.derived_descriptor(&secp)
4949
.unwrap()
5050
.address(&elements::AddressParams::ELEMENTS)
5151
.unwrap();
@@ -68,7 +68,8 @@ fn p2sh_p2wsh<C: Verification>(secp: &Secp256k1<C>) -> Address {
6868

6969
let address = Descriptor::<DescriptorPublicKey>::from_str(&s)
7070
.unwrap()
71-
.derived_descriptor(secp, 5)
71+
.at_derivation_index(5)
72+
.derived_descriptor(secp)
7273
.unwrap()
7374
.address(&elements::AddressParams::ELEMENTS)
7475
.unwrap();

src/descriptor/key.rs

Lines changed: 81 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,9 @@ pub struct DescriptorXKey<K: InnerXKey> {
6868
pub wildcard: Wildcard,
6969
}
7070

71-
/// A derived [`DescriptorPublicKey`]
72-
///
73-
/// Derived keys are guaranteed to never contain wildcards
71+
/// A [`DescriptorPublicKey`] without any wildcards.
7472
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
75-
pub struct DerivedDescriptorKey {
76-
key: DescriptorPublicKey,
77-
index: u32,
78-
}
73+
pub struct DefiniteDescriptorKey(DescriptorPublicKey);
7974

8075
impl fmt::Display for DescriptorSecretKey {
8176
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -354,22 +349,14 @@ impl FromStr for DescriptorPublicKey {
354349
/// Descriptor key conversion error
355350
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
356351
pub enum ConversionError {
357-
/// Attempted to convert a key with a wildcard to a bitcoin public key
358-
Wildcard,
359352
/// Attempted to convert a key with hardened derivations to a bitcoin public key
360353
HardenedChild,
361-
/// Attempted to convert a key with a hardened wildcard to a bitcoin public key
362-
HardenedWildcard,
363354
}
364355

365356
impl fmt::Display for ConversionError {
366357
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367358
f.write_str(match *self {
368-
ConversionError::Wildcard => "uninstantiated wildcard in bip32 path",
369359
ConversionError::HardenedChild => "hardened child step in bip32 path",
370-
ConversionError::HardenedWildcard => {
371-
"hardened and uninstantiated wildcard in bip32 path"
372-
}
373360
})
374361
}
375362
}
@@ -379,7 +366,7 @@ impl error::Error for ConversionError {
379366
use self::ConversionError::*;
380367

381368
match self {
382-
Wildcard | HardenedChild | HardenedWildcard => None,
369+
HardenedChild => None,
383370
}
384371
}
385372
}
@@ -437,40 +424,50 @@ impl DescriptorPublicKey {
437424
}
438425
}
439426

440-
/// Whether or not the key has a wildcards
427+
/// Whether or not the key has a wildcard
428+
#[deprecated(note = "use has_wildcard instead")]
441429
pub fn is_deriveable(&self) -> bool {
430+
self.has_wildcard()
431+
}
432+
433+
/// Whether or not the key has a wildcard
434+
pub fn has_wildcard(&self) -> bool {
442435
match *self {
443436
DescriptorPublicKey::Single(..) => false,
444437
DescriptorPublicKey::XPub(ref xpub) => xpub.wildcard != Wildcard::None,
445438
}
446439
}
447440

448-
/// Derives the [`DescriptorPublicKey`] at `index` if this key is an xpub and has a wildcard.
441+
#[deprecated(note = "use at_derivation_index instead")]
442+
/// Deprecated name of [`at_derivation_index`].
443+
pub fn derive(self, index: u32) -> DefiniteDescriptorKey {
444+
self.at_derivation_index(index)
445+
}
446+
447+
/// Replaces any wildcard (i.e. `/*`) in the key with a particular derivation index, turning it into a
448+
/// *definite* key (i.e. one where all the derivation paths are set).
449449
///
450450
/// # Returns
451451
///
452452
/// - If this key is not an xpub, returns `self`.
453453
/// - If this key is an xpub but does not have a wildcard, returns `self`.
454-
/// - Otherwise, returns the derived xpub at `index` (removing the wildcard).
455-
///
456-
/// Since it's guaranteed that extended keys won't have wildcards, the key is returned as
457-
/// [`DerivedDescriptorKey`].
454+
/// - Otherwise, returns the xpub at derivation `index` (removing the wildcard).
458455
///
459456
/// # Panics
460457
///
461458
/// If `index` ≥ 2^31
462-
pub fn derive(self, index: u32) -> DerivedDescriptorKey {
463-
let derived = match self {
459+
pub fn at_derivation_index(self, index: u32) -> DefiniteDescriptorKey {
460+
let definite = match self {
464461
DescriptorPublicKey::Single(_) => self,
465462
DescriptorPublicKey::XPub(xpub) => {
466463
let derivation_path = match xpub.wildcard {
467464
Wildcard::None => xpub.derivation_path,
468-
Wildcard::Unhardened => xpub
469-
.derivation_path
470-
.into_child(bip32::ChildNumber::from_normal_idx(index).unwrap()),
471-
Wildcard::Hardened => xpub
472-
.derivation_path
473-
.into_child(bip32::ChildNumber::from_hardened_idx(index).unwrap()),
465+
Wildcard::Unhardened => xpub.derivation_path.into_child(
466+
bip32::ChildNumber::from_normal_idx(index).expect("index must < 2^31"),
467+
),
468+
Wildcard::Hardened => xpub.derivation_path.into_child(
469+
bip32::ChildNumber::from_hardened_idx(index).expect("index must < 2^31"),
470+
),
474471
};
475472
DescriptorPublicKey::XPub(DescriptorXKey {
476473
origin: xpub.origin,
@@ -481,7 +478,7 @@ impl DescriptorPublicKey {
481478
}
482479
};
483480

484-
DerivedDescriptorKey::new(derived, index)
481+
DefiniteDescriptorKey::new(definite)
485482
.expect("The key should not contain any wildcards at this point")
486483
}
487484

@@ -490,13 +487,10 @@ impl DescriptorPublicKey {
490487
/// and returns the obtained full [`bitcoin::PublicKey`]. All BIP32 derivations
491488
/// always return a compressed key
492489
///
493-
/// Will return an error if the descriptor key has any hardened
494-
/// derivation steps in its path, or if the key has any wildcards.
490+
/// Will return an error if the descriptor key has any hardened derivation steps in its path. To
491+
/// avoid this error you should replace any such public keys first with [`translate_pk`].
495492
///
496-
/// To ensure there are no wildcards, call `.derive(0)` or similar;
497-
/// to avoid hardened derivation steps, start from a `DescriptorSecretKey`
498-
/// and call `to_public`, or call `TranslatePk2::translate_pk2` with
499-
/// some function which has access to secret key data.
493+
/// [`translate_pk`]: crate::TranslatePk::translate_pk
500494
pub fn derive_public_key<C: Verification>(
501495
&self,
502496
secp: &Secp256k1<C>,
@@ -507,8 +501,9 @@ impl DescriptorPublicKey {
507501
SinglePubKey::XOnly(xpk) => Ok(xpk.to_public_key()),
508502
},
509503
DescriptorPublicKey::XPub(ref xpk) => match xpk.wildcard {
510-
Wildcard::Unhardened => Err(ConversionError::Wildcard),
511-
Wildcard::Hardened => Err(ConversionError::HardenedWildcard),
504+
Wildcard::Unhardened | Wildcard::Hardened => {
505+
unreachable!("we've excluded this error case")
506+
}
512507
Wildcard::None => match xpk.xkey.derive_pub(secp, &xpk.derivation_path.as_ref()) {
513508
Ok(xpub) => Ok(bitcoin::PublicKey::new(xpub.public_key)),
514509
Err(bip32::Error::CannotDeriveFromHardenedKey) => {
@@ -747,7 +742,7 @@ impl MiniscriptKey for DescriptorPublicKey {
747742
}
748743
}
749744

750-
impl DerivedDescriptorKey {
745+
impl DefiniteDescriptorKey {
751746
/// Computes the raw [`bitcoin::PublicKey`] for this descriptor key.
752747
///
753748
/// Will return an error if the key has any hardened derivation steps
@@ -758,32 +753,51 @@ impl DerivedDescriptorKey {
758753
&self,
759754
secp: &Secp256k1<C>,
760755
) -> Result<bitcoin::PublicKey, ConversionError> {
761-
self.key.derive_public_key(secp)
762-
}
763-
764-
/// Return the derivation index of this key
765-
pub fn index(&self) -> u32 {
766-
self.index
756+
self.0.derive_public_key(secp)
767757
}
768758

769759
/// Construct an instance from a descriptor key and a derivation index
770760
///
771761
/// Returns `None` if the key contains a wildcard
772-
fn new(key: DescriptorPublicKey, index: u32) -> Option<Self> {
773-
match key {
774-
DescriptorPublicKey::XPub(ref xpk) if xpk.wildcard != Wildcard::None => None,
775-
k => Some(DerivedDescriptorKey { key: k, index }),
762+
fn new(key: DescriptorPublicKey) -> Option<Self> {
763+
if key.has_wildcard() {
764+
None
765+
} else {
766+
Some(Self(key))
776767
}
777768
}
769+
770+
/// The fingerprint of the master key associated with this key, `0x00000000` if none.
771+
pub fn master_fingerprint(&self) -> bip32::Fingerprint {
772+
self.0.master_fingerprint()
773+
}
774+
775+
/// Full path, from the master key
776+
pub fn full_derivation_path(&self) -> bip32::DerivationPath {
777+
self.0.full_derivation_path()
778+
}
779+
}
780+
781+
impl FromStr for DefiniteDescriptorKey {
782+
type Err = DescriptorKeyParseError;
783+
784+
fn from_str(s: &str) -> Result<Self, Self::Err> {
785+
let inner = DescriptorPublicKey::from_str(s)?;
786+
Ok(
787+
DefiniteDescriptorKey::new(inner).ok_or(DescriptorKeyParseError(
788+
"cannot parse key with a wilcard as a DerivedDescriptorKey",
789+
))?,
790+
)
791+
}
778792
}
779793

780-
impl fmt::Display for DerivedDescriptorKey {
794+
impl fmt::Display for DefiniteDescriptorKey {
781795
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
782-
self.key.fmt(f)
796+
self.0.fmt(f)
783797
}
784798
}
785799

786-
impl MiniscriptKey for DerivedDescriptorKey {
800+
impl MiniscriptKey for DefiniteDescriptorKey {
787801
// This allows us to be able to derive public keys even for PkH s
788802
type RawPkHash = Self;
789803
type Sha256 = sha256::Hash;
@@ -792,22 +806,22 @@ impl MiniscriptKey for DerivedDescriptorKey {
792806
type Hash160 = hash160::Hash;
793807

794808
fn is_uncompressed(&self) -> bool {
795-
self.key.is_uncompressed()
809+
self.0.is_uncompressed()
796810
}
797811

798812
fn is_x_only_key(&self) -> bool {
799-
self.key.is_x_only_key()
813+
self.0.is_x_only_key()
800814
}
801815

802816
fn to_pubkeyhash(&self) -> Self {
803817
self.clone()
804818
}
805819
}
806820

807-
impl ToPublicKey for DerivedDescriptorKey {
821+
impl ToPublicKey for DefiniteDescriptorKey {
808822
fn to_public_key(&self) -> bitcoin::PublicKey {
809823
let secp = Secp256k1::verification_only();
810-
self.key.derive_public_key(&secp).unwrap()
824+
self.0.derive_public_key(&secp).unwrap()
811825
}
812826

813827
fn hash_to_hash160(hash: &Self) -> hash160::Hash {
@@ -831,6 +845,12 @@ impl ToPublicKey for DerivedDescriptorKey {
831845
}
832846
}
833847

848+
impl From<DefiniteDescriptorKey> for DescriptorPublicKey {
849+
fn from(d: DefiniteDescriptorKey) -> Self {
850+
d.0
851+
}
852+
}
853+
834854
#[cfg(test)]
835855
mod test {
836856
use std::str::FromStr;
@@ -936,17 +956,17 @@ mod test {
936956
let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2").unwrap();
937957
assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
938958
assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'/2");
939-
assert_eq!(public_key.is_deriveable(), false);
959+
assert_eq!(public_key.has_wildcard(), false);
940960

941961
let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*").unwrap();
942962
assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
943963
assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'");
944-
assert_eq!(public_key.is_deriveable(), true);
964+
assert_eq!(public_key.has_wildcard(), true);
945965

946966
let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*h").unwrap();
947967
assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
948968
assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'");
949-
assert_eq!(public_key.is_deriveable(), true);
969+
assert_eq!(public_key.has_wildcard(), true);
950970
}
951971

952972
#[test]
@@ -958,7 +978,7 @@ mod test {
958978
assert_eq!(public_key.to_string(), "[2cbe2a6d/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2");
959979
assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d");
960980
assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'/2");
961-
assert_eq!(public_key.is_deriveable(), false);
981+
assert_eq!(public_key.has_wildcard(), false);
962982

963983
let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2'").unwrap();
964984
let public_key = secret_key.to_public(&secp).unwrap();

0 commit comments

Comments
 (0)