sapio_miniscript/descriptor/
pretaproot.rs

1use std::{
2    fmt,
3    str::{self, FromStr},
4};
5
6use bitcoin::{self, Script};
7
8use super::{checksum::verify_checksum, Bare, Pkh, Sh, Wpkh, Wsh};
9use {expression, DescriptorTrait, Error, MiniscriptKey, Satisfier, ToPublicKey};
10
11/// Script descriptor
12#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub enum PreTaprootDescriptor<Pk: MiniscriptKey> {
14    /// Bare descriptor
15    Bare(Bare<Pk>),
16    /// Pay-to-PubKey-Hash
17    Pkh(Pkh<Pk>),
18    /// Pay-to-Witness-PubKey-Hash
19    Wpkh(Wpkh<Pk>),
20    /// Pay-to-ScriptHash(includes nested wsh/wpkh/sorted multi)
21    Sh(Sh<Pk>),
22    /// Pay-to-Witness-ScriptHash with Segwitv0 context
23    Wsh(Wsh<Pk>),
24}
25
26impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for PreTaprootDescriptor<Pk> {
27    /// Whether the descriptor is safe
28    /// Checks whether all the spend paths in the descriptor are possible
29    /// on the bitcoin network under the current standardness and consensus rules
30    /// Also checks whether the descriptor requires signauture on all spend paths
31    /// And whether the script is malleable.
32    /// In general, all the guarantees of miniscript hold only for safe scripts.
33    /// All the analysis guarantees of miniscript only hold safe scripts.
34    /// The signer may not be able to find satisfactions even if one exists
35    fn sanity_check(&self) -> Result<(), Error> {
36        match *self {
37            PreTaprootDescriptor::Bare(ref bare) => bare.sanity_check(),
38            PreTaprootDescriptor::Pkh(ref pkh) => pkh.sanity_check(),
39            PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.sanity_check(),
40            PreTaprootDescriptor::Wsh(ref wsh) => wsh.sanity_check(),
41            PreTaprootDescriptor::Sh(ref sh) => sh.sanity_check(),
42        }
43    }
44    /// Computes the Bitcoin address of the descriptor, if one exists
45    fn address(&self, network: bitcoin::Network) -> Result<bitcoin::Address, Error>
46    where
47        Pk: ToPublicKey,
48    {
49        match *self {
50            PreTaprootDescriptor::Bare(ref bare) => bare.address(network),
51            PreTaprootDescriptor::Pkh(ref pkh) => pkh.address(network),
52            PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.address(network),
53            PreTaprootDescriptor::Wsh(ref wsh) => wsh.address(network),
54            PreTaprootDescriptor::Sh(ref sh) => sh.address(network),
55        }
56    }
57
58    /// Computes the scriptpubkey of the descriptor
59    fn script_pubkey(&self) -> Script
60    where
61        Pk: ToPublicKey,
62    {
63        match *self {
64            PreTaprootDescriptor::Bare(ref bare) => bare.script_pubkey(),
65            PreTaprootDescriptor::Pkh(ref pkh) => pkh.script_pubkey(),
66            PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.script_pubkey(),
67            PreTaprootDescriptor::Wsh(ref wsh) => wsh.script_pubkey(),
68            PreTaprootDescriptor::Sh(ref sh) => sh.script_pubkey(),
69        }
70    }
71
72    /// Computes the scriptSig that will be in place for an unsigned
73    /// input spending an output with this descriptor. For pre-segwit
74    /// descriptors, which use the scriptSig for signatures, this
75    /// returns the empty script.
76    ///
77    /// This is used in Segwit transactions to produce an unsigned
78    /// transaction whose txid will not change during signing (since
79    /// only the witness data will change).
80    fn unsigned_script_sig(&self) -> Script
81    where
82        Pk: ToPublicKey,
83    {
84        match *self {
85            PreTaprootDescriptor::Bare(ref bare) => bare.unsigned_script_sig(),
86            PreTaprootDescriptor::Pkh(ref pkh) => pkh.unsigned_script_sig(),
87            PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.unsigned_script_sig(),
88            PreTaprootDescriptor::Wsh(ref wsh) => wsh.unsigned_script_sig(),
89            PreTaprootDescriptor::Sh(ref sh) => sh.unsigned_script_sig(),
90        }
91    }
92
93    /// Computes the "witness script" of the descriptor, i.e. the underlying
94    /// script before any hashing is done. For `Bare`, `Pkh` and `Wpkh` this
95    /// is the scriptPubkey; for `ShWpkh` and `Sh` this is the redeemScript;
96    /// for the others it is the witness script.
97    /// Errors:
98    /// - When the descriptor is Tr
99    fn explicit_script(&self) -> Result<Script, Error>
100    where
101        Pk: ToPublicKey,
102    {
103        match *self {
104            PreTaprootDescriptor::Bare(ref bare) => bare.explicit_script(),
105            PreTaprootDescriptor::Pkh(ref pkh) => pkh.explicit_script(),
106            PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.explicit_script(),
107            PreTaprootDescriptor::Wsh(ref wsh) => wsh.explicit_script(),
108            PreTaprootDescriptor::Sh(ref sh) => sh.explicit_script(),
109        }
110    }
111
112    /// Returns satisfying non-malleable witness and scriptSig to spend an
113    /// output controlled by the given descriptor if it possible to
114    /// construct one using the satisfier S.
115    fn get_satisfaction<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error>
116    where
117        Pk: ToPublicKey,
118        S: Satisfier<Pk>,
119    {
120        match *self {
121            PreTaprootDescriptor::Bare(ref bare) => bare.get_satisfaction(satisfier),
122            PreTaprootDescriptor::Pkh(ref pkh) => pkh.get_satisfaction(satisfier),
123            PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.get_satisfaction(satisfier),
124            PreTaprootDescriptor::Wsh(ref wsh) => wsh.get_satisfaction(satisfier),
125            PreTaprootDescriptor::Sh(ref sh) => sh.get_satisfaction(satisfier),
126        }
127    }
128
129    /// Returns a possilbly mallable satisfying non-malleable witness and scriptSig to spend an
130    /// output controlled by the given descriptor if it possible to
131    /// construct one using the satisfier S.
132    fn get_satisfaction_mall<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error>
133    where
134        Pk: ToPublicKey,
135        S: Satisfier<Pk>,
136    {
137        match *self {
138            PreTaprootDescriptor::Bare(ref bare) => bare.get_satisfaction_mall(satisfier),
139            PreTaprootDescriptor::Pkh(ref pkh) => pkh.get_satisfaction_mall(satisfier),
140            PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.get_satisfaction_mall(satisfier),
141            PreTaprootDescriptor::Wsh(ref wsh) => wsh.get_satisfaction_mall(satisfier),
142            PreTaprootDescriptor::Sh(ref sh) => sh.get_satisfaction_mall(satisfier),
143        }
144    }
145
146    /// Computes an upper bound on the weight of a satisfying witness to the
147    /// transaction. Assumes all signatures are 73 bytes, including push opcode
148    /// and sighash suffix. Includes the weight of the VarInts encoding the
149    /// scriptSig and witness stack length.
150    fn max_satisfaction_weight(&self) -> Result<usize, Error> {
151        match *self {
152            PreTaprootDescriptor::Bare(ref bare) => bare.max_satisfaction_weight(),
153            PreTaprootDescriptor::Pkh(ref pkh) => pkh.max_satisfaction_weight(),
154            PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.max_satisfaction_weight(),
155            PreTaprootDescriptor::Wsh(ref wsh) => wsh.max_satisfaction_weight(),
156            PreTaprootDescriptor::Sh(ref sh) => sh.max_satisfaction_weight(),
157        }
158    }
159
160    /// Get the `scriptCode` of a transaction output.
161    ///
162    /// The `scriptCode` is the Script of the previous transaction output being serialized in the
163    /// sighash when evaluating a `CHECKSIG` & co. OP code.
164    /// Returns Error for Tr descriptors
165    fn script_code(&self) -> Result<Script, Error>
166    where
167        Pk: ToPublicKey,
168    {
169        match *self {
170            PreTaprootDescriptor::Bare(ref bare) => bare.script_code(),
171            PreTaprootDescriptor::Pkh(ref pkh) => pkh.script_code(),
172            PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.script_code(),
173            PreTaprootDescriptor::Wsh(ref wsh) => wsh.script_code(),
174            PreTaprootDescriptor::Sh(ref sh) => sh.script_code(),
175        }
176    }
177}
178
179impl<Pk> expression::FromTree for PreTaprootDescriptor<Pk>
180where
181    Pk: MiniscriptKey + str::FromStr,
182    Pk::Hash: str::FromStr,
183    <Pk as FromStr>::Err: ToString,
184    <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString,
185{
186    /// Parse an expression tree into a descriptor
187    fn from_tree(top: &expression::Tree) -> Result<PreTaprootDescriptor<Pk>, Error> {
188        Ok(match (top.name, top.args.len() as u32) {
189            ("pkh", 1) => PreTaprootDescriptor::Pkh(Pkh::from_tree(top)?),
190            ("wpkh", 1) => PreTaprootDescriptor::Wpkh(Wpkh::from_tree(top)?),
191            ("sh", 1) => PreTaprootDescriptor::Sh(Sh::from_tree(top)?),
192            ("wsh", 1) => PreTaprootDescriptor::Wsh(Wsh::from_tree(top)?),
193            _ => PreTaprootDescriptor::Bare(Bare::from_tree(top)?),
194        })
195    }
196}
197
198impl<Pk> FromStr for PreTaprootDescriptor<Pk>
199where
200    Pk: MiniscriptKey + str::FromStr,
201    Pk::Hash: str::FromStr,
202    <Pk as FromStr>::Err: ToString,
203    <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString,
204{
205    type Err = Error;
206
207    fn from_str(s: &str) -> Result<PreTaprootDescriptor<Pk>, Error> {
208        let desc_str = verify_checksum(s)?;
209        let top = expression::Tree::from_str(desc_str)?;
210        expression::FromTree::from_tree(&top)
211    }
212}
213
214impl<Pk: MiniscriptKey> fmt::Debug for PreTaprootDescriptor<Pk> {
215    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
216        match *self {
217            PreTaprootDescriptor::Bare(ref sub) => write!(f, "{:?}", sub),
218            PreTaprootDescriptor::Pkh(ref pkh) => write!(f, "{:?}", pkh),
219            PreTaprootDescriptor::Wpkh(ref wpkh) => write!(f, "{:?}", wpkh),
220            PreTaprootDescriptor::Sh(ref sub) => write!(f, "{:?}", sub),
221            PreTaprootDescriptor::Wsh(ref sub) => write!(f, "{:?}", sub),
222        }
223    }
224}
225
226impl<Pk: MiniscriptKey> fmt::Display for PreTaprootDescriptor<Pk> {
227    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
228        match *self {
229            PreTaprootDescriptor::Bare(ref sub) => write!(f, "{}", sub),
230            PreTaprootDescriptor::Pkh(ref pkh) => write!(f, "{}", pkh),
231            PreTaprootDescriptor::Wpkh(ref wpkh) => write!(f, "{}", wpkh),
232            PreTaprootDescriptor::Sh(ref sub) => write!(f, "{}", sub),
233            PreTaprootDescriptor::Wsh(ref sub) => write!(f, "{}", sub),
234        }
235    }
236}
237
238serde_string_impl_pk!(PreTaprootDescriptor, "a pre-taproot script descriptor");
239
240// Have the trait in a separate module to avoid conflicts
241pub(crate) mod traits {
242    use bitcoin::Script;
243
244    use {
245        descriptor::{Pkh, Sh, Wpkh, Wsh},
246        DescriptorTrait, MiniscriptKey, ToPublicKey,
247    };
248
249    use super::PreTaprootDescriptor;
250
251    /// A general trait for Pre taproot bitcoin descriptor.
252    /// Similar to [`DescriptorTrait`], but `explicit_script` and `script_code` methods cannot fail
253    pub trait PreTaprootDescriptorTrait<Pk: MiniscriptKey>: DescriptorTrait<Pk> {
254        /// Same as [`DescriptorTrait::explicit_script`], but a non failing version.
255        /// All PreTaproot descriptors have a unique explicit script
256        fn explicit_script(&self) -> Script
257        where
258            Pk: ToPublicKey,
259        {
260            // This expect can technically be avoided if we implement this for types, but
261            // having this expect saves lots of LoC because of default implementation
262            <Self as DescriptorTrait<Pk>>::explicit_script(&self)
263                .expect("Pre taproot descriptor have explicit script")
264        }
265
266        /// Same as [`DescriptorTrait::script_code`], but a non failing version.
267        /// All PreTaproot descriptors have a script code
268        fn script_code(&self) -> Script
269        where
270            Pk: ToPublicKey,
271        {
272            <Self as DescriptorTrait<Pk>>::script_code(&self)
273                .expect("Pre taproot descriptor have non-failing script code")
274        }
275    }
276
277    impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for Pkh<Pk> {}
278
279    impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for Sh<Pk> {}
280
281    impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for Wpkh<Pk> {}
282
283    impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for Wsh<Pk> {}
284
285    impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for PreTaprootDescriptor<Pk> {}
286}