sapio_miniscript/miniscript/
context.rs

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