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