Skip to content

Commit c7c39f1

Browse files
committedJul 20, 2022
Merge #448: DerivedDescriptor unfinished business
2ad6555 Rename "derive" things that are not doing derivation (LLFourn) 6dc6aca Make DerivedDescriptorKey first-class citizen (LLFourn) Pull request description: This PR further develops the idea introduced in #345. It has two commits both with relatively detailed commit messages that can be reviewed separately. In summary: 1. Develop the `DerivedDescriptorKey` (a key that is guaranteed not to have wildcard in it) idea more by adding missing functionality and refining the API. In addition, I removed the error cases from `ConversionError` which seems to have been omitted from #345. 2. Since the introduction of `DerivedDescriptorKey`, the overlapping usage of the term "derive" has become quite confusing. In addition to the usual definition of "derive" we have also used it to mean "replace a wildcard with a particular derivation index". I deprecated and renamed everything that uses the latter definition. ACKs for top commit: apoelstra: ACK 2ad6555 sanket1729: ACK 2ad6555. Thanks for the clean changes. Tree-SHA512: 0198404a1bfecab2324a8785117248fc566cfbb53decbd234928e378f102bdc5c5de6d31b437b8f1b0ba90ef524a362a46150028f80a4b029589406233abd2fe
2 parents d524c6d + 2ad6555 commit c7c39f1

File tree

6 files changed

+209
-140
lines changed

6 files changed

+209
-140
lines changed
 

‎examples/xpub_descriptors.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::str::FromStr;
1818

1919
use miniscript::bitcoin::secp256k1::{Secp256k1, Verification};
2020
use miniscript::bitcoin::{Address, Network};
21-
use miniscript::{Descriptor, DescriptorPublicKey};
21+
use miniscript::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey};
2222

2323
const XPUB_1: &str = "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB";
2424
const XPUB_2: &str = "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH";
@@ -40,9 +40,9 @@ fn p2wsh<C: Verification>(secp: &Secp256k1<C>) -> Address {
4040
let s = format!("wsh(sortedmulti(1,{},{}))", XPUB_1, XPUB_2);
4141
// let s = format!("wsh(sortedmulti(1,{},{}))", XPUB_2, XPUB_1);
4242

43-
let address = Descriptor::<DescriptorPublicKey>::from_str(&s)
43+
let address = Descriptor::<DefiniteDescriptorKey>::from_str(&s)
4444
.unwrap()
45-
.derived_descriptor(&secp, 0) // dummy index value if it not a wildcard
45+
.derived_descriptor(&secp)
4646
.unwrap()
4747
.address(Network::Bitcoin)
4848
.unwrap();

‎src/descriptor/key.rs

Lines changed: 81 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,9 @@ pub enum SinglePubKey {
7070
XOnly(XOnlyPublicKey),
7171
}
7272

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

8277
impl fmt::Display for DescriptorSecretKey {
8378
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -357,22 +352,14 @@ impl FromStr for DescriptorPublicKey {
357352
/// Descriptor key conversion error
358353
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
359354
pub enum ConversionError {
360-
/// Attempted to convert a key with a wildcard to a bitcoin public key
361-
Wildcard,
362355
/// Attempted to convert a key with hardened derivations to a bitcoin public key
363356
HardenedChild,
364-
/// Attempted to convert a key with a hardened wildcard to a bitcoin public key
365-
HardenedWildcard,
366357
}
367358

368359
impl fmt::Display for ConversionError {
369360
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
370361
f.write_str(match *self {
371-
ConversionError::Wildcard => "uninstantiated wildcard in bip32 path",
372362
ConversionError::HardenedChild => "hardened child step in bip32 path",
373-
ConversionError::HardenedWildcard => {
374-
"hardened and uninstantiated wildcard in bip32 path"
375-
}
376363
})
377364
}
378365
}
@@ -383,7 +370,7 @@ impl error::Error for ConversionError {
383370
use self::ConversionError::*;
384371

385372
match self {
386-
Wildcard | HardenedChild | HardenedWildcard => None,
373+
HardenedChild => None,
387374
}
388375
}
389376
}
@@ -441,40 +428,50 @@ impl DescriptorPublicKey {
441428
}
442429
}
443430

444-
/// Whether or not the key has a wildcards
431+
/// Whether or not the key has a wildcard
432+
#[deprecated(note = "use has_wildcard instead")]
445433
pub fn is_deriveable(&self) -> bool {
434+
self.has_wildcard()
435+
}
436+
437+
/// Whether or not the key has a wildcard
438+
pub fn has_wildcard(&self) -> bool {
446439
match *self {
447440
DescriptorPublicKey::Single(..) => false,
448441
DescriptorPublicKey::XPub(ref xpub) => xpub.wildcard != Wildcard::None,
449442
}
450443
}
451444

452-
/// Derives the [`DescriptorPublicKey`] at `index` if this key is an xpub and has a wildcard.
445+
#[deprecated(note = "use at_derivation_index instead")]
446+
/// Deprecated name of [`at_derivation_index`].
447+
pub fn derive(self, index: u32) -> DefiniteDescriptorKey {
448+
self.at_derivation_index(index)
449+
}
450+
451+
/// Replaces any wildcard (i.e. `/*`) in the key with a particular derivation index, turning it into a
452+
/// *definite* key (i.e. one where all the derivation paths are set).
453453
///
454454
/// # Returns
455455
///
456456
/// - If this key is not an xpub, returns `self`.
457457
/// - If this key is an xpub but does not have a wildcard, returns `self`.
458-
/// - Otherwise, returns the derived xpub at `index` (removing the wildcard).
459-
///
460-
/// Since it's guaranteed that extended keys won't have wildcards, the key is returned as
461-
/// [`DerivedDescriptorKey`].
458+
/// - Otherwise, returns the xpub at derivation `index` (removing the wildcard).
462459
///
463460
/// # Panics
464461
///
465462
/// If `index` ≥ 2^31
466-
pub fn derive(self, index: u32) -> DerivedDescriptorKey {
467-
let derived = match self {
463+
pub fn at_derivation_index(self, index: u32) -> DefiniteDescriptorKey {
464+
let definite = match self {
468465
DescriptorPublicKey::Single(_) => self,
469466
DescriptorPublicKey::XPub(xpub) => {
470467
let derivation_path = match xpub.wildcard {
471468
Wildcard::None => xpub.derivation_path,
472-
Wildcard::Unhardened => xpub
473-
.derivation_path
474-
.into_child(bip32::ChildNumber::from_normal_idx(index).unwrap()),
475-
Wildcard::Hardened => xpub
476-
.derivation_path
477-
.into_child(bip32::ChildNumber::from_hardened_idx(index).unwrap()),
469+
Wildcard::Unhardened => xpub.derivation_path.into_child(
470+
bip32::ChildNumber::from_normal_idx(index).expect("index must < 2^31"),
471+
),
472+
Wildcard::Hardened => xpub.derivation_path.into_child(
473+
bip32::ChildNumber::from_hardened_idx(index).expect("index must < 2^31"),
474+
),
478475
};
479476
DescriptorPublicKey::XPub(DescriptorXKey {
480477
origin: xpub.origin,
@@ -485,7 +482,7 @@ impl DescriptorPublicKey {
485482
}
486483
};
487484

488-
DerivedDescriptorKey::new(derived, index)
485+
DefiniteDescriptorKey::new(definite)
489486
.expect("The key should not contain any wildcards at this point")
490487
}
491488

@@ -494,13 +491,10 @@ impl DescriptorPublicKey {
494491
/// and returns the obtained full [`bitcoin::PublicKey`]. All BIP32 derivations
495492
/// always return a compressed key
496493
///
497-
/// Will return an error if the descriptor key has any hardened
498-
/// derivation steps in its path, or if the key has any wildcards.
494+
/// Will return an error if the descriptor key has any hardened derivation steps in its path. To
495+
/// avoid this error you should replace any such public keys first with [`translate_pk`].
499496
///
500-
/// To ensure there are no wildcards, call `.derive(0)` or similar;
501-
/// to avoid hardened derivation steps, start from a `DescriptorSecretKey`
502-
/// and call `to_public`, or call `TranslatePk2::translate_pk2` with
503-
/// some function which has access to secret key data.
497+
/// [`translate_pk`]: crate::TranslatePk::translate_pk
504498
pub fn derive_public_key<C: Verification>(
505499
&self,
506500
secp: &Secp256k1<C>,
@@ -511,8 +505,9 @@ impl DescriptorPublicKey {
511505
SinglePubKey::XOnly(xpk) => Ok(xpk.to_public_key()),
512506
},
513507
DescriptorPublicKey::XPub(ref xpk) => match xpk.wildcard {
514-
Wildcard::Unhardened => Err(ConversionError::Wildcard),
515-
Wildcard::Hardened => Err(ConversionError::HardenedWildcard),
508+
Wildcard::Unhardened | Wildcard::Hardened => {
509+
unreachable!("we've excluded this error case")
510+
}
516511
Wildcard::None => match xpk.xkey.derive_pub(secp, &xpk.derivation_path.as_ref()) {
517512
Ok(xpub) => Ok(bitcoin::PublicKey::new(xpub.public_key)),
518513
Err(bip32::Error::CannotDeriveFromHardenedKey) => {
@@ -767,7 +762,7 @@ impl MiniscriptKey for DescriptorPublicKey {
767762
}
768763
}
769764

770-
impl DerivedDescriptorKey {
765+
impl DefiniteDescriptorKey {
771766
/// Computes the raw [`bitcoin::PublicKey`] for this descriptor key.
772767
///
773768
/// Will return an error if the key has any hardened derivation steps
@@ -778,32 +773,51 @@ impl DerivedDescriptorKey {
778773
&self,
779774
secp: &Secp256k1<C>,
780775
) -> Result<bitcoin::PublicKey, ConversionError> {
781-
self.key.derive_public_key(secp)
782-
}
783-
784-
/// Return the derivation index of this key
785-
pub fn index(&self) -> u32 {
786-
self.index
776+
self.0.derive_public_key(secp)
787777
}
788778

789779
/// Construct an instance from a descriptor key and a derivation index
790780
///
791781
/// Returns `None` if the key contains a wildcard
792-
fn new(key: DescriptorPublicKey, index: u32) -> Option<Self> {
793-
match key {
794-
DescriptorPublicKey::XPub(ref xpk) if xpk.wildcard != Wildcard::None => None,
795-
k => Some(DerivedDescriptorKey { key: k, index }),
782+
fn new(key: DescriptorPublicKey) -> Option<Self> {
783+
if key.has_wildcard() {
784+
None
785+
} else {
786+
Some(Self(key))
796787
}
797788
}
789+
790+
/// The fingerprint of the master key associated with this key, `0x00000000` if none.
791+
pub fn master_fingerprint(&self) -> bip32::Fingerprint {
792+
self.0.master_fingerprint()
793+
}
794+
795+
/// Full path, from the master key
796+
pub fn full_derivation_path(&self) -> bip32::DerivationPath {
797+
self.0.full_derivation_path()
798+
}
799+
}
800+
801+
impl FromStr for DefiniteDescriptorKey {
802+
type Err = DescriptorKeyParseError;
803+
804+
fn from_str(s: &str) -> Result<Self, Self::Err> {
805+
let inner = DescriptorPublicKey::from_str(s)?;
806+
Ok(
807+
DefiniteDescriptorKey::new(inner).ok_or(DescriptorKeyParseError(
808+
"cannot parse key with a wilcard as a DerivedDescriptorKey",
809+
))?,
810+
)
811+
}
798812
}
799813

800-
impl fmt::Display for DerivedDescriptorKey {
814+
impl fmt::Display for DefiniteDescriptorKey {
801815
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
802-
self.key.fmt(f)
816+
self.0.fmt(f)
803817
}
804818
}
805819

806-
impl MiniscriptKey for DerivedDescriptorKey {
820+
impl MiniscriptKey for DefiniteDescriptorKey {
807821
// This allows us to be able to derive public keys even for PkH s
808822
type RawPkHash = Self;
809823
type Sha256 = sha256::Hash;
@@ -812,22 +826,22 @@ impl MiniscriptKey for DerivedDescriptorKey {
812826
type Hash160 = hash160::Hash;
813827

814828
fn is_uncompressed(&self) -> bool {
815-
self.key.is_uncompressed()
829+
self.0.is_uncompressed()
816830
}
817831

818832
fn is_x_only_key(&self) -> bool {
819-
self.key.is_x_only_key()
833+
self.0.is_x_only_key()
820834
}
821835

822836
fn to_pubkeyhash(&self) -> Self {
823837
self.clone()
824838
}
825839
}
826840

827-
impl ToPublicKey for DerivedDescriptorKey {
841+
impl ToPublicKey for DefiniteDescriptorKey {
828842
fn to_public_key(&self) -> bitcoin::PublicKey {
829843
let secp = Secp256k1::verification_only();
830-
self.key.derive_public_key(&secp).unwrap()
844+
self.0.derive_public_key(&secp).unwrap()
831845
}
832846

833847
fn hash_to_hash160(hash: &Self) -> hash160::Hash {
@@ -851,6 +865,12 @@ impl ToPublicKey for DerivedDescriptorKey {
851865
}
852866
}
853867

868+
impl From<DefiniteDescriptorKey> for DescriptorPublicKey {
869+
fn from(d: DefiniteDescriptorKey) -> Self {
870+
d.0
871+
}
872+
}
873+
854874
#[cfg(test)]
855875
mod test {
856876
use core::str::FromStr;
@@ -957,17 +977,17 @@ mod test {
957977
let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2").unwrap();
958978
assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
959979
assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'/2");
960-
assert_eq!(public_key.is_deriveable(), false);
980+
assert_eq!(public_key.has_wildcard(), false);
961981

962982
let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*").unwrap();
963983
assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
964984
assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'");
965-
assert_eq!(public_key.is_deriveable(), true);
985+
assert_eq!(public_key.has_wildcard(), true);
966986

967987
let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*h").unwrap();
968988
assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00");
969989
assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'");
970-
assert_eq!(public_key.is_deriveable(), true);
990+
assert_eq!(public_key.has_wildcard(), true);
971991
}
972992

973993
#[test]
@@ -979,7 +999,7 @@ mod test {
979999
assert_eq!(public_key.to_string(), "[2cbe2a6d/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2");
9801000
assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d");
9811001
assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'/2");
982-
assert_eq!(public_key.is_deriveable(), false);
1002+
assert_eq!(public_key.has_wildcard(), false);
9831003

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

‎src/descriptor/mod.rs

Lines changed: 102 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ mod checksum;
5858
mod key;
5959

6060
pub use self::key::{
61-
ConversionError, DerivedDescriptorKey, DescriptorKeyParseError, DescriptorPublicKey,
61+
ConversionError, DefiniteDescriptorKey, DescriptorKeyParseError, DescriptorPublicKey,
6262
DescriptorSecretKey, DescriptorXKey, InnerXKey, SinglePriv, SinglePub, SinglePubKey, Wildcard,
6363
};
6464

@@ -513,53 +513,67 @@ impl<Pk: MiniscriptKey> ForEachKey<Pk> for Descriptor<Pk> {
513513

514514
impl Descriptor<DescriptorPublicKey> {
515515
/// Whether or not the descriptor has any wildcards
516+
#[deprecated(note = "use has_wildcards instead")]
516517
pub fn is_deriveable(&self) -> bool {
517-
self.for_any_key(|key| key.is_deriveable())
518+
self.has_wildcard()
518519
}
519520

520-
/// Derives all wildcard keys in the descriptor using the supplied index
521+
/// Whether or not the descriptor has any wildcards i.e. `/*`.
522+
pub fn has_wildcard(&self) -> bool {
523+
self.for_any_key(|key| key.has_wildcard())
524+
}
525+
526+
/// Replaces all wildcards (i.e. `/*`) in the descriptor with a particular derivation index,
527+
/// turning it into a *definite* descriptor.
521528
///
522-
/// Panics if given an index ≥ 2^31
529+
/// # Panics
523530
///
524-
/// In most cases, you would want to use [`Self::derived_descriptor`] directly to obtain
525-
/// a [`Descriptor<bitcoin::PublicKey>`]
526-
pub fn derive(&self, index: u32) -> Descriptor<DerivedDescriptorKey> {
531+
/// If index ≥ 2^31
532+
pub fn at_derivation_index(&self, index: u32) -> Descriptor<DefiniteDescriptorKey> {
527533
struct Derivator(u32);
528534

529-
impl PkTranslator<DescriptorPublicKey, DerivedDescriptorKey, ()> for Derivator {
530-
fn pk(&mut self, pk: &DescriptorPublicKey) -> Result<DerivedDescriptorKey, ()> {
531-
Ok(pk.clone().derive(self.0))
535+
impl PkTranslator<DescriptorPublicKey, DefiniteDescriptorKey, ()> for Derivator {
536+
fn pk(&mut self, pk: &DescriptorPublicKey) -> Result<DefiniteDescriptorKey, ()> {
537+
Ok(pk.clone().at_derivation_index(self.0))
532538
}
533539

534-
fn pkh(&mut self, pkh: &DescriptorPublicKey) -> Result<DerivedDescriptorKey, ()> {
535-
Ok(pkh.clone().derive(self.0))
540+
fn pkh(&mut self, pkh: &DescriptorPublicKey) -> Result<DefiniteDescriptorKey, ()> {
541+
Ok(pkh.clone().at_derivation_index(self.0))
536542
}
537543
}
538544
self.translate_pk(&mut Derivator(index))
539545
.expect("BIP 32 key index substitution cannot fail")
540546
}
541547

542-
/// Derive a [`Descriptor`] with a concrete [`bitcoin::PublicKey`] at a given index
543-
/// Removes all extended pubkeys and wildcards from the descriptor and only leaves
544-
/// concrete [`bitcoin::PublicKey`]. All [`bitcoin::XOnlyPublicKey`]s are converted
545-
/// to [`bitcoin::PublicKey`]s by adding a default(0x02) y-coordinate. For [`Tr`]
546-
/// descriptor, spend info is also cached.
548+
#[deprecated(note = "use at_derivation_index instead")]
549+
/// Deprecated name for [`at_derivation_index`].
550+
pub fn derive(&self, index: u32) -> Descriptor<DefiniteDescriptorKey> {
551+
self.at_derivation_index(index)
552+
}
553+
554+
/// Convert all the public keys in the descriptor to [`bitcoin::PublicKey`] by deriving them or
555+
/// otherwise converting them. All [`bitcoin::XOnlyPublicKey`]s are converted to by adding a
556+
/// default(0x02) y-coordinate.
547557
///
548-
/// # Examples
558+
/// This is a shorthand for:
549559
///
550560
/// ```
551-
/// use miniscript::descriptor::{Descriptor, DescriptorPublicKey};
552-
/// use miniscript::bitcoin::secp256k1;
553-
/// use std::str::FromStr;
554-
///
555-
/// // test from bip 86
556-
/// let secp = secp256k1::Secp256k1::verification_only();
557-
/// let descriptor = Descriptor::<DescriptorPublicKey>::from_str("tr(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)")
561+
/// # use miniscript::{Descriptor, DescriptorPublicKey, bitcoin::secp256k1::Secp256k1};
562+
/// # use core::str::FromStr;
563+
/// # let descriptor = Descriptor::<DescriptorPublicKey>::from_str("tr(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)")
558564
/// .expect("Valid ranged descriptor");
559-
/// let result = descriptor.derived_descriptor(&secp, 0).expect("Non-hardened derivation");
560-
/// assert_eq!(result.to_string(), "tr(03cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115)#6qm9h8ym");
565+
/// # let index = 42;
566+
/// # let secp = Secp256k1::verification_only();
567+
/// let derived_descriptor = descriptor.at_derivation_index(index).derived_descriptor(&secp);
568+
/// # assert_eq!(descriptor.derived_descriptor(&secp, index), derived_descriptor);
561569
/// ```
562570
///
571+
/// and is only here really here for backwards compatbility.
572+
/// See [`at_derivation_index`] and `[derived_descriptor`] for more documentation.
573+
///
574+
/// [`at_derivation_index`]: Self::at_derivation_index
575+
/// [`derived_descriptor`]: crate::DerivedDescriptor::derived_descriptor
576+
///
563577
/// # Errors
564578
///
565579
/// This function will return an error if hardened derivation is attempted.
@@ -568,29 +582,7 @@ impl Descriptor<DescriptorPublicKey> {
568582
secp: &secp256k1::Secp256k1<C>,
569583
index: u32,
570584
) -> Result<Descriptor<bitcoin::PublicKey>, ConversionError> {
571-
struct Derivator<'a, C: secp256k1::Verification>(&'a secp256k1::Secp256k1<C>);
572-
573-
impl<'a, C: secp256k1::Verification>
574-
PkTranslator<DerivedDescriptorKey, bitcoin::PublicKey, ConversionError>
575-
for Derivator<'a, C>
576-
{
577-
fn pk(
578-
&mut self,
579-
pk: &DerivedDescriptorKey,
580-
) -> Result<bitcoin::PublicKey, ConversionError> {
581-
pk.derive_public_key(&self.0)
582-
}
583-
584-
fn pkh(
585-
&mut self,
586-
pkh: &DerivedDescriptorKey,
587-
) -> Result<bitcoin::hashes::hash160::Hash, ConversionError> {
588-
Ok(pkh.derive_public_key(&self.0)?.to_pubkeyhash())
589-
}
590-
}
591-
592-
let derived = self.derive(index).translate_pk(&mut Derivator(secp))?;
593-
Ok(derived)
585+
self.at_derivation_index(index).derived_descriptor(&secp)
594586
}
595587

596588
/// Parse a descriptor that may contain secret keys
@@ -731,7 +723,7 @@ impl Descriptor<DescriptorPublicKey> {
731723
script_pubkey: &Script,
732724
range: Range<u32>,
733725
) -> Result<Option<(u32, Descriptor<bitcoin::PublicKey>)>, ConversionError> {
734-
let range = if self.is_deriveable() { range } else { 0..1 };
726+
let range = if self.has_wildcard() { range } else { 0..1 };
735727

736728
for i in range {
737729
let concrete = self.derived_descriptor(secp, i)?;
@@ -744,6 +736,59 @@ impl Descriptor<DescriptorPublicKey> {
744736
}
745737
}
746738

739+
impl Descriptor<DefiniteDescriptorKey> {
740+
/// Convert all the public keys in the descriptor to [`bitcoin::PublicKey`] by deriving them or
741+
/// otherwise converting them. All [`bitcoin::XOnlyPublicKey`]s are converted to by adding a
742+
/// default(0x02) y-coordinate.
743+
///
744+
/// # Examples
745+
///
746+
/// ```
747+
/// use miniscript::descriptor::{Descriptor, DescriptorPublicKey};
748+
/// use miniscript::bitcoin::secp256k1;
749+
/// use std::str::FromStr;
750+
///
751+
/// // test from bip 86
752+
/// let secp = secp256k1::Secp256k1::verification_only();
753+
/// let descriptor = Descriptor::<DescriptorPublicKey>::from_str("tr(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)")
754+
/// .expect("Valid ranged descriptor");
755+
/// let result = descriptor.at_derivation_index(0).derived_descriptor(&secp).expect("Non-hardened derivation");
756+
/// assert_eq!(result.to_string(), "tr(03cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115)#6qm9h8ym");
757+
/// ```
758+
///
759+
/// # Errors
760+
///
761+
/// This function will return an error if hardened derivation is attempted.
762+
pub fn derived_descriptor<C: secp256k1::Verification>(
763+
&self,
764+
secp: &secp256k1::Secp256k1<C>,
765+
) -> Result<Descriptor<bitcoin::PublicKey>, ConversionError> {
766+
struct Derivator<'a, C: secp256k1::Verification>(&'a secp256k1::Secp256k1<C>);
767+
768+
impl<'a, C: secp256k1::Verification>
769+
PkTranslator<DefiniteDescriptorKey, bitcoin::PublicKey, ConversionError>
770+
for Derivator<'a, C>
771+
{
772+
fn pk(
773+
&mut self,
774+
pk: &DefiniteDescriptorKey,
775+
) -> Result<bitcoin::PublicKey, ConversionError> {
776+
pk.derive_public_key(&self.0)
777+
}
778+
779+
fn pkh(
780+
&mut self,
781+
pkh: &DefiniteDescriptorKey,
782+
) -> Result<bitcoin::hashes::hash160::Hash, ConversionError> {
783+
Ok(pkh.derive_public_key(&self.0)?.to_pubkeyhash())
784+
}
785+
}
786+
787+
let derived = self.translate_pk(&mut Derivator(secp))?;
788+
Ok(derived)
789+
}
790+
}
791+
747792
impl_from_tree!(
748793
Descriptor<Pk>,
749794
/// Parse an expression tree into a descriptor.
@@ -1564,12 +1609,14 @@ mod tests {
15641609

15651610
// Same address
15661611
let addr_one = desc_one
1567-
.derived_descriptor(&secp_ctx, index)
1612+
.at_derivation_index(index)
1613+
.derived_descriptor(&secp_ctx)
15681614
.unwrap()
15691615
.address(bitcoin::Network::Bitcoin)
15701616
.unwrap();
15711617
let addr_two = desc_two
1572-
.derived_descriptor(&secp_ctx, index)
1618+
.at_derivation_index(index)
1619+
.derived_descriptor(&secp_ctx)
15731620
.unwrap()
15741621
.address(bitcoin::Network::Bitcoin)
15751622
.unwrap();
@@ -1646,7 +1693,7 @@ pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHW
16461693
pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
16471694
let policy: policy::concrete::Policy<DescriptorPublicKey> = descriptor_str.parse().unwrap();
16481695
let descriptor = Descriptor::new_sh(policy.compile().unwrap()).unwrap();
1649-
let derived_descriptor = descriptor.derive(42);
1696+
let definite_descriptor = descriptor.at_derivation_index(42);
16501697

16511698
let res_descriptor_str = "thresh(2,\
16521699
pk([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/42),\
@@ -1656,7 +1703,7 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
16561703
res_descriptor_str.parse().unwrap();
16571704
let res_descriptor = Descriptor::new_sh(res_policy.compile().unwrap()).unwrap();
16581705

1659-
assert_eq!(res_descriptor.to_string(), derived_descriptor.to_string());
1706+
assert_eq!(res_descriptor.to_string(), definite_descriptor.to_string());
16601707
}
16611708

16621709
#[test]

‎src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ use std::error;
135135
use bitcoin::blockdata::{opcodes, script};
136136
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash};
137137

138-
pub use crate::descriptor::{Descriptor, DescriptorPublicKey};
138+
pub use crate::descriptor::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey};
139139
pub use crate::interpreter::Interpreter;
140140
pub use crate::miniscript::context::{BareCtx, Legacy, ScriptContext, Segwitv0, Tap};
141141
pub use crate::miniscript::decode::Terminal;

‎src/psbt/mod.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use crate::miniscript::limits::SEQUENCE_LOCKTIME_DISABLE_FLAG;
3636
use crate::miniscript::satisfy::{After, Older};
3737
use crate::prelude::*;
3838
use crate::{
39-
descriptor, interpreter, Descriptor, DescriptorPublicKey, MiniscriptKey, PkTranslator,
39+
descriptor, interpreter, DefiniteDescriptorKey, Descriptor, MiniscriptKey, PkTranslator,
4040
Preimage32, Satisfier, ToPublicKey, TranslatePk,
4141
};
4242

@@ -568,7 +568,7 @@ pub trait PsbtExt {
568568
fn update_input_with_descriptor(
569569
&mut self,
570570
input_index: usize,
571-
descriptor: &Descriptor<DescriptorPublicKey>,
571+
descriptor: &Descriptor<DefiniteDescriptorKey>,
572572
) -> Result<(), UtxoUpdateError>;
573573

574574
/// Get the sighash message(data to sign) at input index `idx` based on the sighash
@@ -735,7 +735,7 @@ impl PsbtExt for Psbt {
735735
fn update_input_with_descriptor(
736736
&mut self,
737737
input_index: usize,
738-
desc: &Descriptor<DescriptorPublicKey>,
738+
desc: &Descriptor<DefiniteDescriptorKey>,
739739
) -> Result<(), UtxoUpdateError> {
740740
let n_inputs = self.inputs.len();
741741
let input = self
@@ -916,14 +916,14 @@ pub trait PsbtInputExt {
916916
/// [`update_input_with_descriptor`]: PsbtExt::update_input_with_descriptor
917917
fn update_with_descriptor_unchecked(
918918
&mut self,
919-
descriptor: &Descriptor<DescriptorPublicKey>,
919+
descriptor: &Descriptor<DefiniteDescriptorKey>,
920920
) -> Result<Descriptor<bitcoin::PublicKey>, descriptor::ConversionError>;
921921
}
922922

923923
impl PsbtInputExt for psbt::Input {
924924
fn update_with_descriptor_unchecked(
925925
&mut self,
926-
descriptor: &Descriptor<DescriptorPublicKey>,
926+
descriptor: &Descriptor<DefiniteDescriptorKey>,
927927
) -> Result<Descriptor<bitcoin::PublicKey>, descriptor::ConversionError> {
928928
let (derived, _) = update_input_with_descriptor_helper(self, descriptor, None)?;
929929
Ok(derived)
@@ -937,19 +937,19 @@ struct XOnlyHashLookUp(
937937
pub secp256k1::Secp256k1<VerifyOnly>,
938938
);
939939

940-
impl PkTranslator<DescriptorPublicKey, bitcoin::PublicKey, descriptor::ConversionError>
940+
impl PkTranslator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::ConversionError>
941941
for XOnlyHashLookUp
942942
{
943943
fn pk(
944944
&mut self,
945-
xpk: &DescriptorPublicKey,
945+
xpk: &DefiniteDescriptorKey,
946946
) -> Result<bitcoin::PublicKey, descriptor::ConversionError> {
947947
xpk.derive_public_key(&self.1)
948948
}
949949

950950
fn pkh(
951951
&mut self,
952-
xpk: &DescriptorPublicKey,
952+
xpk: &DefiniteDescriptorKey,
953953
) -> Result<hash160::Hash, descriptor::ConversionError> {
954954
let pk = xpk.derive_public_key(&self.1)?;
955955
let xonly = pk.to_x_only_pubkey();
@@ -966,12 +966,12 @@ struct KeySourceLookUp(
966966
pub secp256k1::Secp256k1<VerifyOnly>,
967967
);
968968

969-
impl PkTranslator<DescriptorPublicKey, bitcoin::PublicKey, descriptor::ConversionError>
969+
impl PkTranslator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::ConversionError>
970970
for KeySourceLookUp
971971
{
972972
fn pk(
973973
&mut self,
974-
xpk: &DescriptorPublicKey,
974+
xpk: &DefiniteDescriptorKey,
975975
) -> Result<bitcoin::PublicKey, descriptor::ConversionError> {
976976
let derived = xpk.derive_public_key(&self.1)?;
977977
self.0.insert(
@@ -983,15 +983,15 @@ impl PkTranslator<DescriptorPublicKey, bitcoin::PublicKey, descriptor::Conversio
983983

984984
fn pkh(
985985
&mut self,
986-
xpk: &DescriptorPublicKey,
986+
xpk: &DefiniteDescriptorKey,
987987
) -> Result<hash160::Hash, descriptor::ConversionError> {
988988
Ok(self.pk(xpk)?.to_pubkeyhash())
989989
}
990990
}
991991

992992
fn update_input_with_descriptor_helper(
993993
input: &mut psbt::Input,
994-
descriptor: &Descriptor<DescriptorPublicKey>,
994+
descriptor: &Descriptor<DefiniteDescriptorKey>,
995995
check_script: Option<Script>,
996996
// the return value is a tuple here since the two internal calls to it require different info.
997997
// One needs the derived descriptor and the other needs to know whether the script_pubkey check
@@ -1071,7 +1071,6 @@ fn update_input_with_descriptor_helper(
10711071

10721072
derived
10731073
} else {
1074-
// have to use a RefCell because we can't pass FnMut to translate_pk2
10751074
let mut bip32_derivation = KeySourceLookUp(BTreeMap::new(), Secp256k1::verification_only());
10761075
let derived = descriptor.translate_pk(&mut bip32_derivation)?;
10771076

@@ -1439,7 +1438,7 @@ mod tests {
14391438
#[test]
14401439
fn test_update_input_checks() {
14411440
let desc = format!("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/0)");
1442-
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc).unwrap();
1441+
let desc = Descriptor::<DefiniteDescriptorKey>::from_str(&desc).unwrap();
14431442

14441443
let mut non_witness_utxo = bitcoin::Transaction {
14451444
version: 1,

‎tests/test_desc.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,11 @@ pub fn test_desc_satisfy(
8383
.unwrap();
8484
assert_eq!(blocks.len(), 1);
8585

86-
let desc = test_util::parse_test_desc(&descriptor, &testdata.pubdata);
87-
let desc = desc.map_err(|_x| DescError::DescParseError)?;
86+
let definite_desc = test_util::parse_test_desc(&descriptor, &testdata.pubdata)
87+
.map_err(|_| DescError::DescParseError)?
88+
.at_derivation_index(0);
8889

89-
let derived_desc = desc.derived_descriptor(&secp, 0).unwrap();
90+
let derived_desc = definite_desc.derived_descriptor(&secp).unwrap();
9091
let desc_address = derived_desc.address(bitcoin::Network::Regtest);
9192
let desc_address = desc_address.map_err(|_x| DescError::AddressComputationError)?;
9293

@@ -138,7 +139,9 @@ pub fn test_desc_satisfy(
138139
script_pubkey: addr.script_pubkey(),
139140
});
140141
let mut input = psbt::Input::default();
141-
input.update_with_descriptor_unchecked(&desc).unwrap();
142+
input
143+
.update_with_descriptor_unchecked(&definite_desc)
144+
.unwrap();
142145
input.witness_utxo = Some(witness_utxo.clone());
143146
psbt.inputs.push(input);
144147
psbt.outputs.push(psbt::Output::default());
@@ -294,7 +297,7 @@ pub fn test_desc_satisfy(
294297
testdata.pubdata.ripemd160,
295298
testdata.secretdata.ripemd160_pre.to_vec(),
296299
);
297-
println!("Testing descriptor: {}", desc);
300+
println!("Testing descriptor: {}", definite_desc);
298301
// Finalize the transaction using psbt
299302
// Let miniscript do it's magic!
300303
if let Err(_) = psbt.finalize_mut(&secp) {
@@ -307,7 +310,7 @@ pub fn test_desc_satisfy(
307310
// Check whether the node accepts the transactions
308311
let txid = cl
309312
.send_raw_transaction(&tx)
310-
.expect(&format!("send tx failed for desc {}", desc));
313+
.expect(&format!("send tx failed for desc {}", definite_desc));
311314

312315
// Finally mine the blocks and await confirmations
313316
let _blocks = cl

0 commit comments

Comments
 (0)
Please sign in to comment.