miniscript_debug/descriptor/
sh.rs

1// Miniscript
2// Written in 2020 by rust-miniscript developers
3//
4// To the extent possible under law, the author(s) have dedicated all
5// copyright and related and neighboring rights to this software to
6// the public domain worldwide. This software is distributed without
7// any warranty.
8//
9// You should have received a copy of the CC0 Public Domain Dedication
10// along with this software.
11// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
12//
13
14//! # P2SH Descriptors
15//!
16//! Implementation of p2sh descriptors. Contains the implementation
17//! of sh, wrapped fragments for sh which include wsh, sortedmulti
18//! sh(miniscript), and sh(wpkh)
19//!
20
21use core::fmt;
22
23use bitcoin::blockdata::script;
24use bitcoin::{Address, Network, Script};
25
26use super::checksum::{self, verify_checksum};
27use super::{SortedMultiVec, Wpkh, Wsh};
28use crate::expression::{self, FromTree};
29use crate::miniscript::context::ScriptContext;
30use crate::policy::{semantic, Liftable};
31use crate::prelude::*;
32use crate::util::{varint_len, witness_to_scriptsig};
33use crate::{
34    push_opcode_size, Error, ForEachKey, Legacy, Miniscript, MiniscriptKey, Satisfier, Segwitv0,
35    ToPublicKey, TranslatePk, Translator,
36};
37
38/// A Legacy p2sh Descriptor
39#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
40pub struct Sh<Pk: MiniscriptKey> {
41    /// underlying miniscript
42    inner: ShInner<Pk>,
43}
44
45/// Sh Inner
46#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
47pub enum ShInner<Pk: MiniscriptKey> {
48    /// Nested Wsh
49    Wsh(Wsh<Pk>),
50    /// Nested Wpkh
51    Wpkh(Wpkh<Pk>),
52    /// Inner Sorted Multi
53    SortedMulti(SortedMultiVec<Pk, Legacy>),
54    /// p2sh miniscript
55    Ms(Miniscript<Pk, Legacy>),
56}
57
58impl<Pk: MiniscriptKey> Liftable<Pk> for Sh<Pk> {
59    fn lift(&self) -> Result<semantic::Policy<Pk>, Error> {
60        match self.inner {
61            ShInner::Wsh(ref wsh) => wsh.lift(),
62            ShInner::Wpkh(ref pk) => Ok(semantic::Policy::Key(pk.as_inner().clone())),
63            ShInner::SortedMulti(ref smv) => smv.lift(),
64            ShInner::Ms(ref ms) => ms.lift(),
65        }
66    }
67}
68
69impl<Pk: MiniscriptKey> fmt::Debug for Sh<Pk> {
70    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71        match self.inner {
72            ShInner::Wsh(ref wsh_inner) => write!(f, "sh({:?})", wsh_inner),
73            ShInner::Wpkh(ref pk) => write!(f, "sh({:?})", pk),
74            ShInner::SortedMulti(ref smv) => write!(f, "sh({:?})", smv),
75            ShInner::Ms(ref ms) => write!(f, "sh({:?})", ms),
76        }
77    }
78}
79
80impl<Pk: MiniscriptKey> fmt::Display for Sh<Pk> {
81    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82        use fmt::Write;
83        let mut wrapped_f = checksum::Formatter::new(f);
84        match self.inner {
85            ShInner::Wsh(ref wsh) => write!(wrapped_f, "sh({:#})", wsh)?,
86            ShInner::Wpkh(ref pk) => write!(wrapped_f, "sh({:#})", pk)?,
87            ShInner::SortedMulti(ref smv) => write!(wrapped_f, "sh({})", smv)?,
88            ShInner::Ms(ref ms) => write!(wrapped_f, "sh({})", ms)?,
89        }
90        wrapped_f.write_checksum_if_not_alt()
91    }
92}
93
94impl_from_tree!(
95    Sh<Pk>,
96    fn from_tree(top: &expression::Tree) -> Result<Self, Error> {
97        if top.name == "sh" && top.args.len() == 1 {
98            let top = &top.args[0];
99            let inner = match top.name {
100                "wsh" => ShInner::Wsh(Wsh::from_tree(top)?),
101                "wpkh" => ShInner::Wpkh(Wpkh::from_tree(top)?),
102                "sortedmulti" => ShInner::SortedMulti(SortedMultiVec::from_tree(top)?),
103                _ => {
104                    let sub = Miniscript::from_tree(top)?;
105                    Legacy::top_level_checks(&sub)?;
106                    ShInner::Ms(sub)
107                }
108            };
109            Ok(Sh { inner })
110        } else {
111            Err(Error::Unexpected(format!(
112                "{}({} args) while parsing sh descriptor",
113                top.name,
114                top.args.len(),
115            )))
116        }
117    }
118);
119
120impl_from_str!(
121    Sh<Pk>,
122    type Err = Error;,
123    fn from_str(s: &str) -> Result<Self, Self::Err> {
124        let desc_str = verify_checksum(s)?;
125        let top = expression::Tree::from_str(desc_str)?;
126        Self::from_tree(&top)
127    }
128);
129
130impl<Pk: MiniscriptKey> Sh<Pk> {
131    /// Get the Inner
132    pub fn into_inner(self) -> ShInner<Pk> {
133        self.inner
134    }
135
136    /// Get a reference to inner
137    pub fn as_inner(&self) -> &ShInner<Pk> {
138        &self.inner
139    }
140
141    /// Create a new p2sh descriptor with the raw miniscript
142    pub fn new(ms: Miniscript<Pk, Legacy>) -> Result<Self, Error> {
143        // do the top-level checks
144        Legacy::top_level_checks(&ms)?;
145        Ok(Self {
146            inner: ShInner::Ms(ms),
147        })
148    }
149
150    /// Create a new p2sh sortedmulti descriptor with threshold `k`
151    /// and Vec of `pks`.
152    pub fn new_sortedmulti(k: usize, pks: Vec<Pk>) -> Result<Self, Error> {
153        // The context checks will be carried out inside new function for
154        // sortedMultiVec
155        Ok(Self {
156            inner: ShInner::SortedMulti(SortedMultiVec::new(k, pks)?),
157        })
158    }
159
160    /// Create a new p2sh wrapped wsh descriptor with the raw miniscript
161    pub fn new_wsh(ms: Miniscript<Pk, Segwitv0>) -> Result<Self, Error> {
162        Ok(Self {
163            inner: ShInner::Wsh(Wsh::new(ms)?),
164        })
165    }
166
167    /// Create a new p2sh wrapper for the given wsh descriptor
168    pub fn new_with_wsh(wsh: Wsh<Pk>) -> Self {
169        Self {
170            inner: ShInner::Wsh(wsh),
171        }
172    }
173
174    /// Checks whether the descriptor is safe.
175    pub fn sanity_check(&self) -> Result<(), Error> {
176        match self.inner {
177            ShInner::Wsh(ref wsh) => wsh.sanity_check()?,
178            ShInner::Wpkh(ref wpkh) => wpkh.sanity_check()?,
179            ShInner::SortedMulti(ref smv) => smv.sanity_check()?,
180            ShInner::Ms(ref ms) => ms.sanity_check()?,
181        }
182        Ok(())
183    }
184
185    /// Create a new p2sh wrapped wsh sortedmulti descriptor from threshold
186    /// `k` and Vec of `pks`
187    pub fn new_wsh_sortedmulti(k: usize, pks: Vec<Pk>) -> Result<Self, Error> {
188        // The context checks will be carried out inside new function for
189        // sortedMultiVec
190        Ok(Self {
191            inner: ShInner::Wsh(Wsh::new_sortedmulti(k, pks)?),
192        })
193    }
194
195    /// Create a new p2sh wrapped wpkh from `Pk`
196    pub fn new_wpkh(pk: Pk) -> Result<Self, Error> {
197        Ok(Self {
198            inner: ShInner::Wpkh(Wpkh::new(pk)?),
199        })
200    }
201
202    /// Create a new p2sh wrapper for the given wpkh descriptor
203    pub fn new_with_wpkh(wpkh: Wpkh<Pk>) -> Self {
204        Self {
205            inner: ShInner::Wpkh(wpkh),
206        }
207    }
208
209    /// Computes an upper bound on the weight of a satisfying witness to the
210    /// transaction.
211    ///
212    /// Assumes all ec-signatures are 73 bytes, including push opcode and
213    /// sighash suffix. Includes the weight of the VarInts encoding the
214    /// scriptSig and witness stack length.
215    ///
216    /// # Errors
217    /// When the descriptor is impossible to safisfy (ex: sh(OP_FALSE)).
218    pub fn max_satisfaction_weight(&self) -> Result<usize, Error> {
219        Ok(match self.inner {
220            // add weighted script sig, len byte stays the same
221            ShInner::Wsh(ref wsh) => 4 * 35 + wsh.max_satisfaction_weight()?,
222            ShInner::SortedMulti(ref smv) => {
223                let ss = smv.script_size();
224                let ps = push_opcode_size(ss);
225                let scriptsig_len = ps + ss + smv.max_satisfaction_size();
226                4 * (varint_len(scriptsig_len) + scriptsig_len)
227            }
228            // add weighted script sig, len byte stays the same
229            ShInner::Wpkh(ref wpkh) => 4 * 23 + wpkh.max_satisfaction_weight(),
230            ShInner::Ms(ref ms) => {
231                let ss = ms.script_size();
232                let ps = push_opcode_size(ss);
233                let scriptsig_len = ps + ss + ms.max_satisfaction_size()?;
234                4 * (varint_len(scriptsig_len) + scriptsig_len)
235            }
236        })
237    }
238}
239
240impl<Pk: MiniscriptKey + ToPublicKey> Sh<Pk> {
241    /// Obtains the corresponding script pubkey for this descriptor.
242    pub fn script_pubkey(&self) -> Script {
243        match self.inner {
244            ShInner::Wsh(ref wsh) => wsh.script_pubkey().to_p2sh(),
245            ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey().to_p2sh(),
246            ShInner::SortedMulti(ref smv) => smv.encode().to_p2sh(),
247            ShInner::Ms(ref ms) => ms.encode().to_p2sh(),
248        }
249    }
250
251    /// Obtains the corresponding address for this descriptor.
252    pub fn address(&self, network: Network) -> Address {
253        let addr = self.address_fallible(network);
254
255        // Size is checked in `check_global_consensus_validity`.
256        assert!(addr.is_ok());
257        addr.expect("only fails if size > MAX_SCRIPT_ELEMENT_SIZE")
258    }
259
260    fn address_fallible(&self, network: Network) -> Result<Address, Error> {
261        let script = match self.inner {
262            ShInner::Wsh(ref wsh) => wsh.script_pubkey(),
263            ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey(),
264            ShInner::SortedMulti(ref smv) => smv.encode(),
265            ShInner::Ms(ref ms) => ms.encode(),
266        };
267        let address = Address::p2sh(&script, network)?;
268
269        Ok(address)
270    }
271
272    /// Obtain the underlying miniscript for this descriptor
273    pub fn inner_script(&self) -> Script {
274        match self.inner {
275            ShInner::Wsh(ref wsh) => wsh.inner_script(),
276            ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey(),
277            ShInner::SortedMulti(ref smv) => smv.encode(),
278            ShInner::Ms(ref ms) => ms.encode(),
279        }
280    }
281
282    /// Obtains the pre bip-340 signature script code for this descriptor.
283    pub fn ecdsa_sighash_script_code(&self) -> Script {
284        match self.inner {
285            //     - For P2WSH witness program, if the witnessScript does not contain any `OP_CODESEPARATOR`,
286            //       the `scriptCode` is the `witnessScript` serialized as scripts inside CTxOut.
287            ShInner::Wsh(ref wsh) => wsh.ecdsa_sighash_script_code(),
288            ShInner::SortedMulti(ref smv) => smv.encode(),
289            ShInner::Wpkh(ref wpkh) => wpkh.ecdsa_sighash_script_code(),
290            // For "legacy" P2SH outputs, it is defined as the txo's redeemScript.
291            ShInner::Ms(ref ms) => ms.encode(),
292        }
293    }
294
295    /// Computes the scriptSig that will be in place for an unsigned input
296    /// spending an output with this descriptor. For pre-segwit descriptors,
297    /// which use the scriptSig for signatures, this returns the empty script.
298    ///
299    /// This is used in Segwit transactions to produce an unsigned transaction
300    /// whose txid will not change during signing (since only the witness data
301    /// will change).
302    pub fn unsigned_script_sig(&self) -> Script {
303        match self.inner {
304            ShInner::Wsh(ref wsh) => {
305                // wsh explicit must contain exactly 1 element
306                let witness_script = wsh.inner_script();
307                script::Builder::new()
308                    .push_slice(&witness_script.to_v0_p2wsh()[..])
309                    .into_script()
310            }
311            ShInner::Wpkh(ref wpkh) => {
312                let redeem_script = wpkh.script_pubkey();
313                script::Builder::new()
314                    .push_slice(&redeem_script[..])
315                    .into_script()
316            }
317            ShInner::SortedMulti(..) | ShInner::Ms(..) => Script::new(),
318        }
319    }
320
321    /// Returns satisfying non-malleable witness and scriptSig with minimum
322    /// weight to spend an output controlled by the given descriptor if it is
323    /// possible to construct one using the `satisfier`.
324    pub fn get_satisfaction<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error>
325    where
326        S: Satisfier<Pk>,
327    {
328        let script_sig = self.unsigned_script_sig();
329        match self.inner {
330            ShInner::Wsh(ref wsh) => {
331                let (witness, _) = wsh.get_satisfaction(satisfier)?;
332                Ok((witness, script_sig))
333            }
334            ShInner::Wpkh(ref wpkh) => {
335                let (witness, _) = wpkh.get_satisfaction(satisfier)?;
336                Ok((witness, script_sig))
337            }
338            ShInner::SortedMulti(ref smv) => {
339                let mut script_witness = smv.satisfy(satisfier)?;
340                script_witness.push(smv.encode().into_bytes());
341                let script_sig = witness_to_scriptsig(&script_witness);
342                let witness = vec![];
343                Ok((witness, script_sig))
344            }
345            ShInner::Ms(ref ms) => {
346                let mut script_witness = ms.satisfy(satisfier)?;
347                script_witness.push(ms.encode().into_bytes());
348                let script_sig = witness_to_scriptsig(&script_witness);
349                let witness = vec![];
350                Ok((witness, script_sig))
351            }
352        }
353    }
354
355    /// Returns satisfying, possibly malleable, witness and scriptSig with
356    /// minimum weight to spend an output controlled by the given descriptor if
357    /// it is possible to construct one using the `satisfier`.
358    pub fn get_satisfaction_mall<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error>
359    where
360        S: Satisfier<Pk>,
361    {
362        let script_sig = self.unsigned_script_sig();
363        match self.inner {
364            ShInner::Wsh(ref wsh) => {
365                let (witness, _) = wsh.get_satisfaction_mall(satisfier)?;
366                Ok((witness, script_sig))
367            }
368            ShInner::Ms(ref ms) => {
369                let mut script_witness = ms.satisfy_malleable(satisfier)?;
370                script_witness.push(ms.encode().into_bytes());
371                let script_sig = witness_to_scriptsig(&script_witness);
372                let witness = vec![];
373                Ok((witness, script_sig))
374            }
375            _ => self.get_satisfaction(satisfier),
376        }
377    }
378}
379
380impl<Pk: MiniscriptKey> ForEachKey<Pk> for Sh<Pk> {
381    fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool
382    where
383        Pk: 'a,
384    {
385        match self.inner {
386            ShInner::Wsh(ref wsh) => wsh.for_each_key(pred),
387            ShInner::SortedMulti(ref smv) => smv.for_each_key(pred),
388            ShInner::Wpkh(ref wpkh) => wpkh.for_each_key(pred),
389            ShInner::Ms(ref ms) => ms.for_each_key(pred),
390        }
391    }
392}
393
394impl<P, Q> TranslatePk<P, Q> for Sh<P>
395where
396    P: MiniscriptKey,
397    Q: MiniscriptKey,
398{
399    type Output = Sh<Q>;
400
401    fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
402    where
403        T: Translator<P, Q, E>,
404    {
405        let inner = match self.inner {
406            ShInner::Wsh(ref wsh) => ShInner::Wsh(wsh.translate_pk(t)?),
407            ShInner::Wpkh(ref wpkh) => ShInner::Wpkh(wpkh.translate_pk(t)?),
408            ShInner::SortedMulti(ref smv) => ShInner::SortedMulti(smv.translate_pk(t)?),
409            ShInner::Ms(ref ms) => ShInner::Ms(ms.translate_pk(t)?),
410        };
411        Ok(Sh { inner })
412    }
413}