1pub 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#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
25pub enum ErrorKind {
26 NonZeroDupIf,
28 LeftNotDissatisfiable,
31 RightNotDissatisfiable,
33 SwapNonOne,
36 NonZeroZero,
39 LeftNotUnit,
42 ChildBase1(Base),
45 ChildBase2(Base, Base),
48 ChildBase3(Base, Base, Base),
51 ThresholdBase(usize, Base),
54 ThresholdDissat(usize),
57 ThresholdNonUnit(usize),
59}
60
61#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
63pub struct Error {
64 pub fragment_string: String,
66 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#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
153pub struct Type {
154 pub corr: Correctness,
156 pub mall: Malleability,
158}
159
160impl Type {
161 pub const TRUE: Self = Type { corr: Correctness::TRUE, mall: Malleability::TRUE };
163
164 pub const FALSE: Self = Type { corr: Correctness::FALSE, mall: Malleability::FALSE };
166
167 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 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 pub const fn pk_k() -> Self { Type { corr: Correctness::pk_k(), mall: Malleability::pk_k() } }
185
186 pub const fn pk_h() -> Self { Type { corr: Correctness::pk_h(), mall: Malleability::pk_h() } }
188
189 pub const fn multi() -> Self {
191 Type { corr: Correctness::multi(), mall: Malleability::multi() }
192 }
193
194 pub const fn multi_a() -> Self {
196 Type { corr: Correctness::multi_a(), mall: Malleability::multi_a() }
197 }
198
199 pub const fn hash() -> Self { Type { corr: Correctness::hash(), mall: Malleability::hash() } }
201
202 pub const fn time() -> Self { Type { corr: Correctness::time(), mall: Malleability::time() } }
204
205 pub const fn cast_alt(self) -> Result<Self, ErrorKind> {
207 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}