From 816bf94f57ff51a6937c14153c9a9828fbefbb37 Mon Sep 17 00:00:00 2001 From: Alekos Filini Date: Sun, 4 Dec 2022 07:53:39 +0100 Subject: [PATCH] [wip] Remove explicit signatures from `Assets` Instead of storing keys and signatures in the `Assets` struct, only store keys with extra conditions on how the key can sign --- src/descriptor/tr.rs | 11 +- src/miniscript/satisfy.rs | 187 ++++++++++---------------------- src/plan.rs | 221 ++++++++++++++++++++++++++++---------- src/util.rs | 15 +-- 4 files changed, 233 insertions(+), 201 deletions(-) diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index d00563dda..9c866386e 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -14,7 +14,9 @@ use sync::Arc; use super::checksum::{self, verify_checksum}; use crate::descriptor::{DefiniteDescriptorKey, DescriptorType}; use crate::expression::{self, FromTree}; -use crate::miniscript::satisfy::{Placeholder, Satisfaction, Witness, WitnessTemplate}; +use crate::miniscript::satisfy::{ + Placeholder, Satisfaction, SchnorrSigType, Witness, WitnessTemplate, +}; use crate::miniscript::Miniscript; use crate::plan::{AssetProvider, Plan}; use crate::policy::semantic::Policy; @@ -656,11 +658,14 @@ where { let spend_info = desc.spend_info(); // First try the key spend path - if provider.lookup_tap_key_spend_sig(&desc.internal_key) { + if let Some(size) = provider.lookup_tap_key_spend_sig(&desc.internal_key) { Satisfaction { stack: Witness::Stack(vec![Placeholder::SchnorrSig( desc.internal_key.clone(), - None, + SchnorrSigType::KeySpend { + merkle_root: spend_info.merkle_root(), + }, + size, )]), has_sig: true, absolute_timelock: None, diff --git a/src/miniscript/satisfy.rs b/src/miniscript/satisfy.rs index 17878ff24..4f3f50fa9 100644 --- a/src/miniscript/satisfy.rs +++ b/src/miniscript/satisfy.rs @@ -22,13 +22,13 @@ use core::{cmp, fmt, i64, mem}; use bitcoin::hashes::hash160; use bitcoin::secp256k1::XOnlyPublicKey; -use bitcoin::util::taproot::{ControlBlock, LeafVersion, TapLeafHash}; +use bitcoin::util::taproot::{ControlBlock, LeafVersion, TapBranchHash, TapLeafHash}; use bitcoin::{LockTime, PackedLockTime, Script, Sequence}; use sync::Arc; use super::context::SigType; use crate::descriptor::DescriptorType; -use crate::plan::{AssetProvider, Plan, RequiredPreimage, RequiredSig}; +use crate::plan::{AssetProvider, Plan}; use crate::prelude::*; use crate::util::witness_size; use crate::{ @@ -530,6 +530,21 @@ impl_tuple_satisfier!(A, B, C, D, E, F); impl_tuple_satisfier!(A, B, C, D, E, F, G); impl_tuple_satisfier!(A, B, C, D, E, F, G, H); +#[derive(Debug, Clone, PartialEq, Eq)] +/// Type of schnorr signature to produce +pub enum SchnorrSigType { + /// Key spend signature + KeySpend { + /// Merkle root to tweak the key, if present + merkle_root: Option, + }, + /// Script spend signature + ScriptSpend { + /// Leaf hash of the script + leaf_hash: TapLeafHash, + }, +} + #[derive(Debug, Clone, PartialEq, Eq)] /// Placeholder for some data in a [`WitnessTemplate`] pub enum Placeholder { @@ -541,10 +556,10 @@ pub enum Placeholder { EcdsaSigPk(Pk), /// ECDSA signature given the pubkey hash EcdsaSigHash(hash160::Hash), - /// Schnorr signature - SchnorrSig(Pk, Option), - /// Schnorr signature given the pubkey hash and the leaf hash - SchnorrSigHash(hash160::Hash, TapLeafHash), + /// Schnorr signature and its size + SchnorrSig(Pk, SchnorrSigType, usize), + /// Schnorr signature given the pubkey hash and the leaf hash, plus its size + SchnorrSigHash(hash160::Hash, TapLeafHash, usize), /// SHA-256 preimage Sha256Preimage(Pk::Sha256), /// HASH256 preimage @@ -575,12 +590,16 @@ impl fmt::Display for Placeholder { PubkeyHash(pkh, size) => write!(f, "PubkeyHash(pkh: {}, size: {})", pkh, size), EcdsaSigPk(pk) => write!(f, "EcdsaSigPk(pk: {})", pk), EcdsaSigHash(hash) => write!(f, "EcdsaSigHash(hash: {})", hash), - SchnorrSig(pk, tap_leaf_hash) => write!( + SchnorrSig(pk, tap_leaf_hash, size) => write!( f, - "SchnorrSig(pk: {}, tap_leaf_hash: {:?})", - pk, tap_leaf_hash + "SchnorrSig(pk: {}, tap_leaf_hash: {:?}, size: {})", + pk, tap_leaf_hash, size + ), + SchnorrSigHash(pkh, lh, size) => write!( + f, + "SchnorrSigHash(pkh: {}, leaf_hash: {}, size: {})", + pkh, lh, size ), - SchnorrSigHash(pkh, lh) => write!(f, "SchnorrSigHash(pkh: {}, leaf_hash: {})", pkh, lh), Sha256Preimage(hash) => write!(f, "Sha256Preimage(hash: {})", hash), Hash256Preimage(hash) => write!(f, "Hash256Preimage(hash: {})", hash), Ripemd160Preimage(hash) => write!(f, "Ripemd160Preimage(hash: {})", hash), @@ -612,8 +631,8 @@ impl Placeholder { .or(sat.lookup_raw_pkh_ecdsa_sig(pkh).map(|(p, _)| p)) .map(|pk| { let pk = pk.to_bytes(); - // We have to add a 1-byte OP_PUSH - debug_assert!(1 + pk.len() == *size); + // Need to add +1 because the size in the placeholder also accounts for the OP_PUSH + debug_assert!(pk.len() + 1 == *size); pk }), Placeholder::Hash256Preimage(h) => sat.lookup_hash256(h).map(|p| p.to_vec()), @@ -624,13 +643,26 @@ impl Placeholder { Placeholder::EcdsaSigHash(pkh) => { sat.lookup_raw_pkh_ecdsa_sig(pkh).map(|(_, s)| s.to_vec()) } - Placeholder::SchnorrSig(pk, Some(leaf_hash)) => sat + Placeholder::SchnorrSig(pk, SchnorrSigType::ScriptSpend { leaf_hash }, size) => sat .lookup_tap_leaf_script_sig(pk, leaf_hash) - .map(|s| s.to_vec()), - Placeholder::SchnorrSigHash(pkh, lh) => sat + .map(|s| s.to_vec()) + .map(|s| { + debug_assert!(s.len() == *size); + s + }), + Placeholder::SchnorrSigHash(pkh, lh, size) => sat .lookup_raw_pkh_tap_leaf_script_sig(&(*pkh, *lh)) - .map(|(_, s)| s.to_vec()), - Placeholder::SchnorrSig(_, _) => sat.lookup_tap_key_spend_sig().map(|s| s.to_vec()), + .map(|(_, s)| s.to_vec()) + .map(|s| { + debug_assert!(s.len() == *size); + s + }), + Placeholder::SchnorrSig(_, _, size) => { + sat.lookup_tap_key_spend_sig().map(|s| s.to_vec()).map(|s| { + debug_assert!(s.len() == *size); + s + }) + } Placeholder::HashDissatisfaction => Some(vec![0; 32]), Placeholder::PushZero => Some(vec![]), Placeholder::PushOne => Some(vec![1]), @@ -653,29 +685,6 @@ pub enum Witness { Impossible, } -/// Enum for partially satisfied witness templates -pub enum PartialSatisfaction { - /// Placeholder item (not yet satisfied) - Placeholder(Placeholder), - /// Actual data - Data(Vec), -} - -impl PartialSatisfaction { - /// Whether the item is a placeholder - pub fn is_placeholder(&self) -> bool { - match &self { - PartialSatisfaction::Placeholder(_) => true, - _ => false, - } - } - - /// Whether the item is data - pub fn is_data(&self) -> bool { - !self.is_placeholder() - } -} - /// Template of a witness being constructed interactively /// /// The generic `I` type determines the available API: @@ -710,91 +719,6 @@ impl WitnessTemplate> { Some(stack) } - - /// Being an interactive satisfaction session - pub fn interactive_satisfaction(self) -> WitnessTemplate> { - WitnessTemplate { - stack: self - .stack - .into_iter() - .map(PartialSatisfaction::Placeholder) - .collect(), - } - } - - /// Returns the list of required signatures - pub fn required_signatures(&self) -> Vec> { - self.stack - .iter() - .filter_map(|item| match item { - Placeholder::EcdsaSigPk(pk) => Some(RequiredSig::Ecdsa(pk)), - Placeholder::SchnorrSig(pk, None) => Some(RequiredSig::SchnorrTapKey(pk)), - Placeholder::SchnorrSig(pk, Some(lh)) => { - Some(RequiredSig::SchnorrTapScript(pk, lh)) - } - _ => None, - }) - .collect() - } - - /// Returns the list of required preimages - pub fn required_preimages(&self) -> Vec> { - self.stack - .iter() - .filter_map(|item| match item { - Placeholder::Sha256Preimage(h) => Some(RequiredPreimage::Sha256(h)), - Placeholder::Hash256Preimage(h) => Some(RequiredPreimage::Hash256(h)), - Placeholder::Ripemd160Preimage(h) => Some(RequiredPreimage::Ripemd160(h)), - Placeholder::Hash160Preimage(h) => Some(RequiredPreimage::Hash160(h)), - _ => None, - }) - .collect() - } -} - -impl WitnessTemplate> { - /// Apply the items needed from a satisfier - /// - /// Returns the completed witness if all the placeholders have been filled, or `Err` with itself a list of missing - /// items otherwise. - pub fn apply>( - self, - stfr: &Sat, - ) -> Result>, (Self, Vec>)> { - let mut unsatisfied = vec![]; - - let stack = self - .stack - .into_iter() - .map(|ps| { - let placeholder = match &ps { - PartialSatisfaction::Placeholder(p) => p, - PartialSatisfaction::Data(_) => return ps, - }; - - if let Some(data) = placeholder.satisfy_self(stfr) { - return PartialSatisfaction::Data(data); - } - - unsatisfied.push(placeholder.clone()); - ps - }) - .collect::>(); - - if unsatisfied.is_empty() { - Ok(stack - .into_iter() - .map(|ps| match ps { - PartialSatisfaction::Data(d) => d, - PartialSatisfaction::Placeholder(_) => { - unreachable!("there shouldn't be any placeholder left") - } - }) - .collect()) - } else { - Err((WitnessTemplate { stack }, unsatisfied)) - } - } } impl PartialOrd for Witness> { @@ -838,10 +762,13 @@ impl Witness> { } } super::context::SigType::Schnorr => { - if sat.lookup_tap_leaf_script_sig(pk, leaf_hash) { + if let Some(size) = sat.lookup_tap_leaf_script_sig(pk, leaf_hash) { Witness::Stack(vec![Placeholder::SchnorrSig( pk.clone(), - Some(leaf_hash.clone()), + SchnorrSigType::ScriptSpend { + leaf_hash: *leaf_hash, + }, + size, )]) } else { // Signatures cannot be forged @@ -885,11 +812,11 @@ impl Witness> { None => Witness::Impossible, }, SigType::Schnorr => match sat.lookup_raw_pkh_tap_leaf_script_sig(&(*pkh, *leaf_hash)) { - true => Witness::Stack(vec![ - Placeholder::SchnorrSigHash(pkh.clone(), *leaf_hash), + Some(size) => Witness::Stack(vec![ + Placeholder::SchnorrSigHash(pkh.clone(), *leaf_hash, size), Placeholder::PubkeyHash(pkh.clone(), 32), ]), - false => Witness::Impossible, + None => Witness::Impossible, }, } } diff --git a/src/plan.rs b/src/plan.rs index 8f28d5231..c43943f87 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -28,6 +28,7 @@ use core::iter::FromIterator; use bitcoin::hashes::{hash160, ripemd160, sha256}; use bitcoin::util::address::WitnessVersion; +use bitcoin::util::psbt; use bitcoin::util::taproot::TapLeafHash; use bitcoin::{LockTime, Sequence}; @@ -56,14 +57,15 @@ pub trait AssetProvider { false } - /// Lookup the tap key spend sig - fn lookup_tap_key_spend_sig(&self, _: &Pk) -> bool { - false + /// Lookup the tap key spend sig and return its size + fn lookup_tap_key_spend_sig(&self, _: &Pk) -> Option { + None } /// Given a public key and a associated leaf hash, look up an schnorr signature with that key - fn lookup_tap_leaf_script_sig(&self, _: &Pk, _: &TapLeafHash) -> bool { - false + /// and return its size + fn lookup_tap_leaf_script_sig(&self, _: &Pk, _: &TapLeafHash) -> Option { + None } /// Given a raw `Pkh`, lookup corresponding `Pk`. If present, return its lenght. @@ -89,8 +91,13 @@ pub trait AssetProvider { /// Even if signatures for public key Hashes are not available, the users /// can use this map to provide pkh -> pk mapping which can be useful /// for dissatisfying pkh. - fn lookup_raw_pkh_tap_leaf_script_sig(&self, _: &(hash160::Hash, TapLeafHash)) -> bool { - false + /// + /// Returns the signature size if present + fn lookup_raw_pkh_tap_leaf_script_sig( + &self, + _: &(hash160::Hash, TapLeafHash), + ) -> Option { + None } /// Given a SHA256 hash, look up its preimage @@ -143,12 +150,12 @@ macro_rules! impl_log_method { #[cfg(feature = "std")] impl AssetProvider for LoggerAssetProvider { impl_log_method!(lookup_ecdsa_sig, pk: &DefiniteDescriptorKey, -> bool); - impl_log_method!(lookup_tap_key_spend_sig, pk: &DefiniteDescriptorKey, -> bool); - impl_log_method!(lookup_tap_leaf_script_sig, pk: &DefiniteDescriptorKey, leaf_hash: &TapLeafHash, -> bool); + impl_log_method!(lookup_tap_key_spend_sig, pk: &DefiniteDescriptorKey, -> Option); + impl_log_method!(lookup_tap_leaf_script_sig, pk: &DefiniteDescriptorKey, leaf_hash: &TapLeafHash, -> Option); impl_log_method!(lookup_raw_pkh_pk, hash: &hash160::Hash, -> Option); impl_log_method!(lookup_raw_pkh_x_only_pk, hash: &hash160::Hash, -> bool); impl_log_method!(lookup_raw_pkh_ecdsa_sig, hash: &hash160::Hash, -> Option); - impl_log_method!(lookup_raw_pkh_tap_leaf_script_sig, hash: &(hash160::Hash, TapLeafHash), -> bool); + impl_log_method!(lookup_raw_pkh_tap_leaf_script_sig, hash: &(hash160::Hash, TapLeafHash), -> Option); impl_log_method!(lookup_sha256, hash: &sha256::Hash, -> bool); impl_log_method!(lookup_hash256, hash: &hash256::Hash, -> bool); impl_log_method!(lookup_ripemd160, hash: &ripemd160::Hash, -> bool); @@ -166,12 +173,12 @@ where Satisfier::lookup_ecdsa_sig(self, pk).is_some() } - fn lookup_tap_key_spend_sig(&self, _: &Pk) -> bool { - Satisfier::lookup_tap_key_spend_sig(self).is_some() + fn lookup_tap_key_spend_sig(&self, _: &Pk) -> Option { + Satisfier::lookup_tap_key_spend_sig(self).map(|s| s.to_vec().len()) } - fn lookup_tap_leaf_script_sig(&self, pk: &Pk, leaf_hash: &TapLeafHash) -> bool { - Satisfier::lookup_tap_leaf_script_sig(self, pk, leaf_hash).is_some() + fn lookup_tap_leaf_script_sig(&self, pk: &Pk, leaf_hash: &TapLeafHash) -> Option { + Satisfier::lookup_tap_leaf_script_sig(self, pk, leaf_hash).map(|s| s.to_vec().len()) } fn lookup_raw_pkh_pk(&self, hash: &hash160::Hash) -> Option { @@ -186,8 +193,11 @@ where Satisfier::lookup_raw_pkh_ecdsa_sig(self, hash).map(|(p, _)| Ctx::pk_len(&p)) } - fn lookup_raw_pkh_tap_leaf_script_sig(&self, hash: &(hash160::Hash, TapLeafHash)) -> bool { - Satisfier::lookup_raw_pkh_tap_leaf_script_sig(self, hash).is_some() + fn lookup_raw_pkh_tap_leaf_script_sig( + &self, + hash: &(hash160::Hash, TapLeafHash), + ) -> Option { + Satisfier::lookup_raw_pkh_tap_leaf_script_sig(self, hash).map(|(_, s)| s.to_vec().len()) } fn lookup_sha256(&self, hash: &Pk::Sha256) -> bool { @@ -294,13 +304,88 @@ impl Plan { } } +#[derive(Debug)] +/// Signatures which a key can produce +/// +/// Defaults to `ecdsa=true` and `taproot=TaprootCanSign::default()` +pub struct CanSign { + /// Whether the key can produce ECDSA signatures + ecdsa: bool, + /// Whether the key can produce taproot (Schnorr) signatures + taproot: TaprootCanSign, +} + +impl Default for CanSign { + fn default() -> Self { + CanSign { + ecdsa: true, + taproot: TaprootCanSign::default(), + } + } +} + +#[derive(Debug)] +/// Signatures which a taproot key can produce +/// +/// Defaults to `key_spend=true`, `script_spend=Any` and `sighash_default=true` +pub struct TaprootCanSign { + /// Can produce key spend signatures + key_spend: bool, + /// Can produce script spend signatures + script_spend: TaprootAvailableLeaves, + /// Whether `SIGHASH_DEFAULT` will be used to sign + sighash_default: bool, +} + +impl TaprootCanSign { + fn sig_len(&self) -> usize { + match self.sighash_default { + true => 64, + false => 65, + } + } +} + +impl Default for TaprootCanSign { + fn default() -> Self { + TaprootCanSign { + key_spend: true, + script_spend: TaprootAvailableLeaves::Any, + sighash_default: true, + } + } +} + +#[derive(Debug)] +/// Which taproot leaves the key can sign for +pub enum TaprootAvailableLeaves { + /// Cannot sign for any leaf + None, + /// Can sign for any leaf + Any, + /// Can sign only for a specific leaf + Single(TapLeafHash), + /// Can sign for multiple leaves + Many(HashSet), +} + +impl TaprootAvailableLeaves { + fn is_available(&self, lh: &TapLeafHash) -> bool { + use TaprootAvailableLeaves::*; + + match self { + None => false, + Any => true, + Single(v) => v == lh, + Many(set) => set.contains(lh), + } + } +} + /// The Assets we can use to satisfy a particular spending path #[derive(Debug, Default)] pub struct Assets { - keys: HashMap, - tap_key_spend_sig: Option, - ecdsa_signatures: HashMap, - schnorr_signatures: HashMap<(DescriptorPublicKey, TapLeafHash), (bitcoin::SchnorrSig, usize)>, + keys: HashMap, sha256_preimages: HashSet, hash256_preimages: HashSet, ripemd160_preimages: HashSet, @@ -310,57 +395,83 @@ pub struct Assets { } impl Assets { - pub(crate) fn has_key(&self, pk: &DefiniteDescriptorKey) -> bool { - self.keys.values().any(|k| k.is_parent(pk).is_some()) + pub(crate) fn has_ecdsa_key(&self, pk: &DefiniteDescriptorKey) -> bool { + self.keys + .values() + .any(|(key, can_sign)| can_sign.ecdsa && key.is_parent(pk).is_some()) + } + + pub(crate) fn has_taproot_internal_key(&self, pk: &DefiniteDescriptorKey) -> Option { + self.keys.values().find_map(|(key, can_sign)| { + if !can_sign.taproot.key_spend || !key.is_parent(pk).is_some() { + None + } else { + Some(can_sign.taproot.sig_len()) + } + }) } - pub(crate) fn has_ecdsa_sig(&self, pk: &DefiniteDescriptorKey) -> bool { - self.ecdsa_signatures - .keys() - .any(|k| k.is_parent(pk).is_some()) + pub(crate) fn has_taproot_script_key( + &self, + pk: &DefiniteDescriptorKey, + tap_leaf_hash: &TapLeafHash, + ) -> Option { + self.keys.values().find_map(|(key, can_sign)| { + if !can_sign.taproot.script_spend.is_available(tap_leaf_hash) + || !key.is_parent(pk).is_some() + { + None + } else { + Some(can_sign.taproot.sig_len()) + } + }) } - pub(crate) fn has_schnorr_sig( + pub(crate) fn has_taproot_script_key_hash( &self, - pk: &DefiniteDescriptorKey, + key: &hash160::Hash, tap_leaf_hash: &TapLeafHash, - ) -> bool { - self.schnorr_signatures - .keys() - .any(|(k, lh)| tap_leaf_hash == lh && k.is_parent(pk).is_some()) + ) -> Option { + self.keys.get(key).and_then(|(_, can_sign)| { + if !can_sign.taproot.script_spend.is_available(tap_leaf_hash) { + None + } else { + Some(can_sign.taproot.sig_len()) + } + }) } } impl AssetProvider for Assets { fn lookup_ecdsa_sig(&self, pk: &DefiniteDescriptorKey) -> bool { - // Either we have the key to produce the signature, or we already have the signature itself - self.has_key(pk) || self.has_ecdsa_sig(pk) + self.has_ecdsa_key(pk) } - fn lookup_tap_key_spend_sig(&self, pk: &DefiniteDescriptorKey) -> bool { - // Either we have the key to produce the signature, or we already have the signature itself - self.has_key(pk) || self.tap_key_spend_sig.is_some() + fn lookup_tap_key_spend_sig(&self, pk: &DefiniteDescriptorKey) -> Option { + self.has_taproot_internal_key(pk) } fn lookup_tap_leaf_script_sig( &self, pk: &DefiniteDescriptorKey, tap_leaf_hash: &TapLeafHash, - ) -> bool { - // Either we have the key to produce the signature, or we already have the signature itself - self.has_key(pk) || self.has_schnorr_sig(pk, tap_leaf_hash) + ) -> Option { + self.has_taproot_script_key(pk, tap_leaf_hash) } fn lookup_raw_pkh_pk(&self, hash: &hash160::Hash) -> Option { - self.keys.get(hash).map(|p| Ctx::pk_len(p)) + self.keys.get(hash).map(|(pk, _)| Ctx::pk_len(pk)) } fn lookup_raw_pkh_ecdsa_sig(&self, hash: &hash160::Hash) -> Option { - self.keys.get(hash).map(|p| Ctx::pk_len(p)) + self.keys.get(hash).map(|(pk, _)| Ctx::pk_len(pk)) } - fn lookup_raw_pkh_tap_leaf_script_sig(&self, hash: &(hash160::Hash, TapLeafHash)) -> bool { - self.keys.get(&hash.0).is_some() + fn lookup_raw_pkh_tap_leaf_script_sig( + &self, + (key, lh): &(hash160::Hash, TapLeafHash), + ) -> Option { + self.has_taproot_script_key_hash(key, lh) } fn lookup_sha256(&self, hash: &sha256::Hash) -> bool { @@ -409,7 +520,7 @@ impl FromIterator for Assets { pk.clone() .at_derivation_index(0) .to_pubkeyhash(SigType::Ecdsa), - pk, + (pk, CanSign::default()), ) }) .collect(), @@ -510,9 +621,6 @@ impl Assets { fn append(&mut self, b: Self) { self.keys.extend(b.keys.into_iter()); - self.ecdsa_signatures.extend(b.ecdsa_signatures.into_iter()); - self.schnorr_signatures - .extend(b.schnorr_signatures.into_iter()); self.sha256_preimages.extend(b.sha256_preimages.into_iter()); self.hash256_preimages .extend(b.hash256_preimages.into_iter()); @@ -521,7 +629,6 @@ impl Assets { self.hash160_preimages .extend(b.hash160_preimages.into_iter()); - self.tap_key_spend_sig = b.tap_key_spend_sig.or(self.tap_key_spend_sig); self.relative_timelock = b.relative_timelock.or(self.relative_timelock); self.absolute_timelock = b.absolute_timelock.or(self.absolute_timelock); } @@ -768,26 +875,26 @@ mod test { keys[0], keys[1], keys[2], keys[3], keys[4] ); - // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 65 (sig) - let internal_key_sat_weight = Some(71); - // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 65 (sig) + // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 64 (sig) + let internal_key_sat_weight = Some(70); + // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 64 (sig) // + 34 [script: 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIG)] // + 65 [control block: 1 (control byte) + 32 (internal key) + 32 (hash BC)] - let first_leaf_sat_weight = Some(170); - // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 65 (sig) + let first_leaf_sat_weight = Some(169); + // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 64 (sig) // + 1 (OP_ZERO) // + 70 [script: 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIG) // + 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIGADD) // + 1 (OP_PUSHNUM1) + 1 (OP_NUMEQUAL)] // + 97 [control block: 1 (control byte) + 32 (internal key) + 32 (hash C) + 32 (hash // A)] - let second_leaf_sat_weight = Some(239); - // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 65 (sig) + let second_leaf_sat_weight = Some(238); + // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 64 (sig) // + 36 [script: 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIGVERIFY) // + 1 (OP_PUSHNUM_10) + 1 (OP_CLTV)] // + 97 [control block: 1 (control byte) + 32 (internal key) + 32 (hash B) + 32 (hash // A)] - let third_leaf_sat_weight = Some(204); + let third_leaf_sat_weight = Some(203); let tests = vec![ // Don't give assets diff --git a/src/util.rs b/src/util.rs index 5dd9f0ebc..5816868e6 100644 --- a/src/util.rs +++ b/src/util.rs @@ -3,7 +3,7 @@ use bitcoin::hashes::Hash; use bitcoin::{PubkeyHash, Script}; use crate::miniscript::context; -use crate::miniscript::satisfy::{PartialSatisfaction, Placeholder}; +use crate::miniscript::satisfy::Placeholder; use crate::prelude::*; use crate::{MiniscriptKey, ScriptContext, ToPublicKey}; pub(crate) fn varint_len(n: usize) -> usize { @@ -20,7 +20,9 @@ impl ItemSize for Placeholder { Placeholder::PubkeyHash(_, size) => *size, Placeholder::Pubkey(_, size) => *size, Placeholder::EcdsaSigPk(_) | Placeholder::EcdsaSigHash(_) => 73, - Placeholder::SchnorrSig(_, _) | Placeholder::SchnorrSigHash(_, _) => 66, + Placeholder::SchnorrSig(_, _, size) | Placeholder::SchnorrSigHash(_, _, size) => { + size + 1 + } // +1 for the OP_PUSH Placeholder::HashDissatisfaction | Placeholder::Sha256Preimage(_) | Placeholder::Hash256Preimage(_) @@ -34,15 +36,6 @@ impl ItemSize for Placeholder { } } -impl ItemSize for PartialSatisfaction { - fn size(&self) -> usize { - match self { - PartialSatisfaction::Placeholder(p) => p.size(), - PartialSatisfaction::Data(d) => d.len() + varint_len(d.len()), - } - } -} - impl ItemSize for Vec { fn size(&self) -> usize { self.len()