elements_miniscript/
lib.rs

1// Written in 2019 by Andrew Poelstra <apoelstra@wpsoftware.net>
2// SPDX-License-Identifier: CC0-1.0
3
4//! Miniscript and Output Descriptors
5//!
6//! ## Bitcoin Script
7//!
8//! In Bitcoin, spending policies are defined and enforced by means of a
9//! stack-based programming language known as Bitcoin Script. While this
10//! language appears to be designed with tractable analysis in mind (e.g.
11//! there are no looping or jumping constructions), in practice this is
12//! extremely difficult. As a result, typical wallet software supports only
13//! a small set of script templates, cannot interoperate with other similar
14//! software, and each wallet contains independently written ad-hoc manually
15//! verified code to handle these templates. Users who require more complex
16//! spending policies, or who want to combine signing infrastructure which
17//! was not explicitly designed to work together, are simply out of luck.
18//!
19//! ## Miniscript
20//!
21//! Miniscript is an alternative to Bitcoin Script which eliminates these
22//! problems. It can be efficiently and simply encoded as Script to ensure
23//! that it works on the Bitcoin blockchain, but its design is very different.
24//! Essentially, a Miniscript is a monotone function (tree of ANDs, ORs and
25//! thresholds) of signature requirements, hash preimage requirements, and
26//! timelocks.
27//!
28//! A [full description of Miniscript is available here](http://bitcoin.sipa.be/miniscript/miniscript.html).
29//!
30//! Miniscript also admits a more human-readable encoding.
31//!
32//! ## Elements Miniscript
33//!
34//! Elements Miniscript is a fork of miniscript for [elements](https://github.com/ElementsProject/elements) sidechain.
35//!
36//! ## Output Descriptors
37//!
38//! While spending policies in Bitcoin are entirely defined by Script; there
39//! are multiple ways of embedding these Scripts in transaction outputs; for
40//! example, P2SH or Segwit v0. These different embeddings are expressed by
41//! *Output Descriptors*, [which are described here](https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md).
42//! Elements descriptors are extension of bitcoin Output descriptors with support
43//! for blinded descriptors(WIP).
44//! # Examples
45//!
46//! ## Deriving an address from a descriptor
47//!
48//! ```rust
49//! extern crate bitcoin;
50//! extern crate elements;
51//! extern crate elements_miniscript as miniscript;
52//!
53//! use std::str::FromStr;
54//!
55//! fn main() {
56//!     // Elements descriptors are prefixed by string el
57//!     let desc = miniscript::Descriptor::<
58//!         bitcoin::PublicKey,
59//!     >::from_str("\
60//!         elsh(wsh(or_d(\
61//!             c:pk_k(020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261),\
62//!             c:pk_k(0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352)\
63//!         )))\
64//!     ").unwrap();
65//!
66//!     // Derive the P2SH address.
67//!     assert_eq!(
68//!         desc.address(&elements::AddressParams::ELEMENTS).unwrap().to_string(),
69//!         "XMyBX13qCo5Lp65mymgYVdmsYR5bcznWUa"
70//!     );
71//!
72//!     // Check whether the descriptor is safe
73//!     // This checks whether all spend paths are accessible in bitcoin network.
74//!     // It maybe possible that some of the spend require more than 100 elements in Wsh scripts
75//!     // Or they contain a combination of timelock and heightlock.
76//!     assert!(desc.sanity_check().is_ok());
77//!
78//!     // Estimate the satisfaction cost.
79//!     // scriptSig: OP_PUSH34 <OP_0 OP_32 <32-byte-hash>>
80//!     // = (1 + 1 + 1 + 32) * 4 = 140 WU
81//!     // redeemScript: varint <OP_33 <pk1> OP_CHECKSIG OP_IFDUP OP_NOTIF OP_33 <pk2> OP_CHECKSIG OP_ENDIF>
82//!     // = 1 + (1 + 33 + 1 + 1 + 1 + 1 + 33 + 1 + 1) = 74 WU
83//!     // stackItem[Sig]: varint <sig+sighash>
84//!     // = 1 + 73 = 74 WU
85//!     // Expected satisfaction weight: 140 + 74 + 74 = 288
86//!     assert_eq!(desc.max_weight_to_satisfy().unwrap(), 288);
87//! }
88//! ```
89//!
90//!
91
92#![cfg_attr(miniscript_bench, feature(test))]
93#![allow(clippy::manual_range_contains)] // this lint is just stupid
94#![allow(clippy::type_complexity)] // clippy doesn't like how many generics we use
95
96#[cfg(target_pointer_width = "16")]
97compile_error!(
98    "elements-miniscript currently only supports architectures with pointers wider than 16 bits"
99);
100
101#[cfg(feature = "serde")]
102pub use actual_serde as serde;
103pub use {bitcoin, elements};
104#[cfg(miniscript_bench)]
105extern crate test;
106
107// Miniscript imports
108// It can be confusing to code when we have two miniscript libraries
109// As a rule, only import the library here and pub use all the required
110// items. Should help in faster code development in the long run
111use bitcoin_miniscript::expression::{FromTree as BtcFromTree, Tree as BtcTree};
112use bitcoin_miniscript::policy::semantic::Policy as BtcPolicy;
113use bitcoin_miniscript::policy::Liftable as BtcLiftable;
114// re-export imports
115pub use bitcoin_miniscript::{hash256, ForEachKey, MiniscriptKey, SigType, ToPublicKey};
116pub use bitcoin_miniscript::{
117    Descriptor as BtcDescriptor, Error as BtcError, Miniscript as BtcMiniscript,
118    Satisfier as BtcSatisfier, Segwitv0 as BtcSegwitv0, Terminal as BtcTerminal,
119};
120// End imports
121
122#[macro_use]
123mod macros;
124
125#[macro_use]
126mod pub_macros;
127
128pub mod confidential;
129pub mod descriptor;
130pub mod expression;
131pub mod extensions;
132pub mod interpreter;
133pub mod miniscript;
134pub mod policy;
135pub mod psbt;
136
137#[cfg(feature = "simplicity")]
138mod simplicity;
139#[cfg(test)]
140mod test_utils;
141mod util;
142
143use std::{cmp, error, fmt, str};
144
145use elements::hashes::sha256;
146use elements::secp256k1_zkp::Secp256k1;
147use elements::{locktime, opcodes, script, secp256k1_zkp};
148
149pub use crate::confidential::slip77;
150pub use crate::confidential::Descriptor as ConfidentialDescriptor;
151pub use crate::descriptor::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey};
152pub use crate::extensions::{CovenantExt, Extension, NoExt, TxEnv};
153pub use crate::interpreter::Interpreter;
154pub use crate::miniscript::analyzable::{AnalysisError, ExtParams};
155pub use crate::miniscript::context::{BareCtx, Legacy, ScriptContext, Segwitv0, Tap};
156pub use crate::miniscript::decode::Terminal;
157pub use crate::miniscript::satisfy::{
158    elementssig_from_rawsig, elementssig_to_rawsig, ElementsSig, Preimage32, Satisfier,
159};
160pub use crate::miniscript::Miniscript;
161// minimal implementation of contract hash module
162mod contracthash {
163    use bitcoin::secp256k1::Scalar;
164    use bitcoin::PublicKey;
165    use elements::hashes::{sha256, Hash, HashEngine, Hmac, HmacEngine};
166    use elements::secp256k1_zkp::{self, Secp256k1};
167
168    /// Tweak a single key using some arbitrary data
169    pub(super) fn tweak_key<C: secp256k1_zkp::Verification>(
170        secp: &Secp256k1<C>,
171        key: PublicKey,
172        contract: &[u8],
173    ) -> PublicKey {
174        let hmac_result = compute_tweak(&key, contract);
175        let secp_key = key
176            .inner
177            .add_exp_tweak(
178                secp,
179                &Scalar::from_be_bytes(hmac_result.to_byte_array())
180                    .expect("Result of hash must be a valid point"),
181            )
182            .expect("HMAC cannot produce invalid tweak");
183        bitcoin::PublicKey::new(secp_key)
184    }
185
186    /// Compute a tweak from some given data for the given public key
187    fn compute_tweak(pk: &PublicKey, contract: &[u8]) -> Hmac<sha256::Hash> {
188        let mut hmac_engine: HmacEngine<sha256::Hash> = if pk.compressed {
189            HmacEngine::new(&pk.inner.serialize())
190        } else {
191            HmacEngine::new(&pk.inner.serialize_uncompressed())
192        };
193        hmac_engine.input(contract);
194        Hmac::from_engine(hmac_engine)
195    }
196}
197
198/// Tweak a MiniscriptKey to obtain the tweaked key
199// Ideally, we want this in a trait, but doing so we cannot
200// use it in the implementation of DescriptorTrait from
201// rust-miniscript because it would require stricter bounds.
202pub fn tweak_key<Pk, C: secp256k1_zkp::Verification>(
203    pk: &Pk,
204    secp: &Secp256k1<C>,
205    contract: &[u8],
206) -> bitcoin::PublicKey
207where
208    Pk: MiniscriptKey + ToPublicKey,
209{
210    let pk = pk.to_public_key();
211    contracthash::tweak_key(secp, pk, contract)
212}
213
214/// Describes an object that can translate various keys and hashes from one key to the type
215/// associated with the other key. Used by the [`TranslatePk`] trait to do the actual translations.
216pub trait Translator<P, Q, E>
217where
218    P: MiniscriptKey,
219    Q: MiniscriptKey,
220{
221    /// Translates public keys P -> Q.
222    fn pk(&mut self, pk: &P) -> Result<Q, E>;
223
224    /// Provides the translation from P::Sha256 -> Q::Sha256
225    fn sha256(&mut self, sha256: &P::Sha256) -> Result<Q::Sha256, E>;
226
227    /// Provides the translation from P::Hash256 -> Q::Hash256
228    fn hash256(&mut self, hash256: &P::Hash256) -> Result<Q::Hash256, E>;
229
230    /// Translates ripemd160 hashes from P::Ripemd160 -> Q::Ripemd160
231    fn ripemd160(&mut self, ripemd160: &P::Ripemd160) -> Result<Q::Ripemd160, E>;
232
233    /// Translates hash160 hashes from P::Hash160 -> Q::Hash160
234    fn hash160(&mut self, hash160: &P::Hash160) -> Result<Q::Hash160, E>;
235}
236
237/// Trait for translation Extensions
238pub trait ExtTranslator<PExt, QExt, E>
239where
240    PExt: Extension,
241    QExt: Extension,
242{
243    /// Translates one extension to another
244    fn ext(&mut self, e: &PExt) -> Result<QExt, E>;
245}
246
247/// Converts a descriptor using abstract keys to one using specific keys. Uses translator `t` to do
248/// the actual translation function calls.
249pub trait TranslatePk<P, Q>
250where
251    P: MiniscriptKey,
252    Q: MiniscriptKey,
253{
254    /// The associated output type. This must be `Self<Q>`.
255    type Output;
256
257    /// Translates a struct from one generic to another where the translations
258    /// for Pk are provided by the given [`Translator`].
259    fn translate_pk<T, E>(&self, translator: &mut T) -> Result<Self::Output, E>
260    where
261        T: Translator<P, Q, E>;
262}
263
264/// Converts a descriptor using abstract keys to one using specific keys. Uses translator `t` to do
265/// the actual translation function calls.
266pub trait TranslateExt<PExt, QExt>
267where
268    PExt: Extension,
269    QExt: Extension,
270{
271    /// The associated output type.
272    type Output;
273
274    /// Translates a struct from one generic to another where the translations
275    /// for Pk are provided by the given [`Translator`].
276    fn translate_ext<T, E>(&self, translator: &mut T) -> Result<Self::Output, E>
277    where
278        T: ExtTranslator<PExt, QExt, E>;
279}
280
281/// Miniscript Error
282#[derive(Debug, PartialEq)]
283pub enum Error {
284    /// Opcode appeared which is not part of the script subset
285    InvalidOpcode(opcodes::All),
286    /// Some opcode occurred followed by `OP_VERIFY` when it had
287    /// a `VERIFY` version that should have been used instead
288    NonMinimalVerify(String),
289    /// Push was illegal in some context
290    InvalidPush(Vec<u8>),
291    /// rust-bitcoin script error
292    Script(script::Error),
293    /// rust-bitcoin address error
294    AddrError(bitcoin::address::ParseError),
295    /// A `CHECKMULTISIG` opcode was preceded by a number > 20
296    CmsTooManyKeys(u32),
297    /// A tapscript multi_a cannot support more than MAX_BLOCK_WEIGHT/32 keys
298    MultiATooManyKeys(u32),
299    /// expected character while parsing descriptor; didn't find one
300    ExpectedChar(char),
301    /// While parsing backward, hit beginning of script
302    UnexpectedStart,
303    /// Got something we were not expecting
304    Unexpected(String),
305    /// Name of a fragment contained `:` multiple times
306    MultiColon(String),
307    /// Name of a fragment contained `@` multiple times
308    MultiAt(String),
309    /// Name of a fragment contained `@` but we were not parsing an OR
310    AtOutsideOr(String),
311    /// Encountered a `l:0` which is syntactically equal to `u:0` except stupid
312    LikelyFalse,
313    /// Encountered a wrapping character that we don't recognize
314    UnknownWrapper(char),
315    /// Parsed a miniscript and the result was not of type T
316    NonTopLevel(String),
317    /// Parsed a miniscript but there were more script opcodes after it
318    Trailing(String),
319    /// Failed to parse a push as a public key
320    BadPubkey(bitcoin::key::ParsePublicKeyError),
321    /// Failed to parse a slice as public key
322    BadPubkeySlice(bitcoin::key::FromSliceError),
323    /// Could not satisfy a script (fragment) because of a missing hash preimage
324    MissingHash(sha256::Hash),
325    /// Could not satisfy a script (fragment) because of a missing signature
326    MissingSig(bitcoin::PublicKey),
327    /// Could not satisfy, relative locktime not met
328    RelativeLocktimeNotMet(u32),
329    /// Could not satisfy, absolute locktime not met
330    AbsoluteLocktimeNotMet(u32),
331    /// General failure to satisfy
332    CouldNotSatisfy,
333    /// Typechecking failed
334    TypeCheck(String),
335    /// General error in creating descriptor
336    BadDescriptor(String),
337    /// Forward-secp related errors
338    Secp(elements::secp256k1_zkp::Error),
339    #[cfg(feature = "compiler")]
340    /// Compiler related errors
341    CompilerError(policy::compiler::CompilerError),
342    /// Errors related to policy
343    PolicyError(policy::concrete::PolicyError),
344    /// Errors related to lifting
345    LiftError(policy::LiftError),
346    /// Forward script context related errors
347    ContextError(miniscript::context::ScriptContextError),
348    /// Recursion depth exceeded when parsing policy/miniscript from string
349    MaxRecursiveDepthExceeded,
350    /// Script size too large
351    ScriptSizeTooLarge,
352    /// Anything but c:pk(key) (P2PK), c:pk_h(key) (P2PKH), and thresh_m(k,...)
353    /// up to n=3 is invalid by standardness (bare)
354    NonStandardBareScript,
355    /// Analysis Error
356    AnalysisError(miniscript::analyzable::AnalysisError),
357    /// Miniscript is equivalent to false. No possible satisfaction
358    ImpossibleSatisfaction,
359    /// Bare descriptors don't have any addresses
360    BareDescriptorAddr,
361    /// Upstream Miniscript Errors
362    BtcError(bitcoin_miniscript::Error),
363    /// Covenant Error
364    CovError(descriptor::CovError),
365    /// PubKey invalid under current context
366    PubKeyCtxError(miniscript::decode::KeyParseError, &'static str),
367    /// Attempted to call function that requires PreComputed taproot info
368    TaprootSpendInfoUnavialable,
369    /// No script code for Tr descriptors
370    TrNoScriptCode,
371    /// No explicit script for Tr descriptors
372    TrNoExplicitScript,
373    /// At least two BIP389 key expressions in the descriptor contain tuples of
374    /// derivation indexes of different lengths.
375    MultipathDescLenMismatch,
376}
377
378#[doc(hidden)]
379impl<Pk, Ctx, Ext> From<miniscript::types::Error<Pk, Ctx, Ext>> for Error
380where
381    Pk: MiniscriptKey,
382    Ctx: ScriptContext,
383    Ext: Extension,
384{
385    fn from(e: miniscript::types::Error<Pk, Ctx, Ext>) -> Error {
386        Error::TypeCheck(e.to_string())
387    }
388}
389
390#[doc(hidden)]
391impl From<bitcoin_miniscript::Error> for Error {
392    fn from(e: bitcoin_miniscript::Error) -> Error {
393        Error::BtcError(e)
394    }
395}
396
397#[doc(hidden)]
398impl From<policy::LiftError> for Error {
399    fn from(e: policy::LiftError) -> Error {
400        Error::LiftError(e)
401    }
402}
403
404#[doc(hidden)]
405impl From<miniscript::context::ScriptContextError> for Error {
406    fn from(e: miniscript::context::ScriptContextError) -> Error {
407        Error::ContextError(e)
408    }
409}
410
411#[doc(hidden)]
412impl From<miniscript::analyzable::AnalysisError> for Error {
413    fn from(e: miniscript::analyzable::AnalysisError) -> Error {
414        Error::AnalysisError(e)
415    }
416}
417
418#[doc(hidden)]
419impl From<elements::secp256k1_zkp::Error> for Error {
420    fn from(e: elements::secp256k1_zkp::Error) -> Error {
421        Error::Secp(e)
422    }
423}
424
425#[doc(hidden)]
426impl From<elements::secp256k1_zkp::UpstreamError> for Error {
427    fn from(e: elements::secp256k1_zkp::UpstreamError) -> Error {
428        Error::Secp(elements::secp256k1_zkp::Error::Upstream(e))
429    }
430}
431
432#[doc(hidden)]
433impl From<bitcoin::key::ParsePublicKeyError> for Error {
434    fn from(e: bitcoin::key::ParsePublicKeyError) -> Error {
435        Error::BadPubkey(e)
436    }
437}
438
439#[doc(hidden)]
440impl From<bitcoin::key::FromSliceError> for Error {
441    fn from(e: bitcoin::key::FromSliceError) -> Error {
442        Error::BadPubkeySlice(e)
443    }
444}
445
446impl From<bitcoin::address::ParseError> for Error {
447    fn from(e: bitcoin::address::ParseError) -> Error {
448        Error::AddrError(e)
449    }
450}
451
452fn errstr(s: &str) -> Error {
453    Error::Unexpected(s.to_owned())
454}
455
456// https://github.com/sipa/miniscript/pull/5 for discussion on this number
457const MAX_RECURSION_DEPTH: u32 = 402;
458// https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki
459const MAX_SCRIPT_SIZE: u32 = 10000;
460
461impl fmt::Display for Error {
462    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
463        match *self {
464            Error::InvalidOpcode(op) => write!(f, "invalid opcode {}", op),
465            Error::NonMinimalVerify(ref tok) => write!(f, "{} VERIFY", tok),
466            Error::InvalidPush(ref push) => {
467                write!(f, "invalid push ")?;
468                elements::hex::format_hex(push, f)
469            },
470            Error::Script(ref e) => fmt::Display::fmt(e, f),
471            Error::AddrError(ref e) => fmt::Display::fmt(e, f),
472            Error::CmsTooManyKeys(n) => write!(f, "checkmultisig with {} keys", n),
473            Error::ExpectedChar(c) => write!(f, "expected {}", c),
474            Error::UnexpectedStart => f.write_str("unexpected start of script"),
475            Error::Unexpected(ref s) => write!(f, "unexpected «{}»", s),
476            Error::MultiColon(ref s) => write!(f, "«{}» has multiple instances of «:»", s),
477            Error::MultiAt(ref s) => write!(f, "«{}» has multiple instances of «@»", s),
478            Error::AtOutsideOr(ref s) => write!(f, "«{}» contains «@» in non-or() context", s),
479            Error::LikelyFalse => write!(f, "0 is not very likely (use «u:0»)"),
480            Error::UnknownWrapper(ch) => write!(f, "unknown wrapper «{}:»", ch),
481            Error::NonTopLevel(ref s) => write!(f, "non-T miniscript: {}", s),
482            Error::Trailing(ref s) => write!(f, "trailing tokens: {}", s),
483            Error::MissingHash(ref h) => write!(f, "missing preimage of hash {}", h),
484            Error::MissingSig(ref pk) => write!(f, "missing signature for key {:?}", pk),
485            Error::RelativeLocktimeNotMet(n) => {
486                write!(f, "required relative locktime CSV of {} blocks, not met", n)
487            }
488            Error::AbsoluteLocktimeNotMet(n) => write!(
489                f,
490                "required absolute locktime CLTV of {} blocks, not met",
491                n
492            ),
493            Error::CouldNotSatisfy => f.write_str("could not satisfy"),
494            Error::BadPubkey(ref e) => fmt::Display::fmt(e, f),
495            Error::BadPubkeySlice(ref e) => fmt::Display::fmt(e, f),
496            Error::TypeCheck(ref e) => write!(f, "typecheck: {}", e),
497            Error::BadDescriptor(ref e) => write!(f, "Invalid descriptor: {}", e),
498            Error::Secp(ref e) => fmt::Display::fmt(e, f),
499            Error::ContextError(ref e) => fmt::Display::fmt(e, f),
500            #[cfg(feature = "compiler")]
501            Error::CompilerError(ref e) => fmt::Display::fmt(e, f),
502            Error::PolicyError(ref e) => fmt::Display::fmt(e, f),
503            Error::LiftError(ref e) => fmt::Display::fmt(e, f),
504            Error::MaxRecursiveDepthExceeded => write!(
505                f,
506                "Recursive depth over {} not permitted",
507                MAX_RECURSION_DEPTH
508            ),
509            Error::ScriptSizeTooLarge => write!(
510                f,
511                "Standardness rules imply bitcoin than {} bytes",
512                MAX_SCRIPT_SIZE
513            ),
514            Error::NonStandardBareScript => write!(
515                f,
516                "Anything but c:pk(key) (P2PK), c:pk_h(key) (P2PKH), and thresh_m(k,...) \
517                up to n=3 is invalid by standardness (bare).
518                "
519            ),
520            Error::AnalysisError(ref e) => e.fmt(f),
521            Error::ImpossibleSatisfaction => write!(f, "Impossible to satisfy Miniscript"),
522            Error::BareDescriptorAddr => write!(f, "Bare descriptors don't have address"),
523            Error::BtcError(ref e) => write!(f, " Bitcoin Miniscript Error {}", e),
524            Error::CovError(ref e) => write!(f, "Covenant Error: {}", e),
525            Error::PubKeyCtxError(ref pk, ref ctx) => {
526                write!(f, "Pubkey error: {} under {} scriptcontext", pk, ctx)
527            }
528            Error::MultiATooManyKeys(k) => write!(f, "MultiA too many keys {}", k),
529            Error::TaprootSpendInfoUnavialable => write!(f, "Taproot Spend Info not computed."),
530            Error::TrNoScriptCode => write!(f, "No script code for Tr descriptors"),
531            Error::TrNoExplicitScript => write!(f, "No script code for Tr descriptors"),
532            Error::MultipathDescLenMismatch => write!(f, "At least two BIP389 key expressions in the descriptor contain tuples of derivation indexes of different lengths"),
533        }
534    }
535}
536
537impl error::Error for Error {
538    fn cause(&self) -> Option<&dyn error::Error> {
539        use self::Error::*;
540
541        match self {
542            InvalidOpcode(_)
543            | NonMinimalVerify(_)
544            | InvalidPush(_)
545            | CmsTooManyKeys(_)
546            | MultiATooManyKeys(_)
547            | ExpectedChar(_)
548            | UnexpectedStart
549            | Unexpected(_)
550            | MultiColon(_)
551            | MultiAt(_)
552            | AtOutsideOr(_)
553            | LikelyFalse
554            | UnknownWrapper(_)
555            | NonTopLevel(_)
556            | Trailing(_)
557            | MissingHash(_)
558            | MissingSig(_)
559            | RelativeLocktimeNotMet(_)
560            | AbsoluteLocktimeNotMet(_)
561            | CouldNotSatisfy
562            | TypeCheck(_)
563            | BadDescriptor(_)
564            | MaxRecursiveDepthExceeded
565            | ScriptSizeTooLarge
566            | NonStandardBareScript
567            | ImpossibleSatisfaction
568            | BareDescriptorAddr
569            | TaprootSpendInfoUnavialable
570            | TrNoScriptCode
571            | TrNoExplicitScript => None,
572            MultipathDescLenMismatch => None,
573            BtcError(e) => Some(e),
574            CovError(e) => Some(e),
575            Script(_e) => None, // should be Some(e), but requires changes upstream
576            AddrError(e) => Some(e),
577            BadPubkey(e) => Some(e),
578            BadPubkeySlice(e) => Some(e),
579            Secp(e) => Some(e),
580            #[cfg(feature = "compiler")]
581            CompilerError(e) => Some(e),
582            PolicyError(e) => Some(e),
583            LiftError(e) => Some(e),
584            ContextError(e) => Some(e),
585            AnalysisError(e) => Some(e),
586            PubKeyCtxError(e, _) => Some(e),
587        }
588    }
589}
590
591#[doc(hidden)]
592#[cfg(feature = "compiler")]
593impl From<policy::compiler::CompilerError> for Error {
594    fn from(e: policy::compiler::CompilerError) -> Error {
595        Error::CompilerError(e)
596    }
597}
598
599#[doc(hidden)]
600impl From<policy::concrete::PolicyError> for Error {
601    fn from(e: policy::concrete::PolicyError) -> Error {
602        Error::PolicyError(e)
603    }
604}
605
606/// The size of an encoding of a number in Script
607pub fn script_num_size(n: usize) -> usize {
608    match n {
609        n if n <= 0x10 => 1,      // OP_n
610        n if n < 0x80 => 2,       // OP_PUSH1 <n>
611        n if n < 0x8000 => 3,     // OP_PUSH2 <n>
612        n if n < 0x800000 => 4,   // OP_PUSH3 <n>
613        n if n < 0x80000000 => 5, // OP_PUSH4 <n>
614        _ => 6,                   // OP_PUSH5 <n>
615    }
616}
617
618/// Returns the size of the smallest push opcode used to push a given number of bytes onto the stack
619///
620/// For sizes ≤ 75, there are dedicated single-byte opcodes, so the push size is one. Otherwise,
621/// if the size can fit into 1, 2 or 4 bytes, we use the `PUSHDATA{1,2,4}` opcode respectively,
622/// followed by the actual size encoded in that many bytes.
623fn push_opcode_size(script_size: usize) -> usize {
624    if script_size < 76 {
625        1
626    } else if script_size < 0x100 {
627        2
628    } else if script_size < 0x10000 {
629        3
630    } else {
631        5
632    }
633}
634
635/// An absolute locktime that implements `Ord`.
636#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
637pub struct AbsLockTime(locktime::LockTime);
638
639impl AbsLockTime {
640    /// Constructs an `AbsLockTime` from an nLockTime value or the argument to OP_CHEKCLOCKTIMEVERIFY.
641    pub fn from_consensus(n: u32) -> Self {
642        Self(locktime::LockTime::from_consensus(n))
643    }
644
645    /// Returns the inner `u32` value. This is the value used when creating this `LockTime`
646    /// i.e., `n OP_CHECKLOCKTIMEVERIFY` or nLockTime.
647    ///
648    /// This calls through to `locktime::LockTime::to_consensus_u32()` and the same usage warnings
649    /// apply.
650    pub fn to_consensus_u32(self) -> u32 {
651        self.0.to_consensus_u32()
652    }
653
654    /// Returns the inner `u32` value.
655    ///
656    /// Equivalent to `AbsLockTime::to_consensus_u32()`.
657    pub fn to_u32(self) -> u32 {
658        self.to_consensus_u32()
659    }
660}
661
662impl From<locktime::LockTime> for AbsLockTime {
663    fn from(lock_time: locktime::LockTime) -> Self {
664        Self(lock_time)
665    }
666}
667
668impl From<AbsLockTime> for locktime::LockTime {
669    fn from(lock_time: AbsLockTime) -> locktime::LockTime {
670        lock_time.0
671    }
672}
673
674impl cmp::PartialOrd for AbsLockTime {
675    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
676        Some(self.cmp(other))
677    }
678}
679
680impl cmp::Ord for AbsLockTime {
681    fn cmp(&self, other: &Self) -> cmp::Ordering {
682        let this = self.0.to_consensus_u32();
683        let that = other.0.to_consensus_u32();
684        this.cmp(&that)
685    }
686}
687
688impl fmt::Display for AbsLockTime {
689    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
690        fmt::Display::fmt(&self.0, f)
691    }
692}
693
694/// Helper function used by tests
695#[cfg(test)]
696fn hex_script(s: &str) -> elements::Script {
697    let v: Vec<u8> = elements::hex::FromHex::from_hex(s).unwrap();
698    elements::Script::from(v)
699}
700
701#[cfg(test)]
702mod tests {
703    use std::str::FromStr;
704
705    use bitcoin::hashes::hash160;
706
707    use super::*;
708
709    #[test]
710    fn regression_bitcoin_key_hash() {
711        use bitcoin::PublicKey;
712
713        // Uncompressed key.
714        let pk = PublicKey::from_str(
715            "042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133"
716        ).unwrap();
717
718        let want = hash160::Hash::from_str("ac2e7daf42d2c97418fd9f78af2de552bb9c6a7a").unwrap();
719        let got = pk.to_pubkeyhash(SigType::Ecdsa);
720        assert_eq!(got, want)
721    }
722
723    #[test]
724    fn regression_secp256k1_key_hash() {
725        use bitcoin::secp256k1::PublicKey;
726
727        // Compressed key.
728        let pk = PublicKey::from_str(
729            "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af",
730        )
731        .unwrap();
732
733        let want = hash160::Hash::from_str("9511aa27ef39bbfa4e4f3dd15f4d66ea57f475b4").unwrap();
734        let got = pk.to_pubkeyhash(SigType::Ecdsa);
735        assert_eq!(got, want)
736    }
737
738    #[test]
739    fn regression_xonly_key_hash() {
740        use bitcoin::secp256k1::XOnlyPublicKey;
741
742        let pk = XOnlyPublicKey::from_str(
743            "cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115",
744        )
745        .unwrap();
746
747        let want = hash160::Hash::from_str("eb8ac65f971ae688a94aeabf223506865e7e08f2").unwrap();
748        let got = pk.to_pubkeyhash(SigType::Schnorr);
749        assert_eq!(got, want)
750    }
751}