From c17965a97c71032d5a0718d59d766b83c6b1762f Mon Sep 17 00:00:00 2001 From: Harshil Jani Date: Fri, 16 Jun 2023 03:47:31 +0530 Subject: [PATCH 1/2] Add method to convert expr_raw_pkh into pkh The commit adds up the method to convert the expr_raw_pkh into pkh by looking at the available keys and their hases being stored inside of the Hashmap of PSBT Input. If the key is found corresponding to given hash, It will update to pkh. Signed-off-by: Harshil Jani --- src/miniscript/astelem.rs | 69 +++++++++++++++++++++++++++++++++++++++ src/miniscript/mod.rs | 6 ++++ src/psbt/finalizer.rs | 24 ++++++++++++-- 3 files changed, 96 insertions(+), 3 deletions(-) diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs index d0388554c..8ccf2ab5a 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -179,6 +179,75 @@ impl Terminal { }; Ok(frag) } + + /// Substitutes raw public keys hashes with the public keys as provided by map. + pub fn substitute_raw_pkh(&self, pk_map: &HashMap) -> Terminal { + match self { + Terminal::RawPkH(ref p) => match pk_map.get(p) { + Some(pk) => Terminal::PkH(pk.clone()).into(), + None => Terminal::RawPkH(*p).into(), + }, + Terminal::PkK(..) + | Terminal::PkH(..) + | Terminal::Multi(..) + | Terminal::MultiA(..) + | Terminal::After(..) + | Terminal::Older(..) + | Terminal::Sha256(..) + | Terminal::Hash256(..) + | Terminal::Ripemd160(..) + | Terminal::Hash160(..) + | Terminal::True + | Terminal::False => self.clone().into(), + Terminal::Alt(ref sub) => Terminal::Alt(Arc::new(sub.substitute_raw_pkh(pk_map))), + Terminal::Swap(ref sub) => Terminal::Swap(Arc::new(sub.substitute_raw_pkh(pk_map))), + Terminal::Check(ref sub) => Terminal::Check(Arc::new(sub.substitute_raw_pkh(pk_map))), + Terminal::DupIf(ref sub) => Terminal::DupIf(Arc::new(sub.substitute_raw_pkh(pk_map))), + Terminal::Verify(ref sub) => Terminal::Verify(Arc::new(sub.substitute_raw_pkh(pk_map))), + Terminal::NonZero(ref sub) => { + Terminal::NonZero(Arc::new(sub.substitute_raw_pkh(pk_map))) + } + Terminal::ZeroNotEqual(ref sub) => { + Terminal::ZeroNotEqual(Arc::new(sub.substitute_raw_pkh(pk_map))) + } + Terminal::AndV(ref left, ref right) => Terminal::AndV( + Arc::new(left.substitute_raw_pkh(pk_map)), + Arc::new(right.substitute_raw_pkh(pk_map)), + ), + Terminal::AndB(ref left, ref right) => Terminal::AndB( + Arc::new(left.substitute_raw_pkh(pk_map)), + Arc::new(right.substitute_raw_pkh(pk_map)), + ), + Terminal::AndOr(ref a, ref b, ref c) => Terminal::AndOr( + Arc::new(a.substitute_raw_pkh(pk_map)), + Arc::new(b.substitute_raw_pkh(pk_map)), + Arc::new(c.substitute_raw_pkh(pk_map)), + ), + Terminal::OrB(ref left, ref right) => Terminal::OrB( + Arc::new(left.substitute_raw_pkh(pk_map)), + Arc::new(right.substitute_raw_pkh(pk_map)), + ), + Terminal::OrD(ref left, ref right) => Terminal::OrD( + Arc::new(left.substitute_raw_pkh(pk_map)), + Arc::new(right.substitute_raw_pkh(pk_map)), + ), + Terminal::OrC(ref left, ref right) => Terminal::OrC( + Arc::new(left.substitute_raw_pkh(pk_map)), + Arc::new(right.substitute_raw_pkh(pk_map)), + ), + Terminal::OrI(ref left, ref right) => Terminal::OrI( + Arc::new(left.substitute_raw_pkh(pk_map)), + Arc::new(right.substitute_raw_pkh(pk_map)), + ), + Terminal::Thresh(k, ref subs) => { + let subs: Vec>> = subs + .iter() + .map(|s| Arc::new(s.substitute_raw_pkh(pk_map))) + .collect(); + Terminal::Thresh(*k, subs) + } + } + } } impl ForEachKey for Terminal { diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index c73a7bd4e..31da8be61 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -16,6 +16,7 @@ use core::marker::PhantomData; use core::{fmt, hash, str}; +use bitcoin::hashes::hash160; use bitcoin::script; use bitcoin::taproot::{LeafVersion, TapLeafHash}; @@ -334,6 +335,11 @@ impl Miniscript { let inner = self.node.real_translate_pk(t)?; Miniscript::from_ast(inner).map_err(TranslateErr::OuterError) } + + /// Substitutes raw public keys hashes with the public keys as provided by map. + pub fn substitute_raw_pkh(&self, pk_map: &HashMap) -> Miniscript { + Miniscript::from_ast(self.node.substitute_raw_pkh(pk_map)).expect("type check failed") + } } impl_block_str!( diff --git a/src/psbt/finalizer.rs b/src/psbt/finalizer.rs index c0bf447c9..6b84407ab 100644 --- a/src/psbt/finalizer.rs +++ b/src/psbt/finalizer.rs @@ -8,11 +8,13 @@ //! `https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki` //! +use bitcoin::hashes::hash160; use bitcoin::key::XOnlyPublicKey; use bitcoin::secp256k1::{self, Secp256k1}; use bitcoin::sighash::Prevouts; use bitcoin::taproot::LeafVersion; use bitcoin::{PublicKey, Script, ScriptBuf, TxOut, Witness}; +use std::collections::HashMap; use super::{sanity_check, Error, InputError, Psbt, PsbtInputSatisfier}; use crate::prelude::*; @@ -122,6 +124,22 @@ pub(super) fn prevouts(psbt: &Psbt) -> Result, super::Error // we want to move the script is probably already created // and we want to satisfy it in any way possible. fn get_descriptor(psbt: &Psbt, index: usize) -> Result, InputError> { + // Create a HashMap + let mut hash_map: HashMap = HashMap::new(); + let psbt_inputs = &psbt.inputs; + for psbt_input in psbt_inputs { + // Use BIP32 Derviation to get set of all possible keys. + let public_keys = psbt_input.bip32_derivation.keys(); + for key in public_keys { + // Convert bitcoin::secp256k1::PublicKey into just bitcoin::PublicKey + let bitcoin_key = bitcoin::PublicKey::new(*key); + // Convert PubKeyHash into Hash::hash160 + let hash = bitcoin_key.pubkey_hash().to_raw_hash(); + // Insert pair in HashMap + hash_map.insert(hash, bitcoin_key); + } + } + // Figure out Scriptpubkey let script_pubkey = get_scriptpubkey(psbt, index)?; let inp = &psbt.inputs[index]; @@ -178,7 +196,7 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In witness_script, &ExtParams::allow_all(), )?; - Ok(Descriptor::new_wsh(ms)?) + Ok(Descriptor::new_wsh(ms.substitute_raw_pkh(&hash_map))?) } else { Err(InputError::MissingWitnessScript) } @@ -205,7 +223,7 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In witness_script, &ExtParams::allow_all(), )?; - Ok(Descriptor::new_sh_wsh(ms)?) + Ok(Descriptor::new_sh_wsh(ms.substitute_raw_pkh(&hash_map))?) } else { Err(InputError::MissingWitnessScript) } @@ -249,7 +267,7 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In &script_pubkey, &ExtParams::allow_all(), )?; - Ok(Descriptor::new_bare(ms)?) + Ok(Descriptor::new_bare(ms.substitute_raw_pkh(&hash_map))?) } } From 2f3e457fd21a022db2521280542fd74b624ccc9a Mon Sep 17 00:00:00 2001 From: Harshil Jani Date: Tue, 20 Jun 2023 00:07:21 +0530 Subject: [PATCH 2/2] Using BTreeMap in place of HashMap Signed-off-by: Harshil Jani --- src/miniscript/astelem.rs | 2 +- src/miniscript/mod.rs | 2 +- src/psbt/finalizer.rs | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs index 8ccf2ab5a..62dddf633 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -181,7 +181,7 @@ impl Terminal { } /// Substitutes raw public keys hashes with the public keys as provided by map. - pub fn substitute_raw_pkh(&self, pk_map: &HashMap) -> Terminal { + pub fn substitute_raw_pkh(&self, pk_map: &BTreeMap) -> Terminal { match self { Terminal::RawPkH(ref p) => match pk_map.get(p) { Some(pk) => Terminal::PkH(pk.clone()).into(), diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 31da8be61..c31199d6b 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -337,7 +337,7 @@ impl Miniscript { } /// Substitutes raw public keys hashes with the public keys as provided by map. - pub fn substitute_raw_pkh(&self, pk_map: &HashMap) -> Miniscript { + pub fn substitute_raw_pkh(&self, pk_map: &BTreeMap) -> Miniscript { Miniscript::from_ast(self.node.substitute_raw_pkh(pk_map)).expect("type check failed") } } diff --git a/src/psbt/finalizer.rs b/src/psbt/finalizer.rs index 6b84407ab..28902cc36 100644 --- a/src/psbt/finalizer.rs +++ b/src/psbt/finalizer.rs @@ -14,7 +14,6 @@ use bitcoin::secp256k1::{self, Secp256k1}; use bitcoin::sighash::Prevouts; use bitcoin::taproot::LeafVersion; use bitcoin::{PublicKey, Script, ScriptBuf, TxOut, Witness}; -use std::collections::HashMap; use super::{sanity_check, Error, InputError, Psbt, PsbtInputSatisfier}; use crate::prelude::*; @@ -125,7 +124,7 @@ pub(super) fn prevouts(psbt: &Psbt) -> Result, super::Error // and we want to satisfy it in any way possible. fn get_descriptor(psbt: &Psbt, index: usize) -> Result, InputError> { // Create a HashMap - let mut hash_map: HashMap = HashMap::new(); + let mut hash_map: BTreeMap = BTreeMap::new(); let psbt_inputs = &psbt.inputs; for psbt_input in psbt_inputs { // Use BIP32 Derviation to get set of all possible keys.