diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 5fa115666..2bcf1a58b 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -316,7 +316,7 @@ dependencies = [ [[package]] name = "miniscript" -version = "12.3.2" +version = "12.3.3" dependencies = [ "bech32", "bitcoin", diff --git a/Cargo-recent.lock b/Cargo-recent.lock index d4a312d77..680083661 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -294,7 +294,7 @@ dependencies = [ [[package]] name = "miniscript" -version = "12.3.2" +version = "12.3.3" dependencies = [ "bech32", "bitcoin", diff --git a/Cargo.toml b/Cargo.toml index 4649502f7..deaab4939 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "miniscript" -version = "12.3.2" +version = "12.3.3" authors = ["Andrew Poelstra , Sanket Kanjalkar "] license = "CC0-1.0" homepage = "https://github.com/rust-bitcoin/rust-miniscript/" diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index 0ca62fc9f..919c9bc34 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -8,7 +8,7 @@ use std::error; use bitcoin::bip32::{self, XKeyIdentifier}; use bitcoin::hashes::{hash160, ripemd160, sha256, Hash, HashEngine}; -use bitcoin::key::XOnlyPublicKey; +use bitcoin::key::{PublicKey, XOnlyPublicKey}; use bitcoin::secp256k1::{Secp256k1, Signing, Verification}; use crate::prelude::*; @@ -473,6 +473,18 @@ impl FromStr for DescriptorPublicKey { } } +impl From for DescriptorPublicKey { + fn from(key: XOnlyPublicKey) -> Self { + DescriptorPublicKey::Single(SinglePub { origin: None, key: SinglePubKey::XOnly(key) }) + } +} + +impl From for DescriptorPublicKey { + fn from(key: PublicKey) -> Self { + DescriptorPublicKey::Single(SinglePub { origin: None, key: SinglePubKey::FullKey(key) }) + } +} + /// Descriptor key conversion error #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] pub enum ConversionError { @@ -1036,7 +1048,7 @@ impl DefiniteDescriptorKey { /// Construct an instance from a descriptor key and a derivation index /// /// Returns `None` if the key contains a wildcard - fn new(key: DescriptorPublicKey) -> Option { + pub fn new(key: DescriptorPublicKey) -> Option { if key.has_wildcard() { None } else { diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index b1afc0dbd..0c06f492c 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -1004,7 +1004,7 @@ mod tests { use bitcoin::hashes::Hash; use bitcoin::script::PushBytes; use bitcoin::sighash::EcdsaSighashType; - use bitcoin::{bip32, PublicKey, Sequence}; + use bitcoin::{bip32, PublicKey, Sequence, XOnlyPublicKey}; use super::checksum::desc_checksum; use super::*; @@ -2064,4 +2064,49 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))"; ) .unwrap_err(); } + + #[test] + fn convert_public_key_descriptor_to_definite_key() { + let descriptor_str = "wsh(or_d(pk(021d4ea7132d4e1a362ee5efd8d0b59dd4d1fe8906eefa7dd812b05a46b73d829b),pk(0302c8bbbb393f32c843149ce36d56405595aaabab2d0e1f4ca5f9de67dd7419f6)))"; + let full_pk_descriptor: Descriptor = + Descriptor::from_str(descriptor_str).unwrap(); + + struct TranslateFullPk; + + impl Translator for TranslateFullPk { + fn pk(&mut self, pk: &bitcoin::PublicKey) -> Result { + Ok(DefiniteDescriptorKey::new(DescriptorPublicKey::from(*pk)) + .expect("DescriptorPublicKey from PublicKey has no wildcards")) + } + + translate_hash_clone!(bitcoin::PublicKey, DefiniteDescriptorKey, ()); + } + + let converted_descriptor = full_pk_descriptor + .translate_pk(&mut TranslateFullPk) + .expect("infallible"); + + assert_eq!(full_pk_descriptor.to_string(), converted_descriptor.to_string()); + + let xonly_descriptor_str = "tr(1d4ea7132d4e1a362ee5efd8d0b59dd4d1fe8906eefa7dd812b05a46b73d829b,pk(02c8bbbb393f32c843149ce36d56405595aaabab2d0e1f4ca5f9de67dd7419f6))"; + let xonly_pk_descriptor: Descriptor = + Descriptor::from_str(xonly_descriptor_str).unwrap(); + + struct TranslateXOnlyPk; + + impl Translator for TranslateXOnlyPk { + fn pk(&mut self, pk: &XOnlyPublicKey) -> Result { + Ok(DefiniteDescriptorKey::new(DescriptorPublicKey::from(*pk)) + .expect("DescriptorPublicKey from XOnlyPublicKey has no wildcards")) + } + + translate_hash_clone!(XOnlyPublicKey, DefiniteDescriptorKey, ()); + } + + let xonly_converted_descriptor = xonly_pk_descriptor + .translate_pk(&mut TranslateXOnlyPk) + .expect("infallible"); + + assert_eq!(xonly_pk_descriptor.to_string(), xonly_converted_descriptor.to_string()); + } }