diff --git a/src/descriptor/descriptor_impl.rs b/src/descriptor/descriptor_impl.rs new file mode 100644 index 000000000..35d600d6c --- /dev/null +++ b/src/descriptor/descriptor_impl.rs @@ -0,0 +1,452 @@ +//! Module of specialized impl blocks for certain MiniscriptKeys. +//! Contains common APIs for specific types of keys like `DescriptorPublicKey`, +//! `DefinitePublicKey` and more. + +use core::convert::Infallible; +use core::ops::Range; +use core::str::{self, FromStr}; + +use bitcoin::hashes::{hash160, ripemd160, sha256}; +use bitcoin::{secp256k1, Script}; + +use super::ConversionError; +use crate::descriptor::DescriptorSecretKey; +use crate::prelude::*; +use crate::{ + hash256, DefiniteDescriptorKey, Descriptor, DescriptorPublicKey, Error, ForEachKey, + MsDescriptor, MsDescriptorXPubOnly, TranslatePk, Translator, XPubOnly, +}; + +/// Alias type for a map of public key to secret key +/// +/// This map is returned whenever a descriptor that contains secrets is parsed using +/// [`Descriptor::parse_descriptor`], since the descriptor will always only contain +/// public keys. This map allows looking up the corresponding secret key given a +/// public key from the descriptor. +pub type KeyMap = HashMap<DescriptorPublicKey, DescriptorSecretKey>; + +impl MsDescriptorXPubOnly { + /// Whether or not the descriptor has any wildcards i.e. `/*`. + pub fn has_wildcard(&self) -> bool { + self.for_any_key(|key| key.has_wildcard()) + } + + /// Replaces all wildcards (i.e. `/*`) in the descriptor with a particular derivation index, + /// turning it into a *definite* descriptor. + /// + /// # Errors + /// - If index ≥ 2^31 + pub fn at_derivation_index( + &self, + index: u32, + ) -> Result<Descriptor<DefiniteDescriptorKey>, ConversionError> { + struct Derivator(u32); + + impl Translator<XPubOnly, DefiniteDescriptorKey, ConversionError> for Derivator { + fn pk(&mut self, pk: &XPubOnly) -> Result<DefiniteDescriptorKey, ConversionError> { + pk.clone().at_derivation_index(self.0) + } + + translate_hash_clone!(XPubOnly, XPubOnly, ConversionError); + } + + self.translate_pk(&mut Derivator(index)) + .map_err(|e| e.expect_translator_err("No Context errors while translating")) + } + + /// Same as [`Descriptor<DescriptorPublicKey>::derived_descriptor`], but for + /// descriptors with Extended keys only(xpubs only). + pub fn derived_descriptor<C: secp256k1::Verification>( + &self, + secp: &secp256k1::Secp256k1<C>, + index: u32, + ) -> Result<Descriptor<bitcoin::PublicKey>, ConversionError> { + self.at_derivation_index(index)?.derived_descriptor(secp) + } + + /// Returns the ms descriptor of this [`MsDescriptorXPubOnly`]. + pub fn ms_descriptor(&self) -> MsDescriptor { + struct MsDescriptorTranslator; + + impl Translator<XPubOnly, DescriptorPublicKey, Infallible> for MsDescriptorTranslator { + fn pk(&mut self, pk: &XPubOnly) -> Result<DescriptorPublicKey, Infallible> { + Ok(DescriptorPublicKey::XPub(pk.clone())) + } + + translate_hash_clone!(XPubOnly, XPubOnly, Infallible); + } + + let res = self + .translate_pk(&mut MsDescriptorTranslator) + .map_err(|e| e.expect_translator_err("No Context errors while translating")); + // Indirect way to unwrap the infallible error type + match res { + Ok(desc) => desc, + Err(e) => match e {}, + } + } + + /// Constructs a new [`MsDescriptorXPubOnly`] from a [`MsDescriptor`]. + /// + /// # Returns None if: + /// + /// - If the descriptor contains any non-xpub keys. + pub fn from_ms_descriptor(desc: &MsDescriptor) -> Option<Self> { + struct XOnlyKeyTranslator; + + impl Translator<DescriptorPublicKey, XPubOnly, ()> for XOnlyKeyTranslator { + fn pk(&mut self, pk: &DescriptorPublicKey) -> Result<XPubOnly, ()> { + if let DescriptorPublicKey::XPub(xpub) = pk { + Ok(xpub.clone()) + } else { + Err(()) + } + } + + translate_hash_clone!(DescriptorPublicKey, XPubOnly, ()); + } + + desc.translate_pk(&mut XOnlyKeyTranslator) + .map_err(|e| e.expect_translator_err("No Context errors while translating")) + .ok() + } +} + +impl Descriptor<DescriptorPublicKey> { + /// Whether or not the descriptor has any wildcards + #[deprecated(note = "use has_wildcards instead")] + pub fn is_deriveable(&self) -> bool { + self.has_wildcard() + } + + /// Whether or not the descriptor has any wildcards i.e. `/*`. + pub fn has_wildcard(&self) -> bool { + self.for_any_key(|key| key.has_wildcard()) + } + + /// Replaces all wildcards (i.e. `/*`) in the descriptor with a particular derivation index, + /// turning it into a *definite* descriptor. + /// + /// # Errors + /// - If index ≥ 2^31 + pub fn at_derivation_index( + &self, + index: u32, + ) -> Result<Descriptor<DefiniteDescriptorKey>, ConversionError> { + struct Derivator(u32); + + impl Translator<DescriptorPublicKey, DefiniteDescriptorKey, ConversionError> for Derivator { + fn pk( + &mut self, + pk: &DescriptorPublicKey, + ) -> Result<DefiniteDescriptorKey, ConversionError> { + pk.clone().at_derivation_index(self.0) + } + + translate_hash_clone!(DescriptorPublicKey, DescriptorPublicKey, ConversionError); + } + self.translate_pk(&mut Derivator(index)) + .map_err(|e| e.expect_translator_err("No Context errors while translating")) + } + + #[deprecated(note = "use at_derivation_index instead")] + /// Deprecated name for [`Self::at_derivation_index`]. + pub fn derive(&self, index: u32) -> Result<Descriptor<DefiniteDescriptorKey>, ConversionError> { + self.at_derivation_index(index) + } + + /// Convert all the public keys in the descriptor to [`bitcoin::PublicKey`] by deriving them or + /// otherwise converting them. All [`bitcoin::secp256k1::XOnlyPublicKey`]s are converted to by adding a + /// default(0x02) y-coordinate. + /// + /// This is a shorthand for: + /// + /// ``` + /// # use miniscript::{Descriptor, DescriptorPublicKey, bitcoin::secp256k1::Secp256k1}; + /// # use core::str::FromStr; + /// # let descriptor = Descriptor::<DescriptorPublicKey>::from_str("tr(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)") + /// .expect("Valid ranged descriptor"); + /// # let index = 42; + /// # let secp = Secp256k1::verification_only(); + /// let derived_descriptor = descriptor.at_derivation_index(index).unwrap().derived_descriptor(&secp).unwrap(); + /// # assert_eq!(descriptor.derived_descriptor(&secp, index).unwrap(), derived_descriptor); + /// ``` + /// + /// and is only here really here for backwards compatbility. + /// See [`at_derivation_index`] and `[derived_descriptor`] for more documentation. + /// + /// [`at_derivation_index`]: Self::at_derivation_index + /// [`derived_descriptor`]: crate::DerivedDescriptor::derived_descriptor + /// + /// # Errors + /// + /// This function will return an error if hardened derivation is attempted. + pub fn derived_descriptor<C: secp256k1::Verification>( + &self, + secp: &secp256k1::Secp256k1<C>, + index: u32, + ) -> Result<Descriptor<bitcoin::PublicKey>, ConversionError> { + self.at_derivation_index(index)?.derived_descriptor(secp) + } + + /// Parse a descriptor that may contain secret keys + /// + /// Internally turns every secret key found into the corresponding public key and then returns a + /// a descriptor that only contains public keys and a map to lookup the secret key given a public key. + pub fn parse_descriptor<C: secp256k1::Signing>( + secp: &secp256k1::Secp256k1<C>, + s: &str, + ) -> Result<(Descriptor<DescriptorPublicKey>, KeyMap), Error> { + fn parse_key<C: secp256k1::Signing>( + s: &str, + key_map: &mut KeyMap, + secp: &secp256k1::Secp256k1<C>, + ) -> Result<DescriptorPublicKey, Error> { + let (public_key, secret_key) = match DescriptorSecretKey::from_str(s) { + Ok(sk) => ( + sk.to_public(secp) + .map_err(|e| Error::Unexpected(e.to_string()))?, + Some(sk), + ), + Err(_) => ( + DescriptorPublicKey::from_str(s) + .map_err(|e| Error::Unexpected(e.to_string()))?, + None, + ), + }; + + if let Some(secret_key) = secret_key { + key_map.insert(public_key.clone(), secret_key); + } + + Ok(public_key) + } + + let mut keymap_pk = KeyMapWrapper(HashMap::new(), secp); + + struct KeyMapWrapper<'a, C: secp256k1::Signing>(KeyMap, &'a secp256k1::Secp256k1<C>); + + impl<'a, C: secp256k1::Signing> Translator<String, DescriptorPublicKey, Error> + for KeyMapWrapper<'a, C> + { + fn pk(&mut self, pk: &String) -> Result<DescriptorPublicKey, Error> { + parse_key(pk, &mut self.0, self.1) + } + + fn sha256(&mut self, sha256: &String) -> Result<sha256::Hash, Error> { + let hash = + sha256::Hash::from_str(sha256).map_err(|e| Error::Unexpected(e.to_string()))?; + Ok(hash) + } + + fn hash256(&mut self, hash256: &String) -> Result<hash256::Hash, Error> { + let hash = hash256::Hash::from_str(hash256) + .map_err(|e| Error::Unexpected(e.to_string()))?; + Ok(hash) + } + + fn ripemd160(&mut self, ripemd160: &String) -> Result<ripemd160::Hash, Error> { + let hash = ripemd160::Hash::from_str(ripemd160) + .map_err(|e| Error::Unexpected(e.to_string()))?; + Ok(hash) + } + + fn hash160(&mut self, hash160: &String) -> Result<hash160::Hash, Error> { + let hash = hash160::Hash::from_str(hash160) + .map_err(|e| Error::Unexpected(e.to_string()))?; + Ok(hash) + } + } + + let descriptor = Descriptor::<String>::from_str(s)?; + let descriptor = descriptor.translate_pk(&mut keymap_pk).map_err(|e| { + Error::Unexpected( + e.expect_translator_err("No Outer context errors") + .to_string(), + ) + })?; + + Ok((descriptor, keymap_pk.0)) + } + + /// Serialize a descriptor to string with its secret keys + pub fn to_string_with_secret(&self, key_map: &KeyMap) -> String { + struct KeyMapLookUp<'a>(&'a KeyMap); + + impl<'a> Translator<DescriptorPublicKey, String, ()> for KeyMapLookUp<'a> { + fn pk(&mut self, pk: &DescriptorPublicKey) -> Result<String, ()> { + key_to_string(pk, self.0) + } + + fn sha256(&mut self, sha256: &sha256::Hash) -> Result<String, ()> { + Ok(sha256.to_string()) + } + + fn hash256(&mut self, hash256: &hash256::Hash) -> Result<String, ()> { + Ok(hash256.to_string()) + } + + fn ripemd160(&mut self, ripemd160: &ripemd160::Hash) -> Result<String, ()> { + Ok(ripemd160.to_string()) + } + + fn hash160(&mut self, hash160: &hash160::Hash) -> Result<String, ()> { + Ok(hash160.to_string()) + } + } + + fn key_to_string(pk: &DescriptorPublicKey, key_map: &KeyMap) -> Result<String, ()> { + Ok(match key_map.get(pk) { + Some(secret) => secret.to_string(), + None => pk.to_string(), + }) + } + + let descriptor = self + .translate_pk(&mut KeyMapLookUp(key_map)) + .expect("Translation to string cannot fail"); + + descriptor.to_string() + } + + /// Utility method for deriving the descriptor at each index in a range to find one matching + /// `script_pubkey`. + /// + /// If it finds a match then it returns the index it was derived at and the concrete + /// descriptor at that index. If the descriptor is non-derivable then it will simply check the + /// script pubkey against the descriptor and return it if it matches (in this case the index + /// returned will be meaningless). + pub fn find_derivation_index_for_spk<C: secp256k1::Verification>( + &self, + secp: &secp256k1::Secp256k1<C>, + script_pubkey: &Script, + range: Range<u32>, + ) -> Result<Option<(u32, Descriptor<bitcoin::PublicKey>)>, ConversionError> { + let range = if self.has_wildcard() { range } else { 0..1 }; + + for i in range { + let concrete = self.derived_descriptor(secp, i)?; + if &concrete.script_pubkey() == script_pubkey { + return Ok(Some((i, concrete))); + } + } + + Ok(None) + } + + /// Whether this descriptor contains a key that has multiple derivation paths. + pub fn is_multipath(&self) -> bool { + self.for_any_key(DescriptorPublicKey::is_multipath) + } + + /// Get as many descriptors as different paths in this descriptor. + /// + /// For multipath descriptors it will return as many descriptors as there is + /// "parallel" paths. For regular descriptors it will just return itself. + #[allow(clippy::blocks_in_if_conditions)] + pub fn into_single_descriptors(self) -> Result<Vec<Descriptor<DescriptorPublicKey>>, Error> { + // All single-path descriptors contained in this descriptor. + let mut descriptors = Vec::new(); + // We (ab)use `for_any_key` to gather the number of separate descriptors. + if !self.for_any_key(|key| { + // All multipath keys must have the same number of indexes at the "multi-index" + // step. So we can return early if we already populated the vector. + if !descriptors.is_empty() { + return true; + } + + match key { + DescriptorPublicKey::Single(..) | DescriptorPublicKey::XPub(..) => false, + DescriptorPublicKey::MultiXPub(xpub) => { + for _ in 0..xpub.derivation_paths.paths().len() { + descriptors.push(self.clone()); + } + true + } + } + }) { + // If there is no multipath key, return early. + return Ok(vec![self]); + } + assert!(!descriptors.is_empty()); + + // Now, transform the multipath key of each descriptor into a single-key using each index. + struct IndexChoser(usize); + impl Translator<DescriptorPublicKey, DescriptorPublicKey, Error> for IndexChoser { + fn pk(&mut self, pk: &DescriptorPublicKey) -> Result<DescriptorPublicKey, Error> { + match pk { + DescriptorPublicKey::Single(..) | DescriptorPublicKey::XPub(..) => { + Ok(pk.clone()) + } + DescriptorPublicKey::MultiXPub(_) => pk + .clone() + .into_single_keys() + .get(self.0) + .cloned() + .ok_or(Error::MultipathDescLenMismatch), + } + } + translate_hash_clone!(DescriptorPublicKey, DescriptorPublicKey, Error); + } + + for (i, desc) in descriptors.iter_mut().enumerate() { + let mut index_choser = IndexChoser(i); + *desc = desc + .translate_pk(&mut index_choser) + .map_err(|e| e.expect_translator_err("No Context errors possible"))?; + } + + Ok(descriptors) + } +} + +impl Descriptor<DefiniteDescriptorKey> { + /// Convert all the public keys in the descriptor to [`bitcoin::PublicKey`] by deriving them or + /// otherwise converting them. All [`bitcoin::secp256k1::XOnlyPublicKey`]s are converted to by adding a + /// default(0x02) y-coordinate. + /// + /// # Examples + /// + /// ``` + /// use miniscript::descriptor::{Descriptor, DescriptorPublicKey}; + /// use miniscript::bitcoin::secp256k1; + /// use std::str::FromStr; + /// + /// // test from bip 86 + /// let secp = secp256k1::Secp256k1::verification_only(); + /// let descriptor = Descriptor::<DescriptorPublicKey>::from_str("tr(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)") + /// .expect("Valid ranged descriptor"); + /// let result = descriptor.at_derivation_index(0).unwrap().derived_descriptor(&secp).expect("Non-hardened derivation"); + /// assert_eq!(result.to_string(), "tr(03cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115)#6qm9h8ym"); + /// ``` + /// + /// # Errors + /// + /// This function will return an error if hardened derivation is attempted. + pub fn derived_descriptor<C: secp256k1::Verification>( + &self, + secp: &secp256k1::Secp256k1<C>, + ) -> Result<Descriptor<bitcoin::PublicKey>, ConversionError> { + struct Derivator<'a, C: secp256k1::Verification>(&'a secp256k1::Secp256k1<C>); + + impl<'a, C: secp256k1::Verification> + Translator<DefiniteDescriptorKey, bitcoin::PublicKey, ConversionError> + for Derivator<'a, C> + { + fn pk( + &mut self, + pk: &DefiniteDescriptorKey, + ) -> Result<bitcoin::PublicKey, ConversionError> { + pk.derive_public_key(self.0) + } + + translate_hash_clone!(DefiniteDescriptorKey, bitcoin::PublicKey, ConversionError); + } + + let derived = self.translate_pk(&mut Derivator(secp)); + match derived { + Ok(derived) => Ok(derived), + Err(e) => Err(e.expect_translator_err("No Context errors when deriving keys")), + } + } +} diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index 83308e0dc..424e28b8c 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -294,17 +294,7 @@ impl fmt::Display for DescriptorPublicKey { }?; Ok(()) } - DescriptorPublicKey::XPub(ref xpub) => { - maybe_fmt_master_id(f, &xpub.origin)?; - xpub.xkey.fmt(f)?; - fmt_derivation_path(f, &xpub.derivation_path)?; - match xpub.wildcard { - Wildcard::None => {} - Wildcard::Unhardened => write!(f, "/*")?, - Wildcard::Hardened => write!(f, "/*h")?, - } - Ok(()) - } + DescriptorPublicKey::XPub(ref xpub) => xpub.fmt(f), DescriptorPublicKey::MultiXPub(ref xpub) => { maybe_fmt_master_id(f, &xpub.origin)?; xpub.xkey.fmt(f)?; @@ -456,12 +446,7 @@ impl FromStr for DescriptorPublicKey { wildcard, })) } else { - Ok(DescriptorPublicKey::XPub(DescriptorXKey { - origin, - xkey: xpub, - derivation_path: derivation_paths.into_iter().next().unwrap_or_default(), - wildcard, - })) + DescriptorXKey::<bip32::ExtendedPubKey>::from_str(s).map(Self::XPub) } } else { let key = match key_part.len() { @@ -525,17 +510,127 @@ impl error::Error for ConversionError { } } +impl MiniscriptKey for DescriptorXKey<bip32::ExtendedPubKey> { + type Sha256 = sha256::Hash; + type Hash256 = hash256::Hash; + type Ripemd160 = ripemd160::Hash; + type Hash160 = hash160::Hash; + + fn num_der_paths(&self) -> usize { + 1 + } +} + +impl DescriptorXKey<bip32::ExtendedPubKey> { + /// The fingerprint of the master key associated with this key, `0x00000000` if none. + pub fn master_fingerprint(&self) -> bip32::Fingerprint { + if let Some((fingerprint, _)) = self.origin { + fingerprint + } else { + self.xkey.fingerprint() + } + } + + /// Full path, from the master key + /// + /// For wildcard keys this will return the path up to the wildcard, so you + /// can get full paths by appending one additional derivation step, according + /// to the wildcard type (hardened or normal). + pub fn full_derivation_path(&self) -> bip32::DerivationPath { + let origin_path = if let Some((_, ref path)) = self.origin { + path.clone() + } else { + bip32::DerivationPath::from(vec![]) + }; + origin_path.extend(&self.derivation_path) + } + + /// Whether or not the key has a wildcard + pub fn has_wildcard(&self) -> bool { + self.wildcard != Wildcard::None + } + + /// Replaces any wildcard (i.e. `/*`) in the key with a particular derivation index, turning it into a + /// *definite* key (i.e. one where all the derivation paths are set). + /// + /// # Returns + /// + /// - If this key is not an xpub, returns `self`. + /// - If this key is an xpub but does not have a wildcard, returns `self`. + /// - Otherwise, returns the xpub at derivation `index` (removing the wildcard). + /// + /// # Errors + /// + /// - If `index` is hardened. + pub fn at_derivation_index(self, index: u32) -> Result<DefiniteDescriptorKey, ConversionError> { + let derivation_path = match self.wildcard { + Wildcard::None => self.derivation_path, + Wildcard::Unhardened => self.derivation_path.into_child( + bip32::ChildNumber::from_normal_idx(index) + .ok() + .ok_or(ConversionError::HardenedChild)?, + ), + Wildcard::Hardened => self.derivation_path.into_child( + bip32::ChildNumber::from_hardened_idx(index) + .ok() + .ok_or(ConversionError::HardenedChild)?, + ), + }; + let definite = DescriptorPublicKey::XPub(DescriptorXKey { + origin: self.origin, + xkey: self.xkey, + derivation_path, + wildcard: Wildcard::None, + }); + + Ok(DefiniteDescriptorKey::new(definite) + .expect("The key should not contain any wildcards at this point")) + } +} + +impl fmt::Display for DescriptorXKey<bip32::ExtendedPubKey> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + maybe_fmt_master_id(f, &self.origin)?; + self.xkey.fmt(f)?; + fmt_derivation_path(f, &self.derivation_path)?; + match self.wildcard { + Wildcard::None => {} + Wildcard::Unhardened => write!(f, "/*")?, + Wildcard::Hardened => write!(f, "/*h")?, + } + Ok(()) + } +} + +impl FromStr for DescriptorXKey<bip32::ExtendedPubKey> { + type Err = DescriptorKeyParseError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let (key_part, origin) = parse_key_origin(s)?; + + let (xpub, derivation_paths, wildcard) = + parse_xkey_deriv::<bip32::ExtendedPubKey>(key_part)?; + + if derivation_paths.len() > 1 { + return Err(DescriptorKeyParseError( + "Multiple derivation paths are not allowed for single extended keys", + )); + } + + Ok(Self { + origin, + xkey: xpub, + derivation_path: derivation_paths.into_iter().next().unwrap_or_default(), + wildcard, + }) + } +} + impl DescriptorPublicKey { /// The fingerprint of the master key associated with this key, `0x00000000` if none. pub fn master_fingerprint(&self) -> bip32::Fingerprint { match *self { - DescriptorPublicKey::XPub(ref xpub) => { - if let Some((fingerprint, _)) = xpub.origin { - fingerprint - } else { - xpub.xkey.fingerprint() - } - } + DescriptorPublicKey::XPub(ref xpub) => xpub.master_fingerprint(), DescriptorPublicKey::MultiXPub(ref xpub) => { if let Some((fingerprint, _)) = xpub.origin { fingerprint @@ -573,14 +668,7 @@ impl DescriptorPublicKey { /// For multipath extended keys, this returns `None`. pub fn full_derivation_path(&self) -> Option<bip32::DerivationPath> { match *self { - DescriptorPublicKey::XPub(ref xpub) => { - let origin_path = if let Some((_, ref path)) = xpub.origin { - path.clone() - } else { - bip32::DerivationPath::from(vec![]) - }; - Some(origin_path.extend(&xpub.derivation_path)) - } + DescriptorPublicKey::XPub(ref xpub) => Some(xpub.full_derivation_path()), DescriptorPublicKey::Single(ref single) => { Some(if let Some((_, ref path)) = single.origin { path.clone() @@ -602,7 +690,7 @@ impl DescriptorPublicKey { pub fn has_wildcard(&self) -> bool { match *self { DescriptorPublicKey::Single(..) => false, - DescriptorPublicKey::XPub(ref xpub) => xpub.wildcard != Wildcard::None, + DescriptorPublicKey::XPub(ref xpub) => xpub.has_wildcard(), DescriptorPublicKey::MultiXPub(ref xpub) => xpub.wildcard != Wildcard::None, } } @@ -628,27 +716,7 @@ impl DescriptorPublicKey { pub fn at_derivation_index(self, index: u32) -> Result<DefiniteDescriptorKey, ConversionError> { let definite = match self { DescriptorPublicKey::Single(_) => self, - DescriptorPublicKey::XPub(xpub) => { - let derivation_path = match xpub.wildcard { - Wildcard::None => xpub.derivation_path, - Wildcard::Unhardened => xpub.derivation_path.into_child( - bip32::ChildNumber::from_normal_idx(index) - .ok() - .ok_or(ConversionError::HardenedChild)?, - ), - Wildcard::Hardened => xpub.derivation_path.into_child( - bip32::ChildNumber::from_hardened_idx(index) - .ok() - .ok_or(ConversionError::HardenedChild)?, - ), - }; - DescriptorPublicKey::XPub(DescriptorXKey { - origin: xpub.origin, - xkey: xpub.xkey, - derivation_path, - wildcard: Wildcard::None, - }) - } + DescriptorPublicKey::XPub(xpub) => return xpub.at_derivation_index(index), DescriptorPublicKey::MultiXPub(_) => return Err(ConversionError::MultiKey), }; diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 7551e1ad4..f19eb454b 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -12,29 +12,30 @@ //! use core::fmt; -use core::ops::Range; -use core::str::{self, FromStr}; +use core::str::{self}; use bitcoin::address::WitnessVersion; -use bitcoin::hashes::{hash160, ripemd160, sha256}; -use bitcoin::{secp256k1, Address, Network, Script, ScriptBuf, TxIn, Witness}; +use bitcoin::{Address, Network, ScriptBuf, TxIn, Witness}; use sync::Arc; use self::checksum::verify_checksum; use crate::miniscript::{Legacy, Miniscript, Segwitv0}; use crate::prelude::*; use crate::{ - expression, hash256, miniscript, BareCtx, Error, ForEachKey, MiniscriptKey, Satisfier, - ToPublicKey, TranslateErr, TranslatePk, Translator, + expression, miniscript, BareCtx, Error, ForEachKey, MiniscriptKey, Satisfier, ToPublicKey, + TranslateErr, TranslatePk, Translator, }; mod bare; +mod descriptor_impl; mod segwitv0; mod sh; mod sortedmulti; mod tr; // Descriptor Exports +pub use descriptor_impl::KeyMap; + pub use self::bare::{Bare, Pkh}; pub use self::segwitv0::{Wpkh, Wsh, WshInner}; pub use self::sh::{Sh, ShInner}; @@ -50,14 +51,6 @@ pub use self::key::{ SinglePriv, SinglePub, SinglePubKey, Wildcard, }; -/// Alias type for a map of public key to secret key -/// -/// This map is returned whenever a descriptor that contains secrets is parsed using -/// [`Descriptor::parse_descriptor`], since the descriptor will always only contain -/// public keys. This map allows looking up the corresponding secret key given a -/// public key from the descriptor. -pub type KeyMap = HashMap<DescriptorPublicKey, DescriptorSecretKey>; - /// Script descriptor #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Descriptor<Pk: MiniscriptKey> { @@ -547,345 +540,6 @@ impl<Pk: MiniscriptKey> ForEachKey<Pk> for Descriptor<Pk> { } } -impl Descriptor<DescriptorPublicKey> { - /// Whether or not the descriptor has any wildcards - #[deprecated(note = "use has_wildcards instead")] - pub fn is_deriveable(&self) -> bool { - self.has_wildcard() - } - - /// Whether or not the descriptor has any wildcards i.e. `/*`. - pub fn has_wildcard(&self) -> bool { - self.for_any_key(|key| key.has_wildcard()) - } - - /// Replaces all wildcards (i.e. `/*`) in the descriptor with a particular derivation index, - /// turning it into a *definite* descriptor. - /// - /// # Errors - /// - If index ≥ 2^31 - pub fn at_derivation_index( - &self, - index: u32, - ) -> Result<Descriptor<DefiniteDescriptorKey>, ConversionError> { - struct Derivator(u32); - - impl Translator<DescriptorPublicKey, DefiniteDescriptorKey, ConversionError> for Derivator { - fn pk( - &mut self, - pk: &DescriptorPublicKey, - ) -> Result<DefiniteDescriptorKey, ConversionError> { - pk.clone().at_derivation_index(self.0) - } - - translate_hash_clone!(DescriptorPublicKey, DescriptorPublicKey, ConversionError); - } - self.translate_pk(&mut Derivator(index)) - .map_err(|e| e.expect_translator_err("No Context errors while translating")) - } - - #[deprecated(note = "use at_derivation_index instead")] - /// Deprecated name for [`Self::at_derivation_index`]. - pub fn derive(&self, index: u32) -> Result<Descriptor<DefiniteDescriptorKey>, ConversionError> { - self.at_derivation_index(index) - } - - /// Convert all the public keys in the descriptor to [`bitcoin::PublicKey`] by deriving them or - /// otherwise converting them. All [`bitcoin::secp256k1::XOnlyPublicKey`]s are converted to by adding a - /// default(0x02) y-coordinate. - /// - /// This is a shorthand for: - /// - /// ``` - /// # use miniscript::{Descriptor, DescriptorPublicKey, bitcoin::secp256k1::Secp256k1}; - /// # use core::str::FromStr; - /// # let descriptor = Descriptor::<DescriptorPublicKey>::from_str("tr(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)") - /// .expect("Valid ranged descriptor"); - /// # let index = 42; - /// # let secp = Secp256k1::verification_only(); - /// let derived_descriptor = descriptor.at_derivation_index(index).unwrap().derived_descriptor(&secp).unwrap(); - /// # assert_eq!(descriptor.derived_descriptor(&secp, index).unwrap(), derived_descriptor); - /// ``` - /// - /// and is only here really here for backwards compatbility. - /// See [`at_derivation_index`] and `[derived_descriptor`] for more documentation. - /// - /// [`at_derivation_index`]: Self::at_derivation_index - /// [`derived_descriptor`]: crate::DerivedDescriptor::derived_descriptor - /// - /// # Errors - /// - /// This function will return an error if hardened derivation is attempted. - pub fn derived_descriptor<C: secp256k1::Verification>( - &self, - secp: &secp256k1::Secp256k1<C>, - index: u32, - ) -> Result<Descriptor<bitcoin::PublicKey>, ConversionError> { - self.at_derivation_index(index)?.derived_descriptor(secp) - } - - /// Parse a descriptor that may contain secret keys - /// - /// Internally turns every secret key found into the corresponding public key and then returns a - /// a descriptor that only contains public keys and a map to lookup the secret key given a public key. - pub fn parse_descriptor<C: secp256k1::Signing>( - secp: &secp256k1::Secp256k1<C>, - s: &str, - ) -> Result<(Descriptor<DescriptorPublicKey>, KeyMap), Error> { - fn parse_key<C: secp256k1::Signing>( - s: &str, - key_map: &mut KeyMap, - secp: &secp256k1::Secp256k1<C>, - ) -> Result<DescriptorPublicKey, Error> { - let (public_key, secret_key) = match DescriptorSecretKey::from_str(s) { - Ok(sk) => ( - sk.to_public(secp) - .map_err(|e| Error::Unexpected(e.to_string()))?, - Some(sk), - ), - Err(_) => ( - DescriptorPublicKey::from_str(s) - .map_err(|e| Error::Unexpected(e.to_string()))?, - None, - ), - }; - - if let Some(secret_key) = secret_key { - key_map.insert(public_key.clone(), secret_key); - } - - Ok(public_key) - } - - let mut keymap_pk = KeyMapWrapper(HashMap::new(), secp); - - struct KeyMapWrapper<'a, C: secp256k1::Signing>(KeyMap, &'a secp256k1::Secp256k1<C>); - - impl<'a, C: secp256k1::Signing> Translator<String, DescriptorPublicKey, Error> - for KeyMapWrapper<'a, C> - { - fn pk(&mut self, pk: &String) -> Result<DescriptorPublicKey, Error> { - parse_key(pk, &mut self.0, self.1) - } - - fn sha256(&mut self, sha256: &String) -> Result<sha256::Hash, Error> { - let hash = - sha256::Hash::from_str(sha256).map_err(|e| Error::Unexpected(e.to_string()))?; - Ok(hash) - } - - fn hash256(&mut self, hash256: &String) -> Result<hash256::Hash, Error> { - let hash = hash256::Hash::from_str(hash256) - .map_err(|e| Error::Unexpected(e.to_string()))?; - Ok(hash) - } - - fn ripemd160(&mut self, ripemd160: &String) -> Result<ripemd160::Hash, Error> { - let hash = ripemd160::Hash::from_str(ripemd160) - .map_err(|e| Error::Unexpected(e.to_string()))?; - Ok(hash) - } - - fn hash160(&mut self, hash160: &String) -> Result<hash160::Hash, Error> { - let hash = hash160::Hash::from_str(hash160) - .map_err(|e| Error::Unexpected(e.to_string()))?; - Ok(hash) - } - } - - let descriptor = Descriptor::<String>::from_str(s)?; - let descriptor = descriptor.translate_pk(&mut keymap_pk).map_err(|e| { - Error::Unexpected( - e.expect_translator_err("No Outer context errors") - .to_string(), - ) - })?; - - Ok((descriptor, keymap_pk.0)) - } - - /// Serialize a descriptor to string with its secret keys - pub fn to_string_with_secret(&self, key_map: &KeyMap) -> String { - struct KeyMapLookUp<'a>(&'a KeyMap); - - impl<'a> Translator<DescriptorPublicKey, String, ()> for KeyMapLookUp<'a> { - fn pk(&mut self, pk: &DescriptorPublicKey) -> Result<String, ()> { - key_to_string(pk, self.0) - } - - fn sha256(&mut self, sha256: &sha256::Hash) -> Result<String, ()> { - Ok(sha256.to_string()) - } - - fn hash256(&mut self, hash256: &hash256::Hash) -> Result<String, ()> { - Ok(hash256.to_string()) - } - - fn ripemd160(&mut self, ripemd160: &ripemd160::Hash) -> Result<String, ()> { - Ok(ripemd160.to_string()) - } - - fn hash160(&mut self, hash160: &hash160::Hash) -> Result<String, ()> { - Ok(hash160.to_string()) - } - } - - fn key_to_string(pk: &DescriptorPublicKey, key_map: &KeyMap) -> Result<String, ()> { - Ok(match key_map.get(pk) { - Some(secret) => secret.to_string(), - None => pk.to_string(), - }) - } - - let descriptor = self - .translate_pk(&mut KeyMapLookUp(key_map)) - .expect("Translation to string cannot fail"); - - descriptor.to_string() - } - - /// Utility method for deriving the descriptor at each index in a range to find one matching - /// `script_pubkey`. - /// - /// If it finds a match then it returns the index it was derived at and the concrete - /// descriptor at that index. If the descriptor is non-derivable then it will simply check the - /// script pubkey against the descriptor and return it if it matches (in this case the index - /// returned will be meaningless). - pub fn find_derivation_index_for_spk<C: secp256k1::Verification>( - &self, - secp: &secp256k1::Secp256k1<C>, - script_pubkey: &Script, - range: Range<u32>, - ) -> Result<Option<(u32, Descriptor<bitcoin::PublicKey>)>, ConversionError> { - let range = if self.has_wildcard() { range } else { 0..1 }; - - for i in range { - let concrete = self.derived_descriptor(secp, i)?; - if &concrete.script_pubkey() == script_pubkey { - return Ok(Some((i, concrete))); - } - } - - Ok(None) - } - - /// Whether this descriptor contains a key that has multiple derivation paths. - pub fn is_multipath(&self) -> bool { - self.for_any_key(DescriptorPublicKey::is_multipath) - } - - /// Get as many descriptors as different paths in this descriptor. - /// - /// For multipath descriptors it will return as many descriptors as there is - /// "parallel" paths. For regular descriptors it will just return itself. - #[allow(clippy::blocks_in_if_conditions)] - pub fn into_single_descriptors(self) -> Result<Vec<Descriptor<DescriptorPublicKey>>, Error> { - // All single-path descriptors contained in this descriptor. - let mut descriptors = Vec::new(); - // We (ab)use `for_any_key` to gather the number of separate descriptors. - if !self.for_any_key(|key| { - // All multipath keys must have the same number of indexes at the "multi-index" - // step. So we can return early if we already populated the vector. - if !descriptors.is_empty() { - return true; - } - - match key { - DescriptorPublicKey::Single(..) | DescriptorPublicKey::XPub(..) => false, - DescriptorPublicKey::MultiXPub(xpub) => { - for _ in 0..xpub.derivation_paths.paths().len() { - descriptors.push(self.clone()); - } - true - } - } - }) { - // If there is no multipath key, return early. - return Ok(vec![self]); - } - assert!(!descriptors.is_empty()); - - // Now, transform the multipath key of each descriptor into a single-key using each index. - struct IndexChoser(usize); - impl Translator<DescriptorPublicKey, DescriptorPublicKey, Error> for IndexChoser { - fn pk(&mut self, pk: &DescriptorPublicKey) -> Result<DescriptorPublicKey, Error> { - match pk { - DescriptorPublicKey::Single(..) | DescriptorPublicKey::XPub(..) => { - Ok(pk.clone()) - } - DescriptorPublicKey::MultiXPub(_) => pk - .clone() - .into_single_keys() - .get(self.0) - .cloned() - .ok_or(Error::MultipathDescLenMismatch), - } - } - translate_hash_clone!(DescriptorPublicKey, DescriptorPublicKey, Error); - } - - for (i, desc) in descriptors.iter_mut().enumerate() { - let mut index_choser = IndexChoser(i); - *desc = desc - .translate_pk(&mut index_choser) - .map_err(|e| e.expect_translator_err("No Context errors possible"))?; - } - - Ok(descriptors) - } -} - -impl Descriptor<DefiniteDescriptorKey> { - /// Convert all the public keys in the descriptor to [`bitcoin::PublicKey`] by deriving them or - /// otherwise converting them. All [`bitcoin::secp256k1::XOnlyPublicKey`]s are converted to by adding a - /// default(0x02) y-coordinate. - /// - /// # Examples - /// - /// ``` - /// use miniscript::descriptor::{Descriptor, DescriptorPublicKey}; - /// use miniscript::bitcoin::secp256k1; - /// use std::str::FromStr; - /// - /// // test from bip 86 - /// let secp = secp256k1::Secp256k1::verification_only(); - /// let descriptor = Descriptor::<DescriptorPublicKey>::from_str("tr(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)") - /// .expect("Valid ranged descriptor"); - /// let result = descriptor.at_derivation_index(0).unwrap().derived_descriptor(&secp).expect("Non-hardened derivation"); - /// assert_eq!(result.to_string(), "tr(03cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115)#6qm9h8ym"); - /// ``` - /// - /// # Errors - /// - /// This function will return an error if hardened derivation is attempted. - pub fn derived_descriptor<C: secp256k1::Verification>( - &self, - secp: &secp256k1::Secp256k1<C>, - ) -> Result<Descriptor<bitcoin::PublicKey>, ConversionError> { - struct Derivator<'a, C: secp256k1::Verification>(&'a secp256k1::Secp256k1<C>); - - impl<'a, C: secp256k1::Verification> - Translator<DefiniteDescriptorKey, bitcoin::PublicKey, ConversionError> - for Derivator<'a, C> - { - fn pk( - &mut self, - pk: &DefiniteDescriptorKey, - ) -> Result<bitcoin::PublicKey, ConversionError> { - pk.derive_public_key(self.0) - } - - translate_hash_clone!(DefiniteDescriptorKey, bitcoin::PublicKey, ConversionError); - } - - let derived = self.translate_pk(&mut Derivator(secp)); - match derived { - Ok(derived) => Ok(derived), - Err(e) => Err(e.expect_translator_err("No Context errors when deriving keys")), - } - } -} - impl_from_tree!( Descriptor<Pk>, /// Parse an expression tree into a descriptor. @@ -969,7 +623,9 @@ mod tests { use crate::descriptor::{DescriptorPublicKey, DescriptorXKey, SinglePub}; #[cfg(feature = "compiler")] use crate::policy; - use crate::{hex_script, Descriptor, Error, Miniscript, Satisfier}; + use crate::{ + hex_script, Descriptor, Error, Miniscript, MsDescriptor, MsDescriptorXPubOnly, Satisfier, + }; type StdDescriptor = Descriptor<PublicKey>; const TEST_PK: &str = "pk(020000000000000000000000000000000000000000000000000000000000000002)"; @@ -1690,6 +1346,39 @@ mod tests { assert_eq!(format!("{}", expected), desc); } + #[test] + fn test_extended_only_descriptor() { + fn _test_xpub_desc(raw_desc: &str, raw_addr_expected: &str) { + let secp = secp256k1::Secp256k1::verification_only(); + let index = 5; + + // Parse descriptor + let desc = MsDescriptor::from_str(raw_desc).unwrap(); + let desc_xpub_only = MsDescriptorXPubOnly::from_str(raw_desc).unwrap(); + + // Same string formatting + assert_eq!(desc.to_string(), raw_desc); + assert_eq!(desc_xpub_only.to_string(), raw_desc); + + // Same address + let addr_one = desc + .derived_descriptor(&secp, index) + .unwrap() + .address(bitcoin::Network::Bitcoin) + .unwrap(); + let addr_two = desc_xpub_only + .derived_descriptor(&secp, index) + .unwrap() + .address(bitcoin::Network::Bitcoin) + .unwrap(); + let addr_expected = bitcoin::Address::from_str(raw_addr_expected) + .unwrap() + .assume_checked(); + assert_eq!(addr_one, addr_expected); + assert_eq!(addr_two, addr_expected); + } + } + #[test] fn test_sortedmulti() { fn _test_sortedmulti(raw_desc_one: &str, raw_desc_two: &str, raw_addr_expected: &str) { diff --git a/src/lib.rs b/src/lib.rs index 7a51f1405..5db44244f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -118,6 +118,8 @@ mod macros; #[macro_use] mod pub_macros; +use bitcoin::bip32; +use descriptor::DescriptorXKey; use internals::hex::exts::DisplayHex; pub use pub_macros::*; @@ -150,6 +152,23 @@ pub use crate::miniscript::satisfy::{Preimage32, Satisfier}; pub use crate::miniscript::{hash256, Miniscript}; use crate::prelude::*; +/// Output descriptor supporting full capabilities of Miniscript as well as all BIPs +/// from BIP380-386. This is the recommended descriptor type to use if you want to +/// support all the features of Miniscript as well full descriptor support. +pub type MsDescriptor = Descriptor<DescriptorPublicKey>; + +/// They key type that supports parsing only extended public keys. +pub type XPubOnly = DescriptorXKey<bip32::ExtendedPubKey>; +/// Output descriptor supporting all the features of Miniscript, but only supports +/// extended public keys. +/// +/// In particular, as of 0.11.0, this descriptor type does not support the following: +/// - Multi-path descriptors +/// - Single keys in descriptor without derivation paths +/// +/// Wallet developers might want to use this descriptor type for ergonomic reasons +/// if they are **only** interested in supporting extended public keys. +pub type MsDescriptorXPubOnly = Descriptor<XPubOnly>; ///Public key trait which can be converted to Hash type pub trait MiniscriptKey: Clone + Eq + Ord + fmt::Debug + fmt::Display + hash::Hash { /// Returns true if the pubkey is uncompressed. Defaults to `false`.