elements_miniscript/miniscript/
context.rs

1// Written in 2019 by Sanket Kanjalkar and Andrew Poelstra
2// SPDX-License-Identifier: CC0-1.0
3
4use std::{error, fmt, hash};
5
6use bitcoin::hashes::{hash160, ripemd160, sha256};
7use bitcoin::{self, Weight};
8
9use super::decode::ParseableKey;
10use crate::miniscript::limits::{
11    MAX_OPS_PER_SCRIPT, MAX_PUBKEYS_PER_MULTISIG, MAX_SCRIPTSIG_SIZE, MAX_SCRIPT_ELEMENT_SIZE,
12    MAX_SCRIPT_SIZE, MAX_STACK_SIZE, MAX_STANDARD_P2WSH_SCRIPT_SIZE,
13    MAX_STANDARD_P2WSH_STACK_ITEMS,
14};
15use crate::miniscript::types;
16use crate::util::witness_to_scriptsig;
17pub use crate::SigType;
18use crate::{hash256, Error, Extension, Miniscript, MiniscriptKey, Terminal};
19
20/// Error for Script Context
21#[derive(Clone, PartialEq, Eq, Debug)]
22pub enum ScriptContextError {
23    /// Script Context does not permit PkH for non-malleability
24    /// It is not possible to estimate the pubkey size at the creation
25    /// time because of uncompressed pubkeys
26    MalleablePkH,
27    /// Script Context does not permit OrI for non-malleability
28    /// Legacy fragments allow non-minimal IF which results in malleability
29    MalleableOrI,
30    /// Script Context does not permit DupIf for non-malleability
31    /// Legacy fragments allow non-minimal IF which results in malleability
32    MalleableDupIf,
33    /// Only Compressed keys allowed under current descriptor
34    /// Segwitv0 fragments do not allow uncompressed pubkeys
35    CompressedOnly(String),
36    /// XOnly keys are only allowed in Tap context
37    /// The first element is key, and second element is current script context
38    XOnlyKeysNotAllowed(String, &'static str),
39    /// Tapscript descriptors cannot contain uncompressed keys
40    /// Tap context can contain compressed or xonly
41    UncompressedKeysNotAllowed,
42    /// At least one satisfaction path in the Miniscript fragment has more than
43    /// `MAX_STANDARD_P2WSH_STACK_ITEMS` (100) witness elements.
44    MaxWitnessItemssExceeded { actual: usize, limit: usize },
45    /// At least one satisfaction path in the Miniscript fragment contains more
46    /// than `MAX_OPS_PER_SCRIPT`(201) opcodes.
47    MaxOpCountExceeded,
48    /// The Miniscript(under segwit context) corresponding
49    /// Script would be larger than `MAX_STANDARD_P2WSH_SCRIPT_SIZE` bytes.
50    MaxWitnessScriptSizeExceeded,
51    /// The Miniscript (under p2sh context) corresponding Script would be
52    /// larger than `MAX_SCRIPT_ELEMENT_SIZE` bytes.
53    MaxRedeemScriptSizeExceeded,
54    /// The policy rules of bitcoin core only permit Script size upto 1650 bytes
55    MaxScriptSigSizeExceeded,
56    /// Impossible to satisfy the miniscript under the current context
57    ImpossibleSatisfaction,
58    /// Covenant Prefix/ Suffix maximum allowed stack element exceeds 520 bytes
59    CovElementSizeExceeded,
60    /// No Multi Node in Taproot context
61    TaprootMultiDisabled,
62    /// Stack size exceeded in script execution
63    StackSizeLimitExceeded { actual: usize, limit: usize },
64    /// More than 20 keys in a Multi fragment
65    CheckMultiSigLimitExceeded,
66    /// MultiA is only allowed in post tapscript
67    MultiANotAllowed,
68    /// Extension Error for Downstream implementations, includes a string
69    ExtensionError(String),
70}
71
72impl error::Error for ScriptContextError {
73    fn cause(&self) -> Option<&dyn error::Error> {
74        use self::ScriptContextError::*;
75
76        match self {
77            MalleablePkH
78            | MalleableOrI
79            | MalleableDupIf
80            | CompressedOnly(_)
81            | XOnlyKeysNotAllowed(_, _)
82            | UncompressedKeysNotAllowed
83            | MaxWitnessItemssExceeded { .. }
84            | MaxOpCountExceeded
85            | MaxWitnessScriptSizeExceeded
86            | MaxRedeemScriptSizeExceeded
87            | MaxScriptSigSizeExceeded
88            | ImpossibleSatisfaction
89            | TaprootMultiDisabled
90            | StackSizeLimitExceeded { .. }
91            | CheckMultiSigLimitExceeded
92            | MultiANotAllowed
93            | CovElementSizeExceeded
94            | ExtensionError(_) => None,
95        }
96    }
97}
98
99impl fmt::Display for ScriptContextError {
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        match *self {
102            ScriptContextError::MalleablePkH => write!(f, "PkH is malleable under Legacy rules"),
103            ScriptContextError::MalleableOrI => write!(f, "OrI is malleable under Legacy rules"),
104            ScriptContextError::MalleableDupIf => {
105                write!(f, "DupIf is malleable under Legacy rules")
106            }
107            ScriptContextError::CompressedOnly(ref pk) => {
108                write!(
109                    f,
110                    "Only Compressed pubkeys are allowed in segwit context. Found {}",
111                    pk
112                )
113            }
114            ScriptContextError::XOnlyKeysNotAllowed(ref pk, ref ctx) => {
115                write!(f, "x-only key {} not allowed in {}", pk, ctx)
116            }
117            ScriptContextError::UncompressedKeysNotAllowed => {
118                write!(
119                    f,
120                    "uncompressed keys cannot be used in Taproot descriptors."
121                )
122            }
123            ScriptContextError::MaxWitnessItemssExceeded { actual, limit } => write!(
124                f,
125                "At least one spending path in the Miniscript fragment has {} more \
126                 witness items than limit {}.",
127                actual, limit
128            ),
129            ScriptContextError::MaxOpCountExceeded => write!(
130                f,
131                "At least one satisfaction path in the Miniscript fragment contains \
132                 more than MAX_OPS_PER_SCRIPT opcodes."
133            ),
134            ScriptContextError::MaxWitnessScriptSizeExceeded => write!(
135                f,
136                "The Miniscript corresponding Script would be larger than \
137                    MAX_STANDARD_P2WSH_SCRIPT_SIZE bytes."
138            ),
139            ScriptContextError::MaxRedeemScriptSizeExceeded => write!(
140                f,
141                "The Miniscript corresponding Script would be larger than \
142                MAX_SCRIPT_ELEMENT_SIZE bytes."
143            ),
144            ScriptContextError::MaxScriptSigSizeExceeded => write!(
145                f,
146                "At least one satisfaction in Miniscript would be larger than \
147                MAX_SCRIPTSIG_SIZE scriptsig"
148            ),
149            ScriptContextError::ImpossibleSatisfaction => {
150                write!(
151                    f,
152                    "Impossible to satisfy Miniscript under the current context"
153                )
154            }
155            ScriptContextError::CovElementSizeExceeded => {
156                write!(
157                    f,
158                    "Prefix/Suffix len in sighash covenents exceeds 520 bytes"
159                )
160            }
161            ScriptContextError::TaprootMultiDisabled => {
162                write!(f, "Invalid use of Multi node in taproot context")
163            }
164            ScriptContextError::StackSizeLimitExceeded { actual, limit } => {
165                write!(
166                    f,
167                    "Stack limit {} can exceed the allowed limit {} in at least one script path during script execution",
168                    actual, limit
169                )
170            }
171            ScriptContextError::CheckMultiSigLimitExceeded => {
172                write!(
173                    f,
174                    "CHECkMULTISIG ('multi()' descriptor) only supports up to 20 pubkeys"
175                )
176            }
177            ScriptContextError::MultiANotAllowed => {
178                write!(f, "Multi a(CHECKSIGADD) only allowed post tapscript")
179            }
180            ScriptContextError::ExtensionError(ref s) => write!(f, "Extension Error: {}", s),
181        }
182    }
183}
184
185/// The ScriptContext for Miniscript. Additional type information associated with
186/// miniscript that is used for carrying out checks that dependent on the
187/// context under which the script is used.
188/// For example, disallowing uncompressed keys in Segwit context
189pub trait ScriptContext:
190    fmt::Debug + Clone + Ord + PartialOrd + Eq + PartialEq + hash::Hash + private::Sealed
191where
192    Self::Key: MiniscriptKey<Sha256 = sha256::Hash>,
193    Self::Key: MiniscriptKey<Hash256 = hash256::Hash>,
194    Self::Key: MiniscriptKey<Ripemd160 = ripemd160::Hash>,
195    Self::Key: MiniscriptKey<Hash160 = hash160::Hash>,
196{
197    /// The consensus key associated with the type. Must be a parseable key
198    type Key: ParseableKey;
199    /// Depending on ScriptContext, fragments can be malleable. For Example,
200    /// under Legacy context, PkH is malleable because it is possible to
201    /// estimate the cost of satisfaction because of compressed keys
202    /// This is currently only used in compiler code for removing malleable
203    /// compilations.
204    /// This does NOT recursively check if the children of the fragment are
205    /// valid or not. Since the compilation proceeds in a leaf to root fashion,
206    /// a recursive check is unnecessary.
207    fn check_terminal_non_malleable<Pk, Ext>(
208        _frag: &Terminal<Pk, Self, Ext>,
209    ) -> Result<(), ScriptContextError>
210    where
211        Pk: MiniscriptKey,
212        Ext: Extension;
213
214    /// Check whether the given satisfaction is valid under the ScriptContext
215    /// For example, segwit satisfactions may fail if the witness len is more
216    /// 3600 or number of stack elements are more than 100.
217    fn check_witness<Pk, Ext>(_witness: &[Vec<u8>]) -> Result<(), ScriptContextError>
218    where
219        Pk: MiniscriptKey,
220        Ext: Extension,
221    {
222        // Only really need to do this for segwitv0 and legacy
223        // Bare is already restrcited by standardness rules
224        // and would reach these limits.
225        Ok(())
226    }
227
228    /// Depending on script context, the size of a satifaction witness may slightly differ.
229    fn max_satisfaction_size<Pk, Ext>(ms: &Miniscript<Pk, Self, Ext>) -> Option<usize>
230    where
231        Pk: MiniscriptKey,
232        Ext: Extension;
233    /// Depending on script Context, some of the Terminals might not
234    /// be valid under the current consensus rules.
235    /// Or some of the script resource limits may have been exceeded.
236    /// These miniscripts would never be accepted by the Bitcoin network and hence
237    /// it is safe to discard them
238    /// For example, in Segwit Context with MiniscriptKey as bitcoin::PublicKey
239    /// uncompressed public keys are non-standard and thus invalid.
240    /// In LegacyP2SH context, scripts above 520 bytes are invalid.
241    /// Post Tapscript upgrade, this would have to consider other nodes.
242    /// This does *NOT* recursively check the miniscript fragments.
243    fn check_global_consensus_validity<Pk: MiniscriptKey, Ext: Extension>(
244        _ms: &Miniscript<Pk, Self, Ext>,
245    ) -> Result<(), ScriptContextError> {
246        Ok(())
247    }
248
249    /// Depending on script Context, some of the script resource limits
250    /// may have been exceeded under the current bitcoin core policy rules
251    /// These miniscripts would never be accepted by the Bitcoin network and hence
252    /// it is safe to discard them. (unless explicitly disabled by non-standard flag)
253    /// For example, in Segwit Context with MiniscriptKey as bitcoin::PublicKey
254    /// scripts over 3600 bytes are invalid.
255    /// Post Tapscript upgrade, this would have to consider other nodes.
256    /// This does *NOT* recursively check the miniscript fragments.
257    fn check_global_policy_validity<Pk: MiniscriptKey, Ext: Extension>(
258        _ms: &Miniscript<Pk, Self, Ext>,
259    ) -> Result<(), ScriptContextError> {
260        Ok(())
261    }
262
263    /// Consensus rules at the Miniscript satisfaction time.
264    /// It is possible that some paths of miniscript may exceed resource limits
265    /// and our current satisfier and lifting analysis would not work correctly.
266    /// For example, satisfaction path(Legacy/Segwitv0) may require more than 201 opcodes.
267    fn check_local_consensus_validity<Pk: MiniscriptKey, Ext: Extension>(
268        _ms: &Miniscript<Pk, Self, Ext>,
269    ) -> Result<(), ScriptContextError> {
270        Ok(())
271    }
272
273    /// Policy rules at the Miniscript satisfaction time.
274    /// It is possible that some paths of miniscript may exceed resource limits
275    /// and our current satisfier and lifting analysis would not work correctly.
276    /// For example, satisfaction path in Legacy context scriptSig more
277    /// than 1650 bytes
278    fn check_local_policy_validity<Pk: MiniscriptKey, Ext: Extension>(
279        _ms: &Miniscript<Pk, Self, Ext>,
280    ) -> Result<(), ScriptContextError> {
281        Ok(())
282    }
283
284    /// Check the consensus + policy(if not disabled) rules that are not based
285    /// satisfaction
286    fn check_global_validity<Pk, Ext>(
287        ms: &Miniscript<Pk, Self, Ext>,
288    ) -> Result<(), ScriptContextError>
289    where
290        Pk: MiniscriptKey,
291        Ext: Extension,
292    {
293        Self::check_global_consensus_validity(ms)?;
294        Self::check_global_policy_validity(ms)?;
295        Ok(())
296    }
297
298    /// Check the consensus + policy(if not disabled) rules including the
299    /// ones for satisfaction
300    fn check_local_validity<Pk: MiniscriptKey, Ext: Extension>(
301        ms: &Miniscript<Pk, Self, Ext>,
302    ) -> Result<(), ScriptContextError> {
303        Self::check_global_consensus_validity(ms)?;
304        Self::check_global_policy_validity(ms)?;
305        Self::check_local_consensus_validity(ms)?;
306        Self::check_local_policy_validity(ms)?;
307        Ok(())
308    }
309
310    /// Check whether the top-level is type B
311    fn top_level_type_check<Pk: MiniscriptKey, Ext: Extension>(
312        ms: &Miniscript<Pk, Self, Ext>,
313    ) -> Result<(), Error> {
314        if ms.ty.corr.base != types::Base::B {
315            return Err(Error::NonTopLevel(format!("{:?}", ms)));
316        }
317        Ok(())
318    }
319
320    /// Other top level checks that are context specific
321    fn other_top_level_checks<Pk, Ext>(_ms: &Miniscript<Pk, Self, Ext>) -> Result<(), Error>
322    where
323        Pk: MiniscriptKey,
324        Ext: Extension,
325    {
326        Ok(())
327    }
328
329    /// Check top level consensus rules.
330    // All the previous check_ were applied at each fragment while parsing script
331    // Because if any of sub-miniscripts failed the reource level check, the entire
332    // miniscript would also be invalid. However, there are certain checks like
333    // in Bare context, only c:pk(key) (P2PK),
334    // c:pk_h(key) (P2PKH), and thresh_m(k,...) up to n=3 are allowed
335    // that are only applicable at the top-level
336    // We can also combine the top-level check for Base::B here
337    // even though it does not depend on context, but helps in cleaner code
338    fn top_level_checks<Pk: MiniscriptKey, Ext: Extension>(
339        ms: &Miniscript<Pk, Self, Ext>,
340    ) -> Result<(), Error> {
341        Self::top_level_type_check(ms)?;
342        Self::other_top_level_checks(ms)
343    }
344
345    /// The type of signature required for satisfaction
346    // We need to context decide whether the serialize pk to 33 byte or 32 bytes.
347    // And to decide which type of signatures to look for during satisfaction
348    fn sig_type() -> SigType;
349
350    /// Get the len of public key when serialized based on context
351    /// Note that this includes the serialization prefix. Returns
352    /// 34/66 for Bare/Legacy based on key compressedness
353    /// 34 for Segwitv0, 33 for Tap
354    fn pk_len<Pk: MiniscriptKey>(pk: &Pk) -> usize;
355
356    /// Local helper function to display error messages with context
357    fn name_str() -> &'static str;
358}
359
360/// Legacy ScriptContext
361/// To be used as P2SH scripts
362/// For creation of Bare scriptpubkeys, construct the Miniscript
363/// under `Bare` ScriptContext
364#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
365pub enum Legacy {}
366
367impl ScriptContext for Legacy {
368    type Key = bitcoin::PublicKey;
369
370    fn check_terminal_non_malleable<Pk: MiniscriptKey, Ext: Extension>(
371        frag: &Terminal<Pk, Self, Ext>,
372    ) -> Result<(), ScriptContextError> {
373        match *frag {
374            Terminal::PkH(ref _pkh) => Err(ScriptContextError::MalleablePkH),
375            Terminal::RawPkH(ref _pk) => Err(ScriptContextError::MalleablePkH),
376            Terminal::OrI(ref _a, ref _b) => Err(ScriptContextError::MalleableOrI),
377            Terminal::DupIf(ref _ms) => Err(ScriptContextError::MalleableDupIf),
378            _ => Ok(()),
379        }
380    }
381
382    fn check_witness<Pk: MiniscriptKey, Ext: Extension>(
383        witness: &[Vec<u8>],
384    ) -> Result<(), ScriptContextError> {
385        // In future, we could avoid by having a function to count only
386        // len of script instead of converting it.
387        if witness_to_scriptsig(witness).len() > MAX_SCRIPTSIG_SIZE {
388            return Err(ScriptContextError::MaxScriptSigSizeExceeded);
389        }
390        Ok(())
391    }
392
393    fn check_global_consensus_validity<Pk: MiniscriptKey, Ext: Extension>(
394        ms: &Miniscript<Pk, Self, Ext>,
395    ) -> Result<(), ScriptContextError> {
396        if ms.ext.pk_cost > MAX_SCRIPT_ELEMENT_SIZE {
397            return Err(ScriptContextError::MaxRedeemScriptSizeExceeded);
398        }
399
400        match ms.node {
401            Terminal::PkK(ref key) if key.is_x_only_key() => {
402                return Err(ScriptContextError::XOnlyKeysNotAllowed(
403                    key.to_string(),
404                    Self::name_str(),
405                ))
406            }
407            Terminal::Multi(_k, ref pks) => {
408                if pks.len() > MAX_PUBKEYS_PER_MULTISIG {
409                    return Err(ScriptContextError::CheckMultiSigLimitExceeded);
410                }
411                for pk in pks.iter() {
412                    if pk.is_x_only_key() {
413                        return Err(ScriptContextError::XOnlyKeysNotAllowed(
414                            pk.to_string(),
415                            Self::name_str(),
416                        ));
417                    }
418                }
419            }
420            Terminal::MultiA(..) => {
421                return Err(ScriptContextError::MultiANotAllowed);
422            }
423            _ => {}
424        }
425        if let Terminal::Ext(ref _e) = ms.node {
426            return Err(ScriptContextError::ExtensionError(String::from(
427                "No Extensions in Legacy context",
428            )));
429        }
430        Ok(())
431    }
432
433    fn check_local_consensus_validity<Pk: MiniscriptKey, Ext: Extension>(
434        ms: &Miniscript<Pk, Self, Ext>,
435    ) -> Result<(), ScriptContextError> {
436        match ms.ext.ops.op_count() {
437            None => Err(ScriptContextError::MaxOpCountExceeded),
438            Some(op_count) if op_count > MAX_OPS_PER_SCRIPT => {
439                Err(ScriptContextError::MaxOpCountExceeded)
440            }
441            _ => Ok(()),
442        }
443    }
444
445    fn check_local_policy_validity<Pk: MiniscriptKey, Ext: Extension>(
446        ms: &Miniscript<Pk, Self, Ext>,
447    ) -> Result<(), ScriptContextError> {
448        // Legacy scripts permit upto 1000 stack elements, 520 bytes consensus limits
449        // on P2SH size, it is not possible to reach the 1000 elements limit and hence
450        // we do not check it.
451        match ms.max_satisfaction_size() {
452            Err(_e) => Err(ScriptContextError::ImpossibleSatisfaction),
453            Ok(size) if size > MAX_SCRIPTSIG_SIZE => {
454                Err(ScriptContextError::MaxScriptSigSizeExceeded)
455            }
456            _ => Ok(()),
457        }
458    }
459
460    fn max_satisfaction_size<Pk: MiniscriptKey, Ext: Extension>(
461        ms: &Miniscript<Pk, Self, Ext>,
462    ) -> Option<usize> {
463        // The scriptSig cost is the second element of the tuple
464        ms.ext.max_sat_size.map(|x| x.1)
465    }
466
467    fn pk_len<Pk: MiniscriptKey>(pk: &Pk) -> usize {
468        if pk.is_uncompressed() {
469            66
470        } else {
471            34
472        }
473    }
474
475    fn name_str() -> &'static str {
476        "Legacy/p2sh"
477    }
478
479    fn sig_type() -> SigType {
480        SigType::Ecdsa
481    }
482}
483
484/// Segwitv0 ScriptContext
485#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
486pub enum Segwitv0 {}
487
488impl ScriptContext for Segwitv0 {
489    type Key = bitcoin::PublicKey;
490
491    fn check_terminal_non_malleable<Pk: MiniscriptKey, Ext: Extension>(
492        _frag: &Terminal<Pk, Self, Ext>,
493    ) -> Result<(), ScriptContextError> {
494        Ok(())
495    }
496
497    fn check_witness<Pk: MiniscriptKey, Ext: Extension>(
498        witness: &[Vec<u8>],
499    ) -> Result<(), ScriptContextError> {
500        if witness.len() > MAX_STANDARD_P2WSH_STACK_ITEMS {
501            return Err(ScriptContextError::MaxWitnessItemssExceeded {
502                actual: witness.len(),
503                limit: MAX_STANDARD_P2WSH_STACK_ITEMS,
504            });
505        }
506        Ok(())
507    }
508
509    fn check_global_consensus_validity<Pk: MiniscriptKey, Ext: Extension>(
510        ms: &Miniscript<Pk, Self, Ext>,
511    ) -> Result<(), ScriptContextError> {
512        if ms.ext.pk_cost > MAX_SCRIPT_SIZE {
513            return Err(ScriptContextError::MaxWitnessScriptSizeExceeded);
514        }
515
516        match ms.node {
517            Terminal::PkK(ref pk) => {
518                if pk.is_uncompressed() {
519                    return Err(ScriptContextError::CompressedOnly(pk.to_string()));
520                } else if pk.is_x_only_key() {
521                    return Err(ScriptContextError::XOnlyKeysNotAllowed(
522                        pk.to_string(),
523                        Self::name_str(),
524                    ));
525                }
526                Ok(())
527            }
528            Terminal::Multi(_k, ref pks) => {
529                if pks.len() > MAX_PUBKEYS_PER_MULTISIG {
530                    return Err(ScriptContextError::CheckMultiSigLimitExceeded);
531                }
532                for pk in pks.iter() {
533                    if pk.is_uncompressed() {
534                        return Err(ScriptContextError::CompressedOnly(pk.to_string()));
535                    } else if pk.is_x_only_key() {
536                        return Err(ScriptContextError::XOnlyKeysNotAllowed(
537                            pk.to_string(),
538                            Self::name_str(),
539                        ));
540                    }
541                }
542                Ok(())
543            }
544            Terminal::Ext(ref e) => {
545                e.segwit_ctx_checks()?;
546                Ok(())
547            }
548            Terminal::MultiA(..) => Err(ScriptContextError::MultiANotAllowed),
549            _ => Ok(()),
550        }
551    }
552
553    fn check_local_consensus_validity<Pk: MiniscriptKey, Ext: Extension>(
554        ms: &Miniscript<Pk, Self, Ext>,
555    ) -> Result<(), ScriptContextError> {
556        match ms.ext.ops.op_count() {
557            None => Err(ScriptContextError::MaxOpCountExceeded),
558            Some(op_count) if op_count > MAX_OPS_PER_SCRIPT => {
559                Err(ScriptContextError::MaxOpCountExceeded)
560            }
561            _ => Ok(()),
562        }
563    }
564
565    fn check_global_policy_validity<Pk: MiniscriptKey, Ext: Extension>(
566        ms: &Miniscript<Pk, Self, Ext>,
567    ) -> Result<(), ScriptContextError> {
568        if ms.ext.pk_cost > MAX_STANDARD_P2WSH_SCRIPT_SIZE {
569            return Err(ScriptContextError::MaxWitnessScriptSizeExceeded);
570        }
571        Ok(())
572    }
573
574    fn check_local_policy_validity<Pk: MiniscriptKey, Ext: Extension>(
575        ms: &Miniscript<Pk, Self, Ext>,
576    ) -> Result<(), ScriptContextError> {
577        // We don't need to know if this is actually a p2wsh as the standard satisfaction for
578        // other Segwitv0 defined programs all require (much) less than 100 elements.
579        // The witness script item is accounted for in max_satisfaction_witness_elements().
580        match ms.max_satisfaction_witness_elements() {
581            // No possible satisfactions
582            Err(_e) => Err(ScriptContextError::ImpossibleSatisfaction),
583            Ok(max_witness_items) if max_witness_items > MAX_STANDARD_P2WSH_STACK_ITEMS => {
584                Err(ScriptContextError::MaxWitnessItemssExceeded {
585                    actual: max_witness_items,
586                    limit: MAX_STANDARD_P2WSH_STACK_ITEMS,
587                })
588            }
589            _ => Ok(()),
590        }
591    }
592
593    fn max_satisfaction_size<Pk: MiniscriptKey, Ext: Extension>(
594        ms: &Miniscript<Pk, Self, Ext>,
595    ) -> Option<usize> {
596        // The witness stack cost is the first element of the tuple
597        ms.ext.max_sat_size.map(|x| x.0)
598    }
599
600    fn pk_len<Pk: MiniscriptKey>(_pk: &Pk) -> usize {
601        34
602    }
603
604    fn name_str() -> &'static str {
605        "Segwitv0"
606    }
607
608    fn sig_type() -> SigType {
609        SigType::Ecdsa
610    }
611}
612
613/// Tap ScriptContext
614#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
615pub enum Tap {}
616
617impl ScriptContext for Tap {
618    type Key = bitcoin::secp256k1::XOnlyPublicKey;
619    fn check_terminal_non_malleable<Pk: MiniscriptKey, Ext: Extension>(
620        _frag: &Terminal<Pk, Self, Ext>,
621    ) -> Result<(), ScriptContextError> {
622        // No fragment is malleable in tapscript context.
623        // Certain fragments like Multi are invalid, but are not malleable
624        Ok(())
625    }
626
627    fn check_witness<Pk: MiniscriptKey, Ext: Extension>(
628        witness: &[Vec<u8>],
629    ) -> Result<(), ScriptContextError> {
630        // Note that tapscript has a 1000 limit compared to 100 of segwitv0
631        if witness.len() > MAX_STACK_SIZE {
632            return Err(ScriptContextError::MaxWitnessItemssExceeded {
633                actual: witness.len(),
634                limit: MAX_STACK_SIZE,
635            });
636        }
637        Ok(())
638    }
639
640    fn check_global_consensus_validity<Pk: MiniscriptKey, Ext: Extension>(
641        ms: &Miniscript<Pk, Self, Ext>,
642    ) -> Result<(), ScriptContextError> {
643        // No script size checks for global consensus rules
644        // Should we really check for block limits here.
645        // When the transaction sizes get close to block limits,
646        // some guarantees are not easy to satisfy because of knapsack
647        // constraints
648        if ms.ext.pk_cost > Weight::MAX_BLOCK.to_wu() as usize {
649            return Err(ScriptContextError::MaxWitnessScriptSizeExceeded);
650        }
651
652        match ms.node {
653            Terminal::PkK(ref pk) => {
654                if pk.is_uncompressed() {
655                    return Err(ScriptContextError::UncompressedKeysNotAllowed);
656                }
657                Ok(())
658            }
659            Terminal::Multi(..) => Err(ScriptContextError::TaprootMultiDisabled),
660            Terminal::Ext(ref e) => {
661                e.tap_ctx_checks()?;
662                Ok(())
663            }
664            _ => Ok(()),
665        }
666    }
667
668    fn check_local_consensus_validity<Pk: MiniscriptKey, Ext: Extension>(
669        ms: &Miniscript<Pk, Self, Ext>,
670    ) -> Result<(), ScriptContextError> {
671        // Taproot introduces the concept of sigops budget.
672        // All valid miniscripts satisfy the sigops constraint
673        // Whenever we add new fragment that uses pk(pk() or multi based on checksigadd)
674        // miniscript typing rules ensure that pk when executed successfully has it's
675        // own unique signature. That is, there is no way to re-use signatures from one CHECKSIG
676        // to another checksig. In other words, for each successfully executed checksig
677        // will have it's corresponding 64 bytes signature.
678        // sigops budget = witness_script.len() + witness.size() + 50
679        // Each signature will cover it's own cost(64 > 50) and thus will will never exceed the budget
680        if let (Some(s), Some(h)) = (
681            ms.ext.exec_stack_elem_count_sat,
682            ms.ext.stack_elem_count_sat,
683        ) {
684            if s + h > MAX_STACK_SIZE {
685                return Err(ScriptContextError::StackSizeLimitExceeded {
686                    actual: s + h,
687                    limit: MAX_STACK_SIZE,
688                });
689            }
690        }
691        Ok(())
692    }
693
694    fn check_global_policy_validity<Pk: MiniscriptKey, Ext: Extension>(
695        _ms: &Miniscript<Pk, Self, Ext>,
696    ) -> Result<(), ScriptContextError> {
697        // No script rules, rules are subject to entire tx rules
698        Ok(())
699    }
700
701    fn check_local_policy_validity<Pk: MiniscriptKey, Ext: Extension>(
702        _ms: &Miniscript<Pk, Self, Ext>,
703    ) -> Result<(), ScriptContextError> {
704        Ok(())
705    }
706
707    fn max_satisfaction_size<Pk: MiniscriptKey, Ext: Extension>(
708        ms: &Miniscript<Pk, Self, Ext>,
709    ) -> Option<usize> {
710        // The witness stack cost is the first element of the tuple
711        ms.ext.max_sat_size.map(|x| x.0)
712    }
713
714    fn sig_type() -> SigType {
715        SigType::Schnorr
716    }
717
718    fn pk_len<Pk: MiniscriptKey>(_pk: &Pk) -> usize {
719        33
720    }
721
722    fn name_str() -> &'static str {
723        "TapscriptCtx"
724    }
725}
726
727/// Bare ScriptContext
728/// To be used as raw script pubkeys
729/// In general, it is not recommended to use Bare descriptors
730/// as they as strongly limited by standardness policies.
731#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
732pub enum BareCtx {}
733
734impl ScriptContext for BareCtx {
735    type Key = bitcoin::PublicKey;
736    fn check_terminal_non_malleable<Pk: MiniscriptKey, Ext: Extension>(
737        _frag: &Terminal<Pk, Self, Ext>,
738    ) -> Result<(), ScriptContextError> {
739        // Bare fragments can't contain miniscript because of standardness rules
740        // This function is only used in compiler which already checks the standardness
741        // and consensus rules, and because of the limited allowance of bare scripts
742        // we need check for malleable scripts
743        Ok(())
744    }
745
746    fn check_global_consensus_validity<Pk: MiniscriptKey, Ext: Extension>(
747        ms: &Miniscript<Pk, Self, Ext>,
748    ) -> Result<(), ScriptContextError> {
749        if ms.ext.pk_cost > MAX_SCRIPT_SIZE {
750            return Err(ScriptContextError::MaxWitnessScriptSizeExceeded);
751        }
752
753        if let Terminal::Ext(ref _e) = ms.node {
754            return Err(ScriptContextError::ExtensionError(String::from(
755                "No Extensions in Bare context",
756            )));
757        }
758        match ms.node {
759            Terminal::PkK(ref key) if key.is_x_only_key() => {
760                Err(ScriptContextError::XOnlyKeysNotAllowed(
761                    key.to_string(),
762                    Self::name_str(),
763                ))
764            }
765            Terminal::Multi(_k, ref pks) => {
766                if pks.len() > MAX_PUBKEYS_PER_MULTISIG {
767                    return Err(ScriptContextError::CheckMultiSigLimitExceeded);
768                }
769                for pk in pks.iter() {
770                    if pk.is_x_only_key() {
771                        return Err(ScriptContextError::XOnlyKeysNotAllowed(
772                            pk.to_string(),
773                            Self::name_str(),
774                        ));
775                    }
776                }
777                Ok(())
778            }
779            Terminal::MultiA(..) => Err(ScriptContextError::MultiANotAllowed),
780            _ => Ok(()),
781        }
782    }
783
784    fn check_local_consensus_validity<Pk: MiniscriptKey, Ext: Extension>(
785        ms: &Miniscript<Pk, Self, Ext>,
786    ) -> Result<(), ScriptContextError> {
787        match ms.ext.ops.op_count() {
788            None => Err(ScriptContextError::MaxOpCountExceeded),
789            Some(op_count) if op_count > MAX_OPS_PER_SCRIPT => {
790                Err(ScriptContextError::MaxOpCountExceeded)
791            }
792            _ => Ok(()),
793        }
794    }
795
796    fn other_top_level_checks<Pk: MiniscriptKey, Ext: Extension>(
797        ms: &Miniscript<Pk, Self, Ext>,
798    ) -> Result<(), Error> {
799        match &ms.node {
800            Terminal::Check(ref ms) => match &ms.node {
801                Terminal::RawPkH(_pkh) => Ok(()),
802                Terminal::PkK(_pk) | Terminal::PkH(_pk) => Ok(()),
803                _ => Err(Error::NonStandardBareScript),
804            },
805            Terminal::Multi(_k, subs) if subs.len() <= 3 => Ok(()),
806            _ => Err(Error::NonStandardBareScript),
807        }
808    }
809
810    fn max_satisfaction_size<Pk: MiniscriptKey, Ext: Extension>(
811        ms: &Miniscript<Pk, Self, Ext>,
812    ) -> Option<usize> {
813        // The witness stack cost is the first element of the tuple
814        ms.ext.max_sat_size.map(|x| x.1)
815    }
816
817    fn pk_len<Pk: MiniscriptKey>(pk: &Pk) -> usize {
818        if pk.is_uncompressed() {
819            66
820        } else {
821            34
822        }
823    }
824
825    fn name_str() -> &'static str {
826        "BareCtx"
827    }
828
829    fn sig_type() -> SigType {
830        SigType::Ecdsa
831    }
832}
833
834/// "No Checks Ecdsa" Context
835///
836/// Used by the "satisified constraints" iterator, which is intended to read
837/// scripts off of the blockchain without doing any sanity checks on them.
838/// This context should *NOT* be used unless you know what you are doing.
839#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
840pub enum NoChecks {}
841impl ScriptContext for NoChecks {
842    type Key = bitcoin::PublicKey;
843    fn check_terminal_non_malleable<Pk: MiniscriptKey, Ext: Extension>(
844        _frag: &Terminal<Pk, Self, Ext>,
845    ) -> Result<(), ScriptContextError> {
846        Ok(())
847    }
848
849    fn check_global_policy_validity<Pk: MiniscriptKey, Ext: Extension>(
850        _ms: &Miniscript<Pk, Self, Ext>,
851    ) -> Result<(), ScriptContextError> {
852        Ok(())
853    }
854
855    fn check_global_consensus_validity<Pk: MiniscriptKey, Ext: Extension>(
856        _ms: &Miniscript<Pk, Self, Ext>,
857    ) -> Result<(), ScriptContextError> {
858        Ok(())
859    }
860
861    fn check_local_policy_validity<Pk: MiniscriptKey, Ext: Extension>(
862        _ms: &Miniscript<Pk, Self, Ext>,
863    ) -> Result<(), ScriptContextError> {
864        Ok(())
865    }
866
867    fn check_local_consensus_validity<Pk: MiniscriptKey, Ext: Extension>(
868        _ms: &Miniscript<Pk, Self, Ext>,
869    ) -> Result<(), ScriptContextError> {
870        Ok(())
871    }
872
873    fn max_satisfaction_size<Pk: MiniscriptKey, Ext: Extension>(
874        _ms: &Miniscript<Pk, Self, Ext>,
875    ) -> Option<usize> {
876        panic!("Tried to compute a satisfaction size bound on a no-checks ecdsa miniscript")
877    }
878
879    fn pk_len<Pk: MiniscriptKey>(_pk: &Pk) -> usize {
880        panic!("Tried to compute a pk len bound on a no-checks ecdsa miniscript")
881    }
882
883    fn name_str() -> &'static str {
884        // Internally used code
885        "NochecksEcdsa"
886    }
887
888    fn check_witness<Pk: MiniscriptKey, Ext: Extension>(
889        _witness: &[Vec<u8>],
890    ) -> Result<(), ScriptContextError> {
891        // Only really need to do this for segwitv0 and legacy
892        // Bare is already restrcited by standardness rules
893        // and would reach these limits.
894        Ok(())
895    }
896
897    fn check_global_validity<Pk: MiniscriptKey, Ext: Extension>(
898        ms: &Miniscript<Pk, Self, Ext>,
899    ) -> Result<(), ScriptContextError> {
900        Self::check_global_consensus_validity(ms)?;
901        Self::check_global_policy_validity(ms)?;
902        Ok(())
903    }
904
905    fn check_local_validity<Pk: MiniscriptKey, Ext: Extension>(
906        ms: &Miniscript<Pk, Self, Ext>,
907    ) -> Result<(), ScriptContextError> {
908        Self::check_global_consensus_validity(ms)?;
909        Self::check_global_policy_validity(ms)?;
910        Self::check_local_consensus_validity(ms)?;
911        Self::check_local_policy_validity(ms)?;
912        Ok(())
913    }
914
915    fn top_level_type_check<Pk: MiniscriptKey, Ext: Extension>(
916        ms: &Miniscript<Pk, Self, Ext>,
917    ) -> Result<(), Error> {
918        if ms.ty.corr.base != types::Base::B {
919            return Err(Error::NonTopLevel(format!("{:?}", ms)));
920        }
921        Ok(())
922    }
923
924    fn other_top_level_checks<Pk: MiniscriptKey, Ext: Extension>(
925        _ms: &Miniscript<Pk, Self, Ext>,
926    ) -> Result<(), Error> {
927        Ok(())
928    }
929
930    fn top_level_checks<Pk: MiniscriptKey, Ext: Extension>(
931        ms: &Miniscript<Pk, Self, Ext>,
932    ) -> Result<(), Error> {
933        Self::top_level_type_check(ms)?;
934        Self::other_top_level_checks(ms)
935    }
936
937    fn sig_type() -> SigType {
938        SigType::Ecdsa
939    }
940}
941
942/// Private Mod to prevent downstream from implementing this public trait
943mod private {
944    use super::{BareCtx, Legacy, NoChecks, Segwitv0, Tap};
945
946    pub trait Sealed {}
947
948    // Implement for those same types, but no others.
949    impl Sealed for BareCtx {}
950    impl Sealed for Legacy {}
951    impl Sealed for Segwitv0 {}
952    impl Sealed for Tap {}
953    impl Sealed for NoChecks {}
954}