#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
#![cfg_attr(bench, feature(test))]
#![warn(missing_docs)]
#![deny(unsafe_code)]
#![allow(clippy::iter_kv_map)] #![allow(clippy::manual_range_contains)] #![allow(unexpected_cfgs)]
#[cfg(target_pointer_width = "16")]
compile_error!(
"rust-miniscript currently only supports architectures with pointers wider than 16 bits"
);
pub use {bitcoin, hex};
#[cfg(not(feature = "std"))]
#[macro_use]
extern crate alloc;
#[cfg(any(feature = "std", test))]
extern crate core;
#[cfg(feature = "serde")]
pub use serde;
#[cfg(bench)]
extern crate test;
#[macro_use]
mod macros;
#[macro_use]
mod pub_macros;
#[cfg(bench)]
mod benchmarks;
mod blanket_traits;
pub mod descriptor;
mod error;
pub mod expression;
pub mod interpreter;
pub mod iter;
pub mod miniscript;
pub mod plan;
pub mod policy;
mod primitives;
pub mod psbt;
#[cfg(test)]
mod test_utils;
mod util;
use core::{fmt, hash, str};
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash};
pub use crate::blanket_traits::FromStrKey;
pub use crate::descriptor::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey};
pub use crate::error::ParseError;
pub use crate::expression::{ParseNumError, ParseThresholdError, ParseTreeError};
pub use crate::interpreter::Interpreter;
pub use crate::miniscript::analyzable::{AnalysisError, ExtParams};
pub use crate::miniscript::context::{BareCtx, Legacy, ScriptContext, Segwitv0, SigType, Tap};
pub use crate::miniscript::decode::Terminal;
pub use crate::miniscript::satisfy::{Preimage32, Satisfier};
pub use crate::miniscript::{hash256, Miniscript};
use crate::prelude::*;
pub use crate::primitives::absolute_locktime::{AbsLockTime, AbsLockTimeError};
pub use crate::primitives::relative_locktime::{RelLockTime, RelLockTimeError};
pub use crate::primitives::threshold::{Threshold, ThresholdError};
pub trait MiniscriptKey: Clone + Eq + Ord + fmt::Debug + fmt::Display + hash::Hash {
fn is_uncompressed(&self) -> bool { false }
fn is_x_only_key(&self) -> bool { false }
fn num_der_paths(&self) -> usize { 0 }
type Sha256: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash;
type Hash256: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash;
type Ripemd160: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash;
type Hash160: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash;
}
impl MiniscriptKey for bitcoin::secp256k1::PublicKey {
type Sha256 = sha256::Hash;
type Hash256 = hash256::Hash;
type Ripemd160 = ripemd160::Hash;
type Hash160 = hash160::Hash;
}
impl MiniscriptKey for bitcoin::PublicKey {
fn is_uncompressed(&self) -> bool { !self.compressed }
type Sha256 = sha256::Hash;
type Hash256 = hash256::Hash;
type Ripemd160 = ripemd160::Hash;
type Hash160 = hash160::Hash;
}
impl MiniscriptKey for bitcoin::secp256k1::XOnlyPublicKey {
type Sha256 = sha256::Hash;
type Hash256 = hash256::Hash;
type Ripemd160 = ripemd160::Hash;
type Hash160 = hash160::Hash;
fn is_x_only_key(&self) -> bool { true }
}
impl MiniscriptKey for String {
type Sha256 = String; type Hash256 = String;
type Ripemd160 = String;
type Hash160 = String;
}
pub trait ToPublicKey: MiniscriptKey {
fn to_public_key(&self) -> bitcoin::PublicKey;
fn to_x_only_pubkey(&self) -> bitcoin::secp256k1::XOnlyPublicKey {
let pk = self.to_public_key();
bitcoin::secp256k1::XOnlyPublicKey::from(pk.inner)
}
fn to_pubkeyhash(&self, sig_type: SigType) -> hash160::Hash {
match sig_type {
SigType::Ecdsa => hash160::Hash::hash(&self.to_public_key().to_bytes()),
SigType::Schnorr => hash160::Hash::hash(&self.to_x_only_pubkey().serialize()),
}
}
fn to_sha256(hash: &<Self as MiniscriptKey>::Sha256) -> sha256::Hash;
fn to_hash256(hash: &<Self as MiniscriptKey>::Hash256) -> hash256::Hash;
fn to_ripemd160(hash: &<Self as MiniscriptKey>::Ripemd160) -> ripemd160::Hash;
fn to_hash160(hash: &<Self as MiniscriptKey>::Hash160) -> hash160::Hash;
}
impl ToPublicKey for bitcoin::PublicKey {
fn to_public_key(&self) -> bitcoin::PublicKey { *self }
fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash }
fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { *hash }
fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash { *hash }
fn to_hash160(hash: &hash160::Hash) -> hash160::Hash { *hash }
}
impl ToPublicKey for bitcoin::secp256k1::PublicKey {
fn to_public_key(&self) -> bitcoin::PublicKey { bitcoin::PublicKey::new(*self) }
fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash }
fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { *hash }
fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash { *hash }
fn to_hash160(hash: &hash160::Hash) -> hash160::Hash { *hash }
}
impl ToPublicKey for bitcoin::secp256k1::XOnlyPublicKey {
fn to_public_key(&self) -> bitcoin::PublicKey {
let mut data: Vec<u8> = vec![0x02];
data.extend(self.serialize().iter());
bitcoin::PublicKey::from_slice(&data)
.expect("Failed to construct 33 Publickey from 0x02 appended x-only key")
}
fn to_x_only_pubkey(&self) -> bitcoin::secp256k1::XOnlyPublicKey { *self }
fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash }
fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { *hash }
fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash { *hash }
fn to_hash160(hash: &hash160::Hash) -> hash160::Hash { *hash }
}
pub trait Translator<P: MiniscriptKey> {
type TargetPk: MiniscriptKey;
type Error;
fn pk(&mut self, pk: &P) -> Result<Self::TargetPk, Self::Error>;
fn sha256(
&mut self,
sha256: &P::Sha256,
) -> Result<<Self::TargetPk as MiniscriptKey>::Sha256, Self::Error>;
fn hash256(
&mut self,
hash256: &P::Hash256,
) -> Result<<Self::TargetPk as MiniscriptKey>::Hash256, Self::Error>;
fn ripemd160(
&mut self,
ripemd160: &P::Ripemd160,
) -> Result<<Self::TargetPk as MiniscriptKey>::Ripemd160, Self::Error>;
fn hash160(
&mut self,
hash160: &P::Hash160,
) -> Result<<Self::TargetPk as MiniscriptKey>::Hash160, Self::Error>;
}
pub enum TranslateErr<E> {
TranslatorErr(E),
OuterError(Error),
}
impl<E> TranslateErr<E> {
pub fn expect_translator_err(self, msg: &str) -> E {
match self {
Self::TranslatorErr(v) => v,
Self::OuterError(ref e) => {
panic!("Unexpected Miniscript error when translating: {}\nMessage: {}", e, msg)
}
}
}
}
impl TranslateErr<core::convert::Infallible> {
pub fn into_outer_err(self) -> Error {
match self {
Self::TranslatorErr(impossible) => match impossible {},
Self::OuterError(e) => e,
}
}
}
impl TranslateErr<Error> {
pub fn flatten(self) -> Error {
match self {
Self::TranslatorErr(e) => e,
Self::OuterError(e) => e,
}
}
}
impl<E> From<E> for TranslateErr<E> {
fn from(v: E) -> Self { Self::TranslatorErr(v) }
}
impl<E: fmt::Debug> fmt::Debug for TranslateErr<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::TranslatorErr(e) => write!(f, "TranslatorErr({:?})", e),
Self::OuterError(e) => write!(f, "OuterError({:?})", e),
}
}
}
#[deprecated(since = "TBD", note = "This trait no longer needs to be imported.")]
pub trait TranslatePk<P, Q>
where
P: MiniscriptKey,
Q: MiniscriptKey,
{
}
pub trait ForEachKey<Pk: MiniscriptKey> {
fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool
where
Pk: 'a;
fn for_any_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool
where
Pk: 'a,
{
!self.for_each_key(|key| !pred(key))
}
}
#[derive(Debug)]
pub enum Error {
ScriptLexer(crate::miniscript::lex::Error),
AddrError(bitcoin::address::ParseError),
AddrP2shError(bitcoin::address::P2shError),
UnexpectedStart,
Unexpected(String),
UnknownWrapper(char),
NonTopLevel(String),
Trailing(String),
MissingSig(bitcoin::PublicKey),
CouldNotSatisfy,
TypeCheck(String),
Secp(bitcoin::secp256k1::Error),
#[cfg(feature = "compiler")]
CompilerError(crate::policy::compiler::CompilerError),
ConcretePolicy(policy::concrete::PolicyError),
LiftError(policy::LiftError),
ContextError(miniscript::context::ScriptContextError),
TapTreeDepthError(crate::descriptor::TapTreeDepthError),
MaxRecursiveDepthExceeded,
NonStandardBareScript,
AnalysisError(miniscript::analyzable::AnalysisError),
ImpossibleSatisfaction,
BareDescriptorAddr,
PubKeyCtxError(miniscript::decode::KeyError, &'static str),
TrNoScriptCode,
MultipathDescLenMismatch,
AbsoluteLockTime(AbsLockTimeError),
RelativeLockTime(RelLockTimeError),
Threshold(ThresholdError),
ParseThreshold(ParseThresholdError),
Parse(ParseError),
}
#[doc(hidden)] impl From<ParseThresholdError> for Error {
fn from(e: ParseThresholdError) -> Self { Self::ParseThreshold(e) }
}
const MAX_RECURSION_DEPTH: u32 = 402;
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::ScriptLexer(ref e) => e.fmt(f),
Error::AddrError(ref e) => fmt::Display::fmt(e, f),
Error::AddrP2shError(ref e) => fmt::Display::fmt(e, f),
Error::UnexpectedStart => f.write_str("unexpected start of script"),
Error::Unexpected(ref s) => write!(f, "unexpected «{}»", s),
Error::UnknownWrapper(ch) => write!(f, "unknown wrapper «{}:»", ch),
Error::NonTopLevel(ref s) => write!(f, "non-T miniscript: {}", s),
Error::Trailing(ref s) => write!(f, "trailing tokens: {}", s),
Error::MissingSig(ref pk) => write!(f, "missing signature for key {:?}", pk),
Error::CouldNotSatisfy => f.write_str("could not satisfy"),
Error::TypeCheck(ref e) => write!(f, "typecheck: {}", e),
Error::Secp(ref e) => fmt::Display::fmt(e, f),
Error::ContextError(ref e) => fmt::Display::fmt(e, f),
Error::TapTreeDepthError(ref e) => fmt::Display::fmt(e, f),
#[cfg(feature = "compiler")]
Error::CompilerError(ref e) => fmt::Display::fmt(e, f),
Error::ConcretePolicy(ref e) => fmt::Display::fmt(e, f),
Error::LiftError(ref e) => fmt::Display::fmt(e, f),
Error::MaxRecursiveDepthExceeded => write!(
f,
"Recursive depth over {} not permitted",
MAX_RECURSION_DEPTH
),
Error::NonStandardBareScript => write!(
f,
"Anything but c:pk(key) (P2PK), c:pk_h(key) (P2PKH), and thresh_m(k,...) \
up to n=3 is invalid by standardness (bare).
"
),
Error::AnalysisError(ref e) => e.fmt(f),
Error::ImpossibleSatisfaction => write!(f, "Impossible to satisfy Miniscript"),
Error::BareDescriptorAddr => write!(f, "Bare descriptors don't have address"),
Error::PubKeyCtxError(ref pk, ref ctx) => {
write!(f, "Pubkey error: {} under {} scriptcontext", pk, ctx)
}
Error::TrNoScriptCode => write!(f, "No script code for Tr descriptors"),
Error::MultipathDescLenMismatch => write!(f, "At least two BIP389 key expressions in the descriptor contain tuples of derivation indexes of different lengths"),
Error::AbsoluteLockTime(ref e) => e.fmt(f),
Error::RelativeLockTime(ref e) => e.fmt(f),
Error::Threshold(ref e) => e.fmt(f),
Error::ParseThreshold(ref e) => e.fmt(f),
Error::Parse(ref e) => e.fmt(f),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {
fn cause(&self) -> Option<&dyn std::error::Error> {
use self::Error::*;
match self {
UnexpectedStart
| Unexpected(_)
| UnknownWrapper(_)
| NonTopLevel(_)
| Trailing(_)
| MissingSig(_)
| CouldNotSatisfy
| TypeCheck(_)
| MaxRecursiveDepthExceeded
| NonStandardBareScript
| ImpossibleSatisfaction
| BareDescriptorAddr
| TrNoScriptCode
| MultipathDescLenMismatch => None,
ScriptLexer(e) => Some(e),
AddrError(e) => Some(e),
AddrP2shError(e) => Some(e),
Secp(e) => Some(e),
#[cfg(feature = "compiler")]
CompilerError(e) => Some(e),
ConcretePolicy(e) => Some(e),
LiftError(e) => Some(e),
ContextError(e) => Some(e),
TapTreeDepthError(e) => Some(e),
AnalysisError(e) => Some(e),
PubKeyCtxError(e, _) => Some(e),
AbsoluteLockTime(e) => Some(e),
RelativeLockTime(e) => Some(e),
Threshold(e) => Some(e),
ParseThreshold(e) => Some(e),
Parse(e) => Some(e),
}
}
}
#[doc(hidden)]
impl From<miniscript::lex::Error> for Error {
fn from(e: miniscript::lex::Error) -> Error { Error::ScriptLexer(e) }
}
#[doc(hidden)]
impl From<miniscript::types::Error> for Error {
fn from(e: miniscript::types::Error) -> Error { Error::TypeCheck(e.to_string()) }
}
#[doc(hidden)]
impl From<policy::LiftError> for Error {
fn from(e: policy::LiftError) -> Error { Error::LiftError(e) }
}
#[doc(hidden)]
impl From<crate::descriptor::TapTreeDepthError> for Error {
fn from(e: crate::descriptor::TapTreeDepthError) -> Error { Error::TapTreeDepthError(e) }
}
#[doc(hidden)]
impl From<miniscript::context::ScriptContextError> for Error {
fn from(e: miniscript::context::ScriptContextError) -> Error { Error::ContextError(e) }
}
#[doc(hidden)]
impl From<miniscript::analyzable::AnalysisError> for Error {
fn from(e: miniscript::analyzable::AnalysisError) -> Error { Error::AnalysisError(e) }
}
#[doc(hidden)]
impl From<bitcoin::secp256k1::Error> for Error {
fn from(e: bitcoin::secp256k1::Error) -> Error { Error::Secp(e) }
}
#[doc(hidden)]
impl From<bitcoin::address::ParseError> for Error {
fn from(e: bitcoin::address::ParseError) -> Error { Error::AddrError(e) }
}
#[doc(hidden)]
impl From<bitcoin::address::P2shError> for Error {
fn from(e: bitcoin::address::P2shError) -> Error { Error::AddrP2shError(e) }
}
#[doc(hidden)]
#[cfg(feature = "compiler")]
impl From<crate::policy::compiler::CompilerError> for Error {
fn from(e: crate::policy::compiler::CompilerError) -> Error { Error::CompilerError(e) }
}
pub fn script_num_size(n: usize) -> usize {
match n {
n if n <= 0x10 => 1, n if n < 0x80 => 2, n if n < 0x8000 => 3, n if n < 0x800000 => 4, n if n < 0x80000000 => 5, _ => 6, }
}
fn push_opcode_size(script_size: usize) -> usize {
if script_size < 76 {
1
} else if script_size < 0x100 {
2
} else if script_size < 0x10000 {
3
} else {
5
}
}
#[cfg(test)]
fn hex_script(s: &str) -> bitcoin::ScriptBuf { bitcoin::ScriptBuf::from_hex(s).unwrap() }
#[cfg(test)]
mod tests {
use core::str::FromStr;
use super::*;
#[test]
fn regression_bitcoin_key_hash() {
use bitcoin::PublicKey;
let pk = PublicKey::from_str(
"042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133"
).unwrap();
let want = hash160::Hash::from_str("ac2e7daf42d2c97418fd9f78af2de552bb9c6a7a").unwrap();
let got = pk.to_pubkeyhash(SigType::Ecdsa);
assert_eq!(got, want)
}
#[test]
fn regression_secp256k1_key_hash() {
use bitcoin::secp256k1::PublicKey;
let pk = PublicKey::from_str(
"032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af",
)
.unwrap();
let want = hash160::Hash::from_str("9511aa27ef39bbfa4e4f3dd15f4d66ea57f475b4").unwrap();
let got = pk.to_pubkeyhash(SigType::Ecdsa);
assert_eq!(got, want)
}
#[test]
fn regression_xonly_key_hash() {
use bitcoin::secp256k1::XOnlyPublicKey;
let pk = XOnlyPublicKey::from_str(
"cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115",
)
.unwrap();
let want = hash160::Hash::from_str("eb8ac65f971ae688a94aeabf223506865e7e08f2").unwrap();
let got = pk.to_pubkeyhash(SigType::Schnorr);
assert_eq!(got, want)
}
}
#[allow(unused_imports)] mod prelude {
#[cfg(all(not(feature = "std"), not(test)))]
mod mutex {
use core::cell::{RefCell, RefMut};
use core::ops::{Deref, DerefMut};
pub type LockResult<Guard> = Result<Guard, ()>;
pub struct Mutex<T: ?Sized> {
inner: RefCell<T>,
}
#[must_use = "if unused the Mutex will immediately unlock"]
pub struct MutexGuard<'a, T: ?Sized + 'a> {
lock: RefMut<'a, T>,
}
impl<T: ?Sized> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T { self.lock.deref() }
}
impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T { self.lock.deref_mut() }
}
impl<T> Mutex<T> {
pub fn new(inner: T) -> Mutex<T> { Mutex { inner: RefCell::new(inner) } }
pub fn lock(&self) -> LockResult<MutexGuard<'_, T>> {
Ok(MutexGuard { lock: self.inner.borrow_mut() })
}
}
}
#[cfg(all(not(feature = "std"), not(test)))]
pub use alloc::{
borrow::{Borrow, Cow, ToOwned},
boxed::Box,
collections::{btree_map, vec_deque::VecDeque, BTreeMap, BTreeSet, BinaryHeap},
rc, slice,
string::{String, ToString},
sync,
vec::Vec,
};
#[cfg(any(feature = "std", test))]
pub use std::{
borrow::{Borrow, Cow, ToOwned},
boxed::Box,
collections::{
btree_map, vec_deque::VecDeque, BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet,
},
rc, slice,
string::{String, ToString},
sync,
sync::Mutex,
vec::Vec,
};
#[cfg(all(not(feature = "std"), not(test)))]
pub use self::mutex::Mutex;
}