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