diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 320e80c4c..98e51fd13 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -50,63 +50,19 @@ use crate::{expression, Error, ForEachKey, MiniscriptKey, ToPublicKey, Translate #[cfg(test)] mod ms_tests; -/// Top-level script AST type +/// The top-level miniscript abstract syntax tree (AST). #[derive(Clone)] pub struct Miniscript { - ///A node in the Abstract Syntax Tree( + /// A node in the AST. pub node: Terminal, - ///The correctness and malleability type information for the AST node + /// The correctness and malleability type information for the AST node. pub ty: types::Type, - ///Additional information helpful for extra analysis. + /// Additional information helpful for extra analysis. pub ext: types::extra_props::ExtData, /// Context PhantomData. Only accessible inside this crate phantom: PhantomData, } -/// `PartialOrd` of `Miniscript` must depend only on node and not the type information. -/// The type information and extra_properties can be deterministically determined -/// by the ast. -impl PartialOrd for Miniscript { - fn partial_cmp(&self, other: &Miniscript) -> Option { - Some(self.node.cmp(&other.node)) - } -} - -/// `Ord` of `Miniscript` must depend only on node and not the type information. -/// The type information and extra_properties can be deterministically determined -/// by the ast. -impl Ord for Miniscript { - fn cmp(&self, other: &Miniscript) -> cmp::Ordering { - self.node.cmp(&other.node) - } -} - -/// `PartialEq` of `Miniscript` must depend only on node and not the type information. -/// The type information and extra_properties can be deterministically determined -/// by the ast. -impl PartialEq for Miniscript { - fn eq(&self, other: &Miniscript) -> bool { - self.node.eq(&other.node) - } -} - -/// `Eq` of `Miniscript` must depend only on node and not the type information. -/// The type information and extra_properties can be deterministically determined -/// by the ast. -impl Eq for Miniscript {} - -impl fmt::Debug for Miniscript { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.node) - } -} - -impl hash::Hash for Miniscript { - fn hash(&self, state: &mut H) { - self.node.hash(state); - } -} - impl Miniscript { /// Add type information(Type and Extdata) to Miniscript based on /// `AstElem` fragment. Dependent on display and clone because of Error @@ -139,15 +95,7 @@ impl Miniscript { phantom: PhantomData, } } -} -impl fmt::Display for Miniscript { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.node) - } -} - -impl Miniscript { /// Extracts the `AstElem` representing the root of the miniscript pub fn into_inner(self) -> Terminal { self.node @@ -157,6 +105,141 @@ impl Miniscript { pub fn as_inner(&self) -> &Terminal { &self.node } + + /// Encode as a Bitcoin script + pub fn encode(&self) -> script::ScriptBuf + where + Pk: ToPublicKey, + { + self.node.encode(script::Builder::new()).into_script() + } + + /// Size, in bytes of the script-pubkey. If this Miniscript is used outside + /// of segwit (e.g. in a bare or P2SH descriptor), this quantity should be + /// multiplied by 4 to compute the weight. + /// + /// In general, it is not recommended to use this function directly, but + /// to instead call the corresponding function on a `Descriptor`, which + /// will handle the segwit/non-segwit technicalities for you. + pub fn script_size(&self) -> usize { + use Terminal::*; + + let mut len = 0; + for ms in self.pre_order_iter() { + len += match ms.node { + AndV(..) => 0, + True | False | Swap(..) | Check(..) | ZeroNotEqual(..) | AndB(..) | OrB(..) => 1, + Alt(..) | OrC(..) => 2, + DupIf(..) | AndOr(..) | OrD(..) | OrI(..) => 3, + NonZero(..) => 4, + PkH(..) | RawPkH(..) => 24, + Ripemd160(..) | Hash160(..) => 21 + 6, + Sha256(..) | Hash256(..) => 33 + 6, + + Terminal::PkK(ref pk) => Ctx::pk_len(pk), + Terminal::After(n) => script_num_size(n.to_consensus_u32() as usize) + 1, + Terminal::Older(n) => script_num_size(n.to_consensus_u32() as usize) + 1, + Terminal::Verify(ref sub) => usize::from(!sub.ext.has_free_verify), + Terminal::Thresh(k, ref subs) => { + assert!(!subs.is_empty(), "threshold must be nonempty"); + script_num_size(k) // k + + 1 // EQUAL + + subs.len() // ADD + - 1 // no ADD on first element + } + Terminal::Multi(k, ref pks) => { + script_num_size(k) + + 1 + + script_num_size(pks.len()) + + pks.iter().map(|pk| Ctx::pk_len(pk)).sum::() + } + Terminal::MultiA(k, ref pks) => { + script_num_size(k) + + 1 // NUMEQUAL + + pks.iter().map(|pk| Ctx::pk_len(pk)).sum::() // n keys + + pks.len() // n times CHECKSIGADD + } + } + } + len + } + + /// Maximum number of witness elements used to satisfy the Miniscript + /// fragment, including the witness script itself. Used to estimate + /// the weight of the `VarInt` that specifies this number in a serialized + /// transaction. + /// + /// This function may returns Error when the Miniscript is + /// impossible to satisfy + pub fn max_satisfaction_witness_elements(&self) -> Result { + self.ext + .stack_elem_count_sat + .map(|x| x + 1) + .ok_or(Error::ImpossibleSatisfaction) + } + + /// Maximum size, in bytes, of a satisfying witness. For Segwit outputs + /// `one_cost` should be set to 2, since the number `1` requires two + /// bytes to encode. For non-segwit outputs `one_cost` should be set to + /// 1, since `OP_1` is available in scriptSigs. + /// + /// In general, it is not recommended to use this function directly, but + /// to instead call the corresponding function on a `Descriptor`, which + /// will handle the segwit/non-segwit technicalities for you. + /// + /// All signatures are assumed to be 73 bytes in size, including the + /// length prefix (segwit) or push opcode (pre-segwit) and sighash + /// postfix. + pub fn max_satisfaction_size(&self) -> Result { + Ctx::max_satisfaction_size(self).ok_or(Error::ImpossibleSatisfaction) + } + + /// Attempt to produce non-malleable satisfying witness for the + /// witness script represented by the parse tree + pub fn satisfy>(&self, satisfier: S) -> Result>, Error> + where + Pk: ToPublicKey, + { + // Only satisfactions for default versions (0xc0) are allowed. + let leaf_hash = TapLeafHash::from_script(&self.encode(), LeafVersion::TapScript); + let satisfaction = + satisfy::Satisfaction::satisfy(&self.node, &satisfier, self.ty.mall.safe, &leaf_hash); + self._satisfy(satisfaction) + } + + /// Attempt to produce a malleable satisfying witness for the + /// witness script represented by the parse tree + pub fn satisfy_malleable>( + &self, + satisfier: S, + ) -> Result>, Error> + where + Pk: ToPublicKey, + { + let leaf_hash = TapLeafHash::from_script(&self.encode(), LeafVersion::TapScript); + let satisfaction = satisfy::Satisfaction::satisfy_mall( + &self.node, + &satisfier, + self.ty.mall.safe, + &leaf_hash, + ); + self._satisfy(satisfaction) + } + + fn _satisfy(&self, satisfaction: satisfy::Satisfaction) -> Result>, Error> + where + Pk: ToPublicKey, + { + match satisfaction.stack { + satisfy::Witness::Stack(stack) => { + Ctx::check_witness::(&stack)?; + Ok(stack) + } + satisfy::Witness::Unavailable | satisfy::Witness::Impossible => { + Err(Error::CouldNotSatisfy) + } + } + } } impl Miniscript { @@ -238,108 +321,56 @@ impl Miniscript { } } -impl Miniscript -where - Pk: MiniscriptKey, - Ctx: ScriptContext, -{ - /// Encode as a Bitcoin script - pub fn encode(&self) -> script::ScriptBuf - where - Pk: ToPublicKey, - { - self.node.encode(script::Builder::new()).into_script() +/// `PartialOrd` of `Miniscript` must depend only on node and not the type information. +/// +/// The type information and extra properties are implied by the AST. +impl PartialOrd for Miniscript { + fn partial_cmp(&self, other: &Miniscript) -> Option { + Some(self.node.cmp(&other.node)) } +} - /// Size, in bytes of the script-pubkey. If this Miniscript is used outside - /// of segwit (e.g. in a bare or P2SH descriptor), this quantity should be - /// multiplied by 4 to compute the weight. - /// - /// In general, it is not recommended to use this function directly, but - /// to instead call the corresponding function on a `Descriptor`, which - /// will handle the segwit/non-segwit technicalities for you. - pub fn script_size(&self) -> usize { - let mut len = 0; - for ms in self.pre_order_iter() { - len += match ms.node { - Terminal::PkK(ref pk) => Ctx::pk_len(pk), - Terminal::PkH(..) | Terminal::RawPkH(..) => 24, - Terminal::After(n) => script_num_size(n.to_consensus_u32() as usize) + 1, - Terminal::Older(n) => script_num_size(n.to_consensus_u32() as usize) + 1, - Terminal::Sha256(..) => 33 + 6, - Terminal::Hash256(..) => 33 + 6, - Terminal::Ripemd160(..) => 21 + 6, - Terminal::Hash160(..) => 21 + 6, - Terminal::True => 1, - Terminal::False => 1, - Terminal::Alt(..) => 2, - Terminal::Swap(..) => 1, - Terminal::Check(..) => 1, - Terminal::DupIf(..) => 3, - Terminal::Verify(ref sub) => usize::from(!sub.ext.has_free_verify), - Terminal::NonZero(..) => 4, - Terminal::ZeroNotEqual(..) => 1, - Terminal::AndV(..) => 0, - Terminal::AndB(..) => 1, - Terminal::AndOr(..) => 3, - Terminal::OrB(..) => 1, - Terminal::OrD(..) => 3, - Terminal::OrC(..) => 2, - Terminal::OrI(..) => 3, - Terminal::Thresh(k, ref subs) => { - assert!(!subs.is_empty(), "threshold must be nonempty"); - script_num_size(k) // k - + 1 // EQUAL - + subs.len() // ADD - - 1 // no ADD on first element - } - Terminal::Multi(k, ref pks) => { - script_num_size(k) - + 1 - + script_num_size(pks.len()) - + pks.iter().map(|pk| Ctx::pk_len(pk)).sum::() - } - Terminal::MultiA(k, ref pks) => { - script_num_size(k) - + 1 // NUMEQUAL - + pks.iter().map(|pk| Ctx::pk_len(pk)).sum::() // n keys - + pks.len() // n times CHECKSIGADD - } - } - } - len +/// `Ord` of `Miniscript` must depend only on node and not the type information. +/// +/// The type information and extra properties are implied by the AST. +impl Ord for Miniscript { + fn cmp(&self, other: &Miniscript) -> cmp::Ordering { + self.node.cmp(&other.node) } } -impl Miniscript { - /// Maximum number of witness elements used to satisfy the Miniscript - /// fragment, including the witness script itself. Used to estimate - /// the weight of the `VarInt` that specifies this number in a serialized - /// transaction. - /// - /// This function may returns Error when the Miniscript is - /// impossible to satisfy - pub fn max_satisfaction_witness_elements(&self) -> Result { - self.ext - .stack_elem_count_sat - .map(|x| x + 1) - .ok_or(Error::ImpossibleSatisfaction) +/// `PartialEq` of `Miniscript` must depend only on node and not the type information. +/// +/// The type information and extra properties are implied by the AST. +impl PartialEq for Miniscript { + fn eq(&self, other: &Miniscript) -> bool { + self.node.eq(&other.node) } +} - /// Maximum size, in bytes, of a satisfying witness. For Segwit outputs - /// `one_cost` should be set to 2, since the number `1` requires two - /// bytes to encode. For non-segwit outputs `one_cost` should be set to - /// 1, since `OP_1` is available in scriptSigs. - /// - /// In general, it is not recommended to use this function directly, but - /// to instead call the corresponding function on a `Descriptor`, which - /// will handle the segwit/non-segwit technicalities for you. - /// - /// All signatures are assumed to be 73 bytes in size, including the - /// length prefix (segwit) or push opcode (pre-segwit) and sighash - /// postfix. - pub fn max_satisfaction_size(&self) -> Result { - Ctx::max_satisfaction_size(self).ok_or(Error::ImpossibleSatisfaction) +/// `Eq` of `Miniscript` must depend only on node and not the type information. +/// +/// The type information and extra properties are implied by the AST. +impl Eq for Miniscript {} + +/// `Hash` of `Miniscript` must depend only on node and not the type information. +/// +/// The type information and extra properties are implied by the AST. +impl hash::Hash for Miniscript { + fn hash(&self, state: &mut H) { + self.node.hash(state); + } +} + +impl fmt::Debug for Miniscript { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.node) + } +} + +impl fmt::Display for Miniscript { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.node) } } @@ -507,57 +538,6 @@ impl_block_str!( } ); -impl Miniscript { - /// Attempt to produce non-malleable satisfying witness for the - /// witness script represented by the parse tree - pub fn satisfy>(&self, satisfier: S) -> Result>, Error> - where - Pk: ToPublicKey, - { - // Only satisfactions for default versions (0xc0) are allowed. - let leaf_hash = TapLeafHash::from_script(&self.encode(), LeafVersion::TapScript); - match satisfy::Satisfaction::satisfy(&self.node, &satisfier, self.ty.mall.safe, &leaf_hash) - .stack - { - satisfy::Witness::Stack(stack) => { - Ctx::check_witness::(&stack)?; - Ok(stack) - } - satisfy::Witness::Unavailable | satisfy::Witness::Impossible => { - Err(Error::CouldNotSatisfy) - } - } - } - - /// Attempt to produce a malleable satisfying witness for the - /// witness script represented by the parse tree - pub fn satisfy_malleable>( - &self, - satisfier: S, - ) -> Result>, Error> - where - Pk: ToPublicKey, - { - let leaf_hash = TapLeafHash::from_script(&self.encode(), LeafVersion::TapScript); - match satisfy::Satisfaction::satisfy_mall( - &self.node, - &satisfier, - self.ty.mall.safe, - &leaf_hash, - ) - .stack - { - satisfy::Witness::Stack(stack) => { - Ctx::check_witness::(&stack)?; - Ok(stack) - } - satisfy::Witness::Unavailable | satisfy::Witness::Impossible => { - Err(Error::CouldNotSatisfy) - } - } - } -} - impl_from_tree!( ;Ctx; ScriptContext, Arc>,