miniscript_debug/interpreter/
error.rs

1// Miniscript
2// Written in 2019 by
3//     Sanket Kanjular 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;
16#[cfg(feature = "std")]
17use std::error;
18
19use bitcoin::hashes::hash160;
20use bitcoin::hashes::hex::ToHex;
21use bitcoin::util::taproot;
22use bitcoin::{self, secp256k1};
23
24use super::BitcoinKey;
25use crate::prelude::*;
26
27/// Detailed Error type for Interpreter
28#[derive(Debug)]
29pub enum Error {
30    /// Could not satisfy, absolute locktime not met
31    AbsoluteLocktimeNotMet(u32),
32    /// Could not satisfy, lock time values are different units
33    AbsoluteLocktimeComparisonInvalid(u32, u32),
34    /// Cannot Infer a taproot descriptor
35    /// Key spends cannot infer the internal key of the descriptor
36    /// Inferring script spends is possible, but is hidden nodes are currently
37    /// not supported in descriptor spec
38    CannotInferTrDescriptors,
39    /// Error parsing taproot control block
40    ControlBlockParse(taproot::TaprootError),
41    /// Tap control block(merkle proofs + tweak) verification error
42    ControlBlockVerificationError,
43    /// General Interpreter error.
44    CouldNotEvaluate,
45    /// EcdsaSig related error
46    EcdsaSig(bitcoin::EcdsaSigError),
47    /// We expected a push (including a `OP_1` but no other numeric pushes)
48    ExpectedPush,
49    /// The preimage to the hash function must be exactly 32 bytes.
50    HashPreimageLengthMismatch,
51    /// Incorrect scriptPubKey (pay-to-pubkeyhash) for the provided public key
52    IncorrectPubkeyHash,
53    /// Incorrect scriptPubKey for the provided redeem script
54    IncorrectScriptHash,
55    /// Incorrect scriptPubKey (pay-to-witness-pubkeyhash) for the provided public key
56    IncorrectWPubkeyHash,
57    /// Incorrect scriptPubKey for the provided witness script
58    IncorrectWScriptHash,
59    /// MultiSig missing at least `1` witness elements out of `k + 1` required
60    InsufficientSignaturesMultiSig,
61    /// Invalid Sighash type
62    InvalidSchnorrSighashType(Vec<u8>),
63    /// ecdsa Signature failed to verify
64    InvalidEcdsaSignature(bitcoin::PublicKey),
65    /// Signature failed to verify
66    InvalidSchnorrSignature(bitcoin::XOnlyPublicKey),
67    /// Last byte of this signature isn't a standard sighash type
68    NonStandardSighash(Vec<u8>),
69    /// Miniscript error
70    Miniscript(crate::Error),
71    /// MultiSig requires 1 extra zero element apart from the `k` signatures
72    MissingExtraZeroMultiSig,
73    /// Script abortion because of incorrect dissatisfaction for multisig.
74    /// Any input witness apart from sat(0 sig ...) or nsat(0 0 ..) leads to
75    /// this error. This is network standardness assumption and miniscript only
76    /// supports standard scripts
77    MultiSigEvaluationError,
78    ///Witness must be empty for pre-segwit transactions
79    NonEmptyWitness,
80    ///ScriptSig must be empty for pure segwit transactions
81    NonEmptyScriptSig,
82    /// Script abortion because of incorrect dissatisfaction for Checksig.
83    /// Any input witness apart from sat(sig) or nsat(0) leads to
84    /// this error. This is network standardness assumption and miniscript only
85    /// supports standard scripts
86    // note that BitcoinKey is not exported, create a data structure to convey the same
87    // information in error
88    PkEvaluationError(PkEvalErrInner),
89    /// The Public Key hash check for the given pubkey. This occurs in `PkH`
90    /// node when the given key does not match to Hash in script.
91    PkHashVerifyFail(hash160::Hash),
92    /// Parse Error while parsing a `stack::Element::Push` as a Pubkey. Both
93    /// 33 byte and 65 bytes are supported.
94    PubkeyParseError,
95    /// Parse Error while parsing a `stack::Element::Push` as a XOnlyPublicKey (32 bytes)
96    XOnlyPublicKeyParseError,
97    /// Could not satisfy, relative locktime not met
98    RelativeLocktimeNotMet(u32),
99    /// Forward-secp related errors
100    Secp(secp256k1::Error),
101    /// Miniscript requires the entire top level script to be satisfied.
102    ScriptSatisfactionError,
103    /// Schnorr Signature error
104    SchnorrSig(bitcoin::SchnorrSigError),
105    /// Errors in signature hash calculations
106    SighashError(bitcoin::util::sighash::Error),
107    /// Taproot Annex Unsupported
108    TapAnnexUnsupported,
109    /// An uncompressed public key was encountered in a context where it is
110    /// disallowed (e.g. in a Segwit script or p2wpkh output)
111    UncompressedPubkey,
112    /// Got `stack::Element::Satisfied` or `stack::Element::Dissatisfied` when the
113    /// interpreter was expecting `stack::Element::Push`
114    UnexpectedStackBoolean,
115    /// Unexpected Stack End, caused by popping extra elements from stack
116    UnexpectedStackEnd,
117    /// Unexpected Stack Push `stack::Element::Push` element when the interpreter
118    /// was expecting a stack boolean `stack::Element::Satisfied` or
119    /// `stack::Element::Dissatisfied`
120    UnexpectedStackElementPush,
121    /// Verify expects stack top element exactly to be `stack::Element::Satisfied`.
122    /// This error is raised even if the stack top is `stack::Element::Push`.
123    VerifyFailed,
124}
125
126impl fmt::Display for Error {
127    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
128        match *self {
129            Error::AbsoluteLocktimeNotMet(n) => write!(
130                f,
131                "required absolute locktime CLTV of {} blocks, not met",
132                n
133            ),
134            Error::AbsoluteLocktimeComparisonInvalid(n, lock_time) => write!(
135                f,
136                "could not satisfy, lock time values are different units n: {} lock_time: {}",
137                n, lock_time
138            ),
139            Error::CannotInferTrDescriptors => write!(f, "Cannot infer taproot descriptors"),
140            Error::ControlBlockParse(ref e) => write!(f, "Control block parse error {}", e),
141            Error::ControlBlockVerificationError => {
142                f.write_str("Control block verification failed")
143            }
144            Error::EcdsaSig(ref s) => write!(f, "Ecdsa sig error: {}", s),
145            Error::ExpectedPush => f.write_str("expected push in script"),
146            Error::CouldNotEvaluate => f.write_str("Interpreter Error: Could not evaluate"),
147            Error::HashPreimageLengthMismatch => f.write_str("Hash preimage should be 32 bytes"),
148            Error::IncorrectPubkeyHash => f.write_str("public key did not match scriptpubkey"),
149            Error::IncorrectScriptHash => f.write_str("redeem script did not match scriptpubkey"),
150            Error::IncorrectWPubkeyHash => {
151                f.write_str("public key did not match scriptpubkey (segwit v0)")
152            }
153            Error::IncorrectWScriptHash => f.write_str("witness script did not match scriptpubkey"),
154            Error::InsufficientSignaturesMultiSig => f.write_str("Insufficient signatures for CMS"),
155            Error::InvalidSchnorrSighashType(ref sig) => write!(
156                f,
157                "Invalid sighash type for schnorr signature '{}'",
158                sig.to_hex()
159            ),
160            Error::InvalidEcdsaSignature(pk) => write!(f, "bad ecdsa signature with pk {}", pk),
161            Error::InvalidSchnorrSignature(pk) => write!(f, "bad schnorr signature with pk {}", pk),
162            Error::NonStandardSighash(ref sig) => write!(
163                f,
164                "Non standard sighash type for signature '{}'",
165                sig.to_hex()
166            ),
167            Error::NonEmptyWitness => f.write_str("legacy spend had nonempty witness"),
168            Error::NonEmptyScriptSig => f.write_str("segwit spend had nonempty scriptsig"),
169            Error::Miniscript(ref e) => write!(f, "parse error: {}", e),
170            Error::MissingExtraZeroMultiSig => f.write_str("CMS missing extra zero"),
171            Error::MultiSigEvaluationError => {
172                f.write_str("CMS script aborted, incorrect satisfaction/dissatisfaction")
173            }
174            Error::PkEvaluationError(ref key) => write!(f, "Incorrect Signature for pk {}", key),
175            Error::PkHashVerifyFail(ref hash) => write!(f, "Pubkey Hash check failed {}", hash),
176            Error::PubkeyParseError => f.write_str("could not parse pubkey"),
177            Error::XOnlyPublicKeyParseError => f.write_str("could not parse x-only pubkey"),
178            Error::RelativeLocktimeNotMet(n) => {
179                write!(f, "required relative locktime CSV of {} blocks, not met", n)
180            }
181            Error::ScriptSatisfactionError => f.write_str("Top level script must be satisfied"),
182            Error::Secp(ref e) => fmt::Display::fmt(e, f),
183            Error::SchnorrSig(ref s) => write!(f, "Schnorr sig error: {}", s),
184            Error::SighashError(ref e) => fmt::Display::fmt(e, f),
185            Error::TapAnnexUnsupported => f.write_str("Encountered annex element"),
186            Error::UncompressedPubkey => {
187                f.write_str("uncompressed pubkey in non-legacy descriptor")
188            }
189            Error::UnexpectedStackBoolean => {
190                f.write_str("Expected Stack Push operation, found stack bool")
191            }
192            Error::UnexpectedStackElementPush => write!(f, "Got {}, expected Stack Boolean", 1),
193            Error::UnexpectedStackEnd => f.write_str("unexpected end of stack"),
194            Error::VerifyFailed => {
195                f.write_str("Expected Satisfied Boolean at stack top for VERIFY")
196            }
197        }
198    }
199}
200
201#[cfg(feature = "std")]
202impl error::Error for Error {
203    fn cause(&self) -> Option<&dyn error::Error> {
204        use self::Error::*;
205
206        match self {
207            AbsoluteLocktimeNotMet(_)
208            | AbsoluteLocktimeComparisonInvalid(_, _)
209            | CannotInferTrDescriptors
210            | ControlBlockVerificationError
211            | CouldNotEvaluate
212            | ExpectedPush
213            | HashPreimageLengthMismatch
214            | IncorrectPubkeyHash
215            | IncorrectScriptHash
216            | IncorrectWPubkeyHash
217            | IncorrectWScriptHash
218            | InsufficientSignaturesMultiSig
219            | InvalidEcdsaSignature(_)
220            | InvalidSchnorrSignature(_)
221            | InvalidSchnorrSighashType(_)
222            | NonStandardSighash(_)
223            | MissingExtraZeroMultiSig
224            | MultiSigEvaluationError
225            | NonEmptyWitness
226            | NonEmptyScriptSig
227            | PubkeyParseError
228            | XOnlyPublicKeyParseError
229            | PkEvaluationError(_)
230            | PkHashVerifyFail(_)
231            | RelativeLocktimeNotMet(_)
232            | ScriptSatisfactionError
233            | TapAnnexUnsupported
234            | UncompressedPubkey
235            | UnexpectedStackBoolean
236            | UnexpectedStackEnd
237            | UnexpectedStackElementPush
238            | VerifyFailed => None,
239            ControlBlockParse(e) => Some(e),
240            EcdsaSig(e) => Some(e),
241            Miniscript(e) => Some(e),
242            Secp(e) => Some(e),
243            SchnorrSig(e) => Some(e),
244            SighashError(e) => Some(e),
245        }
246    }
247}
248
249#[doc(hidden)]
250impl From<secp256k1::Error> for Error {
251    fn from(e: secp256k1::Error) -> Error {
252        Error::Secp(e)
253    }
254}
255
256#[doc(hidden)]
257impl From<bitcoin::util::sighash::Error> for Error {
258    fn from(e: bitcoin::util::sighash::Error) -> Error {
259        Error::SighashError(e)
260    }
261}
262
263#[doc(hidden)]
264impl From<bitcoin::EcdsaSigError> for Error {
265    fn from(e: bitcoin::EcdsaSigError) -> Error {
266        Error::EcdsaSig(e)
267    }
268}
269
270#[doc(hidden)]
271impl From<bitcoin::SchnorrSigError> for Error {
272    fn from(e: bitcoin::SchnorrSigError) -> Error {
273        Error::SchnorrSig(e)
274    }
275}
276
277#[doc(hidden)]
278impl From<crate::Error> for Error {
279    fn from(e: crate::Error) -> Error {
280        Error::Miniscript(e)
281    }
282}
283
284/// A type of representing which keys errored during interpreter checksig evaluation
285// Note that we can't use BitcoinKey because it is not public
286#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
287pub enum PkEvalErrInner {
288    /// Full Key
289    FullKey(bitcoin::PublicKey),
290    /// XOnly Key
291    XOnlyKey(bitcoin::XOnlyPublicKey),
292}
293
294impl From<BitcoinKey> for PkEvalErrInner {
295    fn from(pk: BitcoinKey) -> Self {
296        match pk {
297            BitcoinKey::Fullkey(pk) => PkEvalErrInner::FullKey(pk),
298            BitcoinKey::XOnlyPublicKey(xpk) => PkEvalErrInner::XOnlyKey(xpk),
299        }
300    }
301}
302
303impl fmt::Display for PkEvalErrInner {
304    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305        match self {
306            PkEvalErrInner::FullKey(pk) => pk.fmt(f),
307            PkEvalErrInner::XOnlyKey(xpk) => xpk.fmt(f),
308        }
309    }
310}