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