miniscript/miniscript/types/
mod.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Miniscript Types
4//! Contains structures representing Miniscript types and utility functions
5//! Contains all the type checking rules for correctness and malleability
6//! Implemented as per rules on bitcoin.sipa.be/miniscript
7pub mod correctness;
8pub mod extra_props;
9pub mod malleability;
10
11#[cfg(all(not(feature = "std"), not(test)))]
12use alloc::string::{String, ToString};
13use core::fmt;
14#[cfg(feature = "std")]
15use std::error;
16
17pub use self::correctness::{Base, Correctness, Input};
18pub use self::extra_props::ExtData;
19pub use self::malleability::{Dissat, Malleability};
20use super::ScriptContext;
21use crate::{MiniscriptKey, Terminal};
22
23/// Detailed type of a typechecker error
24#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
25pub enum ErrorKind {
26    /// Passed a `z` argument to a `d` wrapper when `z` was expected
27    NonZeroDupIf,
28    /// Many fragments (all disjunctions except `or_i` as well as
29    /// `andor` require their left child be dissatisfiable.
30    LeftNotDissatisfiable,
31    /// `or_b` requires its right child be dissatisfiable
32    RightNotDissatisfiable,
33    /// Tried to use the `s:` modifier on a fragment that takes more
34    /// than one input
35    SwapNonOne,
36    /// Tried to use the `j:` (`SIZE 0NOTEQUAL IF`) wrapper on something
37    /// that may be satisfied by a 0 input
38    NonZeroZero,
39    /// Many fragments require their left child to be a unit. This
40    /// was not the case.
41    LeftNotUnit,
42    /// Attempted to construct a wrapper, but the child had
43    /// an invalid type
44    ChildBase1(Base),
45    /// Attempted to construct a conjunction or disjunction, but
46    /// the fragments' children were of invalid types
47    ChildBase2(Base, Base),
48    /// Attempted to construct an `andor` but the fragments'
49    /// children were of invalid types
50    ChildBase3(Base, Base, Base),
51    /// The nth child of a threshold fragment had an invalid type (the
52    /// first must be `B` and the rest `W`s)
53    ThresholdBase(usize, Base),
54    /// The nth child of a threshold fragment did not have a unique
55    /// satisfaction
56    ThresholdDissat(usize),
57    /// The nth child of a threshold fragment was not a unit
58    ThresholdNonUnit(usize),
59}
60
61/// Error type for typechecking
62#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
63pub struct Error {
64    /// The fragment that failed typecheck
65    pub fragment_string: String,
66    /// The reason that typechecking failed
67    pub error: ErrorKind,
68}
69
70impl fmt::Display for Error {
71    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72        match self.error {
73            ErrorKind::NonZeroDupIf => write!(
74                f,
75                "fragment «{}» represents needs to be `z`, needs to consume zero elements from the stack",
76                self.fragment_string,
77            ),
78            ErrorKind::LeftNotDissatisfiable => write!(
79                f,
80                "fragment «{}» requires its left child be dissatisfiable",
81                self.fragment_string,
82            ),
83            ErrorKind::RightNotDissatisfiable => write!(
84                f,
85                "fragment «{}» requires its right child be dissatisfiable",
86                self.fragment_string,
87            ),
88            ErrorKind::SwapNonOne => write!(
89                f,
90                "fragment «{}» attempts to use `SWAP` to prefix something
91                 which does not take exactly one input",
92                self.fragment_string,
93            ),
94            ErrorKind::NonZeroZero => write!(
95                f,
96                "fragment «{}» attempts to use use the `j:` wrapper around a
97                 fragment which might be satisfied by an input of size zero",
98                self.fragment_string,
99            ),
100            ErrorKind::LeftNotUnit => write!(
101                f,
102                "fragment «{}» requires its left child be a unit (outputs
103                 exactly 1 given a satisfying input)",
104                self.fragment_string,
105            ),
106            ErrorKind::ChildBase1(base) => write!(
107                f,
108                "fragment «{}» cannot wrap a fragment of type {:?}",
109                self.fragment_string, base,
110            ),
111            ErrorKind::ChildBase2(base1, base2) => write!(
112                f,
113                "fragment «{}» cannot accept children of types {:?} and {:?}",
114                self.fragment_string, base1, base2,
115            ),
116            ErrorKind::ChildBase3(base1, base2, base3) => write!(
117                f,
118                "fragment «{}» cannot accept children of types {:?}, {:?} and {:?}",
119                self.fragment_string, base1, base2, base3,
120            ),
121            ErrorKind::ThresholdBase(idx, base) => write!(
122                f,
123                "fragment «{}» sub-fragment {} has type {:?} rather than {:?}",
124                self.fragment_string,
125                idx,
126                base,
127                if idx == 0 { Base::B } else { Base::W },
128            ),
129            ErrorKind::ThresholdDissat(idx) => write!(
130                f,
131                "fragment «{}» sub-fragment {} can not be dissatisfied \
132                 and cannot be used in a threshold",
133                self.fragment_string, idx,
134            ),
135            ErrorKind::ThresholdNonUnit(idx) => write!(
136                f,
137                "fragment «{}» sub-fragment {} is not a unit (does not put \
138                 exactly 1 on the stack given a satisfying input)",
139                self.fragment_string, idx,
140            ),
141        }
142    }
143}
144
145#[cfg(feature = "std")]
146impl error::Error for Error {
147    fn cause(&self) -> Option<&dyn error::Error> { None }
148}
149
150/// Structure representing the type of a Miniscript fragment, including all
151/// properties relevant to the main codebase
152#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
153pub struct Type {
154    /// Correctness/soundness properties
155    pub corr: Correctness,
156    /// Malleability properties
157    pub mall: Malleability,
158}
159
160impl Type {
161    /// Type of the `0` combinator
162    pub const TRUE: Self = Type { corr: Correctness::TRUE, mall: Malleability::TRUE };
163
164    /// Type of the `0` combinator
165    pub const FALSE: Self = Type { corr: Correctness::FALSE, mall: Malleability::FALSE };
166
167    /// Check whether the `self` is a subtype of `other` argument .
168    /// This checks whether the argument `other` has attributes which are present
169    /// in the given `Type`. This returns `true` on same arguments
170    /// `a.is_subtype(a)` is `true`.
171    pub const fn is_subtype(&self, other: Self) -> bool {
172        self.corr.is_subtype(other.corr) && self.mall.is_subtype(other.mall)
173    }
174
175    /// Confirm invariants of the type checker.
176    pub fn sanity_checks(&self) {
177        debug_assert!(!self.corr.dissatisfiable || self.mall.dissat != Dissat::None);
178        debug_assert!(self.mall.dissat == Dissat::None || self.corr.base != Base::V);
179        debug_assert!(self.mall.safe || self.corr.base != Base::K);
180        debug_assert!(self.mall.non_malleable || self.corr.input != Input::Zero);
181    }
182
183    /// Constructor for the type of the `pk_k` fragment.
184    pub const fn pk_k() -> Self { Type { corr: Correctness::pk_k(), mall: Malleability::pk_k() } }
185
186    /// Constructor for the type of the `pk_h` fragment.
187    pub const fn pk_h() -> Self { Type { corr: Correctness::pk_h(), mall: Malleability::pk_h() } }
188
189    /// Constructor for the type of the `multi` fragment.
190    pub const fn multi() -> Self {
191        Type { corr: Correctness::multi(), mall: Malleability::multi() }
192    }
193
194    /// Constructor for the type of the `multi_a` fragment.
195    pub const fn multi_a() -> Self {
196        Type { corr: Correctness::multi_a(), mall: Malleability::multi_a() }
197    }
198
199    /// Constructor for the type of all the hash fragments.
200    pub const fn hash() -> Self { Type { corr: Correctness::hash(), mall: Malleability::hash() } }
201
202    /// Constructor for the type of the `after` and `older` fragments.
203    pub const fn time() -> Self { Type { corr: Correctness::time(), mall: Malleability::time() } }
204
205    /// Constructor for the type of the `a:` fragment.
206    pub const fn cast_alt(self) -> Result<Self, ErrorKind> {
207        // FIXME need to do manual `?` because ? is not supported in constfns. (Also below.)
208        Ok(Type {
209            corr: match Correctness::cast_alt(self.corr) {
210                Ok(x) => x,
211                Err(e) => return Err(e),
212            },
213            mall: Malleability::cast_alt(self.mall),
214        })
215    }
216
217    /// Constructor for the type of the `s:` fragment.
218    pub const fn cast_swap(self) -> Result<Self, ErrorKind> {
219        Ok(Type {
220            corr: match Correctness::cast_swap(self.corr) {
221                Ok(x) => x,
222                Err(e) => return Err(e),
223            },
224            mall: Malleability::cast_swap(self.mall),
225        })
226    }
227
228    /// Constructor for the type of the `c:` fragment.
229    pub const fn cast_check(self) -> Result<Self, ErrorKind> {
230        Ok(Type {
231            corr: match Correctness::cast_check(self.corr) {
232                Ok(x) => x,
233                Err(e) => return Err(e),
234            },
235            mall: Malleability::cast_check(self.mall),
236        })
237    }
238
239    /// Constructor for the type of the `d:` fragment.
240    pub const fn cast_dupif(self) -> Result<Self, ErrorKind> {
241        Ok(Type {
242            corr: match Correctness::cast_dupif(self.corr) {
243                Ok(x) => x,
244                Err(e) => return Err(e),
245            },
246            mall: Malleability::cast_dupif(self.mall),
247        })
248    }
249
250    /// Constructor for the type of the `v:` fragment.
251    pub const fn cast_verify(self) -> Result<Self, ErrorKind> {
252        Ok(Type {
253            corr: match Correctness::cast_verify(self.corr) {
254                Ok(x) => x,
255                Err(e) => return Err(e),
256            },
257            mall: Malleability::cast_verify(self.mall),
258        })
259    }
260
261    /// Constructor for the type of the `j:` fragment.
262    pub const fn cast_nonzero(self) -> Result<Self, ErrorKind> {
263        Ok(Type {
264            corr: match Correctness::cast_nonzero(self.corr) {
265                Ok(x) => x,
266                Err(e) => return Err(e),
267            },
268            mall: Malleability::cast_nonzero(self.mall),
269        })
270    }
271
272    /// Constructor for the type of the `n:` fragment.
273    pub const fn cast_zeronotequal(self) -> Result<Self, ErrorKind> {
274        Ok(Type {
275            corr: match Correctness::cast_zeronotequal(self.corr) {
276                Ok(x) => x,
277                Err(e) => return Err(e),
278            },
279            mall: Malleability::cast_zeronotequal(self.mall),
280        })
281    }
282
283    /// Constructor for the type of the `t:` fragment.
284    pub const fn cast_true(self) -> Result<Self, ErrorKind> {
285        Ok(Type {
286            corr: match Correctness::cast_true(self.corr) {
287                Ok(x) => x,
288                Err(e) => return Err(e),
289            },
290            mall: Malleability::cast_true(self.mall),
291        })
292    }
293
294    /// Constructor for the type of the `u:` fragment.
295    pub const fn cast_unlikely(self) -> Result<Self, ErrorKind> {
296        Ok(Type {
297            corr: match Correctness::cast_or_i_false(self.corr) {
298                Ok(x) => x,
299                Err(e) => return Err(e),
300            },
301            mall: Malleability::cast_or_i_false(self.mall),
302        })
303    }
304
305    /// Constructor for the type of the `l:` fragment.
306    pub const fn cast_likely(self) -> Result<Self, ErrorKind> {
307        Ok(Type {
308            corr: match Correctness::cast_or_i_false(self.corr) {
309                Ok(x) => x,
310                Err(e) => return Err(e),
311            },
312            mall: Malleability::cast_or_i_false(self.mall),
313        })
314    }
315
316    /// Constructor for the type of the `and_b` fragment.
317    pub const fn and_b(left: Self, right: Self) -> Result<Self, ErrorKind> {
318        Ok(Type {
319            corr: match Correctness::and_b(left.corr, right.corr) {
320                Ok(x) => x,
321                Err(e) => return Err(e),
322            },
323            mall: Malleability::and_b(left.mall, right.mall),
324        })
325    }
326
327    /// Constructor for the type of the `and_v` fragment.
328    pub const fn and_v(left: Self, right: Self) -> Result<Self, ErrorKind> {
329        Ok(Type {
330            corr: match Correctness::and_v(left.corr, right.corr) {
331                Ok(x) => x,
332                Err(e) => return Err(e),
333            },
334            mall: Malleability::and_v(left.mall, right.mall),
335        })
336    }
337
338    /// Constructor for the type of the `or_b` fragment.
339    pub const fn or_b(left: Self, right: Self) -> Result<Self, ErrorKind> {
340        Ok(Type {
341            corr: match Correctness::or_b(left.corr, right.corr) {
342                Ok(x) => x,
343                Err(e) => return Err(e),
344            },
345            mall: Malleability::or_b(left.mall, right.mall),
346        })
347    }
348
349    /// Constructor for the type of the `or_b` fragment.
350    pub const fn or_d(left: Self, right: Self) -> Result<Self, ErrorKind> {
351        Ok(Type {
352            corr: match Correctness::or_d(left.corr, right.corr) {
353                Ok(x) => x,
354                Err(e) => return Err(e),
355            },
356            mall: Malleability::or_d(left.mall, right.mall),
357        })
358    }
359
360    /// Constructor for the type of the `or_c` fragment.
361    pub const fn or_c(left: Self, right: Self) -> Result<Self, ErrorKind> {
362        Ok(Type {
363            corr: match Correctness::or_c(left.corr, right.corr) {
364                Ok(x) => x,
365                Err(e) => return Err(e),
366            },
367            mall: Malleability::or_c(left.mall, right.mall),
368        })
369    }
370
371    /// Constructor for the type of the `or_i` fragment.
372    pub const fn or_i(left: Self, right: Self) -> Result<Self, ErrorKind> {
373        Ok(Type {
374            corr: match Correctness::or_i(left.corr, right.corr) {
375                Ok(x) => x,
376                Err(e) => return Err(e),
377            },
378            mall: Malleability::or_i(left.mall, right.mall),
379        })
380    }
381
382    /// Constructor for the type of the `and_or` fragment.
383    pub const fn and_or(a: Self, b: Self, c: Self) -> Result<Self, ErrorKind> {
384        Ok(Type {
385            corr: match Correctness::and_or(a.corr, b.corr, c.corr) {
386                Ok(x) => x,
387                Err(e) => return Err(e),
388            },
389            mall: Malleability::and_or(a.mall, b.mall, c.mall),
390        })
391    }
392
393    /// Constructor for the type of the `thresh` fragment.
394    // Cannot be a constfn because it takes a closure.
395    pub fn threshold<'a, I>(k: usize, subs: I) -> Result<Self, ErrorKind>
396    where
397        I: Clone + ExactSizeIterator<Item = &'a Self>,
398    {
399        Ok(Type {
400            corr: Correctness::threshold(k, subs.clone().map(|s| &s.corr))?,
401            mall: Malleability::threshold(k, subs.map(|s| &s.mall)),
402        })
403    }
404}
405
406impl Type {
407    /// Compute the type of a fragment assuming all the children of
408    /// Miniscript have been computed already.
409    pub fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error>
410    where
411        Pk: MiniscriptKey,
412        Ctx: ScriptContext,
413    {
414        let wrap_err = |result: Result<Self, ErrorKind>| {
415            result.map_err(|kind| Error { fragment_string: fragment.to_string(), error: kind })
416        };
417
418        let ret = match *fragment {
419            Terminal::True => Ok(Self::TRUE),
420            Terminal::False => Ok(Self::FALSE),
421            Terminal::PkK(..) => Ok(Self::pk_k()),
422            Terminal::PkH(..) | Terminal::RawPkH(..) => Ok(Self::pk_h()),
423            Terminal::Multi(..) => Ok(Self::multi()),
424            Terminal::MultiA(..) => Ok(Self::multi_a()),
425            Terminal::After(_) => Ok(Self::time()),
426            Terminal::Older(_) => Ok(Self::time()),
427            Terminal::Sha256(..) => Ok(Self::hash()),
428            Terminal::Hash256(..) => Ok(Self::hash()),
429            Terminal::Ripemd160(..) => Ok(Self::hash()),
430            Terminal::Hash160(..) => Ok(Self::hash()),
431            Terminal::Alt(ref sub) => wrap_err(Self::cast_alt(sub.ty)),
432            Terminal::Swap(ref sub) => wrap_err(Self::cast_swap(sub.ty)),
433            Terminal::Check(ref sub) => wrap_err(Self::cast_check(sub.ty)),
434            Terminal::DupIf(ref sub) => wrap_err(Self::cast_dupif(sub.ty)),
435            Terminal::Verify(ref sub) => wrap_err(Self::cast_verify(sub.ty)),
436            Terminal::NonZero(ref sub) => wrap_err(Self::cast_nonzero(sub.ty)),
437            Terminal::ZeroNotEqual(ref sub) => wrap_err(Self::cast_zeronotequal(sub.ty)),
438            Terminal::AndB(ref l, ref r) => {
439                let ltype = l.ty;
440                let rtype = r.ty;
441                wrap_err(Self::and_b(ltype, rtype))
442            }
443            Terminal::AndV(ref l, ref r) => {
444                let ltype = l.ty;
445                let rtype = r.ty;
446                wrap_err(Self::and_v(ltype, rtype))
447            }
448            Terminal::OrB(ref l, ref r) => {
449                let ltype = l.ty;
450                let rtype = r.ty;
451                wrap_err(Self::or_b(ltype, rtype))
452            }
453            Terminal::OrD(ref l, ref r) => {
454                let ltype = l.ty;
455                let rtype = r.ty;
456                wrap_err(Self::or_d(ltype, rtype))
457            }
458            Terminal::OrC(ref l, ref r) => {
459                let ltype = l.ty;
460                let rtype = r.ty;
461                wrap_err(Self::or_c(ltype, rtype))
462            }
463            Terminal::OrI(ref l, ref r) => {
464                let ltype = l.ty;
465                let rtype = r.ty;
466                wrap_err(Self::or_i(ltype, rtype))
467            }
468            Terminal::AndOr(ref a, ref b, ref c) => {
469                let atype = a.ty;
470                let btype = b.ty;
471                let ctype = c.ty;
472                wrap_err(Self::and_or(atype, btype, ctype))
473            }
474            Terminal::Thresh(ref thresh) => {
475                let res = Self::threshold(thresh.k(), thresh.iter().map(|ms| &ms.ty));
476                res.map_err(|kind| Error { fragment_string: fragment.to_string(), error: kind })
477            }
478        };
479        if let Ok(ref ret) = ret {
480            ret.sanity_checks()
481        }
482        ret
483    }
484}