diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index 79e74353c..783b9855b 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::*; @@ -670,6 +670,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 { @@ -1260,7 +1272,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 650b4ad74..4d7afa4b2 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -1051,7 +1051,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, *}; use crate::hex_script; @@ -2183,4 +2183,58 @@ 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 { + type TargetPk = DefiniteDescriptorKey; + type Error = core::convert::Infallible; + + 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, Self::Error); + } + + 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 { + type TargetPk = DefiniteDescriptorKey; + type Error = core::convert::Infallible; + + 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, Self::Error); + } + + 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()); + } }