elements_miniscript/descriptor/
sh.rs

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