#![cfg_attr(all(test, feature = "unstable"), feature(test))]
#![deny(unsafe_code)]
#![deny(non_upper_case_globals)]
#![deny(non_camel_case_types)]
#![deny(non_snake_case)]
#![deny(unused_mut)]
#![deny(dead_code)]
#![deny(unused_imports)]
#![deny(missing_docs)]
pub extern crate bitcoin;
#[cfg(feature = "serde")]
pub extern crate serde;
#[cfg(all(test, feature = "unstable"))]
extern crate test;
#[macro_use]
mod macros;
pub mod descriptor;
pub mod expression;
pub mod interpreter;
pub mod miniscript;
pub mod policy;
pub mod psbt;
mod util;
use std::str::FromStr;
use std::{error, fmt, hash, str};
use bitcoin::blockdata::{opcodes, script};
use bitcoin::hashes::{hash160, sha256, Hash};
pub use descriptor::{Descriptor, DescriptorPublicKey, DescriptorTrait};
pub use interpreter::Interpreter;
pub use miniscript::context::{BareCtx, Legacy, ScriptContext, Segwitv0, Tap};
pub use miniscript::decode::Terminal;
pub use miniscript::satisfy::{Preimage32, Satisfier};
pub use miniscript::Miniscript;
pub use descriptor::pretaproot::{traits::PreTaprootDescriptorTrait, PreTaprootDescriptor};
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
}
type Hash: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash;
fn to_pubkeyhash(&self) -> Self::Hash;
}
impl MiniscriptKey for bitcoin::PublicKey {
fn is_uncompressed(&self) -> bool {
!self.compressed
}
type Hash = hash160::Hash;
fn to_pubkeyhash(&self) -> Self::Hash {
let mut engine = hash160::Hash::engine();
self.write_into(&mut engine).expect("engines don't error");
hash160::Hash::from_engine(engine)
}
}
impl MiniscriptKey for bitcoin::secp256k1::XOnlyPublicKey {
type Hash = hash160::Hash;
fn to_pubkeyhash(&self) -> Self::Hash {
hash160::Hash::hash(&self.serialize())
}
fn is_x_only_key(&self) -> bool {
true
}
}
impl MiniscriptKey for String {
type Hash = String;
fn to_pubkeyhash(&self) -> Self::Hash {
format!("{}", &self)
}
}
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 hash_to_hash160(hash: &<Self as MiniscriptKey>::Hash) -> hash160::Hash;
}
impl ToPublicKey for bitcoin::PublicKey {
fn to_public_key(&self) -> bitcoin::PublicKey {
*self
}
fn hash_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 hash_to_hash160(hash: &hash160::Hash) -> hash160::Hash {
*hash
}
}
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)]
pub struct DummyKey;
impl str::FromStr for DummyKey {
type Err = &'static str;
fn from_str(x: &str) -> Result<DummyKey, &'static str> {
if x.is_empty() {
Ok(DummyKey)
} else {
Err("non empty dummy key")
}
}
}
impl MiniscriptKey for DummyKey {
type Hash = DummyKeyHash;
fn to_pubkeyhash(&self) -> Self::Hash {
DummyKeyHash
}
}
impl hash::Hash for DummyKey {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
"DummyKey".hash(state);
}
}
impl fmt::Display for DummyKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("")
}
}
impl ToPublicKey for DummyKey {
fn to_public_key(&self) -> bitcoin::PublicKey {
bitcoin::PublicKey::from_str(
"0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352",
)
.unwrap()
}
fn hash_to_hash160(_: &DummyKeyHash) -> hash160::Hash {
hash160::Hash::from_str("f54a5851e9372b87810a8e60cdd2e7cfd80b6e31").unwrap()
}
}
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)]
pub struct DummyKeyHash;
impl str::FromStr for DummyKeyHash {
type Err = &'static str;
fn from_str(x: &str) -> Result<DummyKeyHash, &'static str> {
if x.is_empty() {
Ok(DummyKeyHash)
} else {
Err("non empty dummy key")
}
}
}
impl fmt::Display for DummyKeyHash {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("")
}
}
impl hash::Hash for DummyKeyHash {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
"DummyKeyHash".hash(state);
}
}
pub trait TranslatePk<P: MiniscriptKey, Q: MiniscriptKey> {
type Output;
fn translate_pk<Fpk, Fpkh, E>(
&self,
translatefpk: Fpk,
translatefpkh: Fpkh,
) -> Result<Self::Output, E>
where
Fpk: FnMut(&P) -> Result<Q, E>,
Fpkh: FnMut(&P::Hash) -> Result<Q::Hash, E>;
fn translate_pk_infallible<Fpk, Fpkh>(
&self,
mut translatefpk: Fpk,
mut translatefpkh: Fpkh,
) -> Self::Output
where
Fpk: FnMut(&P) -> Q,
Fpkh: FnMut(&P::Hash) -> Q::Hash,
{
self.translate_pk::<_, _, ()>(|pk| Ok(translatefpk(pk)), |pkh| Ok(translatefpkh(pkh)))
.expect("infallible translation function")
}
}
pub trait TranslatePk1<P: MiniscriptKey, Q: MiniscriptKey<Hash = P::Hash>>:
TranslatePk<P, Q>
{
fn translate_pk1<Fpk, E>(
&self,
translatefpk: Fpk,
) -> Result<<Self as TranslatePk<P, Q>>::Output, E>
where
Fpk: FnMut(&P) -> Result<Q, E>,
{
self.translate_pk(translatefpk, |h| Ok(h.clone()))
}
fn translate_pk1_infallible<Fpk: FnMut(&P) -> Q>(
&self,
translatefpk: Fpk,
) -> <Self as TranslatePk<P, Q>>::Output {
self.translate_pk_infallible(translatefpk, P::Hash::clone)
}
}
impl<P: MiniscriptKey, Q: MiniscriptKey<Hash = P::Hash>, T: TranslatePk<P, Q>> TranslatePk1<P, Q>
for T
{
}
pub trait TranslatePk2<P: MiniscriptKey<Hash = P>, Q: MiniscriptKey>: TranslatePk<P, Q> {
fn translate_pk2<Fpk: Fn(&P) -> Result<Q, E>, E>(
&self,
translatefpk: Fpk,
) -> Result<<Self as TranslatePk<P, Q>>::Output, E> {
self.translate_pk(&translatefpk, |h| {
translatefpk(h).map(|q| q.to_pubkeyhash())
})
}
fn translate_pk2_infallible<Fpk: Fn(&P) -> Q>(
&self,
translatefpk: Fpk,
) -> <Self as TranslatePk<P, Q>>::Output {
self.translate_pk_infallible(&translatefpk, |h| translatefpk(h).to_pubkeyhash())
}
}
impl<P: MiniscriptKey<Hash = P>, Q: MiniscriptKey, T: TranslatePk<P, Q>> TranslatePk2<P, Q> for T {}
pub trait TranslatePk3<P: MiniscriptKey + ToPublicKey, Q: MiniscriptKey<Hash = hash160::Hash>>:
TranslatePk<P, Q>
{
fn translate_pk3<Fpk, E>(
&self,
translatefpk: Fpk,
) -> Result<<Self as TranslatePk<P, Q>>::Output, E>
where
Fpk: FnMut(&P) -> Result<Q, E>,
{
self.translate_pk(translatefpk, |h| Ok(P::hash_to_hash160(h)))
}
fn translate_pk3_infallible<Fpk: FnMut(&P) -> Q>(
&self,
translatefpk: Fpk,
) -> <Self as TranslatePk<P, Q>>::Output {
self.translate_pk_infallible(translatefpk, P::hash_to_hash160)
}
}
impl<
P: MiniscriptKey + ToPublicKey,
Q: MiniscriptKey<Hash = hash160::Hash>,
T: TranslatePk<P, Q>,
> TranslatePk3<P, Q> for T
{
}
pub enum ForEach<'a, Pk: MiniscriptKey + 'a> {
Key(&'a Pk),
Hash(&'a Pk::Hash),
}
impl<'a, Pk: MiniscriptKey<Hash = Pk>> ForEach<'a, Pk> {
pub fn as_key(&self) -> &'a Pk {
match *self {
ForEach::Key(ref_key) => ref_key,
ForEach::Hash(ref_key) => ref_key,
}
}
}
pub trait ForEachKey<Pk: MiniscriptKey> {
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool
where
Pk: 'a,
Pk::Hash: 'a;
fn for_any_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
where
Pk: 'a,
Pk::Hash: 'a,
{
!self.for_each_key(|key| !pred(key))
}
}
#[derive(Debug)]
pub enum Error {
InvalidOpcode(opcodes::All),
NonMinimalVerify(String),
InvalidPush(Vec<u8>),
Script(script::Error),
AddrError(bitcoin::util::address::Error),
CmsTooManyKeys(u32),
MultiATooManyKeys(u32),
Unprintable(u8),
ExpectedChar(char),
UnexpectedStart,
Unexpected(String),
MultiColon(String),
MultiAt(String),
AtOutsideOr(String),
LikelyFalse,
UnknownWrapper(char),
NonTopLevel(String),
Trailing(String),
BadPubkey(bitcoin::util::key::Error),
MissingHash(sha256::Hash),
MissingSig(bitcoin::PublicKey),
RelativeLocktimeNotMet(u32),
AbsoluteLocktimeNotMet(u32),
CouldNotSatisfy,
TypeCheck(String),
BadDescriptor(String),
Secp(bitcoin::secp256k1::Error),
#[cfg(feature = "compiler")]
CompilerError(policy::compiler::CompilerError),
PolicyError(policy::concrete::PolicyError),
LiftError(policy::LiftError),
ContextError(miniscript::context::ScriptContextError),
MaxRecursiveDepthExceeded,
ScriptSizeTooLarge,
NonStandardBareScript,
AnalysisError(miniscript::analyzable::AnalysisError),
ImpossibleSatisfaction,
BareDescriptorAddr,
PubKeyCtxError(miniscript::decode::KeyParseError, &'static str),
TaprootSpendInfoUnavialable,
TrNoScriptCode,
TrNoExplicitScript,
}
#[doc(hidden)]
impl<Pk, Ctx> From<miniscript::types::Error<Pk, Ctx>> for Error
where
Pk: MiniscriptKey,
Ctx: ScriptContext,
{
fn from(e: miniscript::types::Error<Pk, Ctx>) -> 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<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::util::address::Error> for Error {
fn from(e: bitcoin::util::address::Error) -> Error {
Error::AddrError(e)
}
}
fn errstr(s: &str) -> Error {
Error::Unexpected(s.to_owned())
}
impl error::Error for Error {
fn cause(&self) -> Option<&dyn error::Error> {
match *self {
Error::BadPubkey(ref e) => Some(e),
_ => None,
}
}
}
const MAX_RECURSION_DEPTH: u32 = 402;
const MAX_SCRIPT_SIZE: u32 = 10000;
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::InvalidOpcode(op) => write!(f, "invalid opcode {}", op),
Error::NonMinimalVerify(ref tok) => write!(f, "{} VERIFY", tok),
Error::InvalidPush(ref push) => write!(f, "invalid push {:?}", push), Error::Script(ref e) => fmt::Display::fmt(e, f),
Error::AddrError(ref e) => fmt::Display::fmt(e, f),
Error::CmsTooManyKeys(n) => write!(f, "checkmultisig with {} keys", n),
Error::Unprintable(x) => write!(f, "unprintable character 0x{:02x}", x),
Error::ExpectedChar(c) => write!(f, "expected {}", c),
Error::UnexpectedStart => f.write_str("unexpected start of script"),
Error::Unexpected(ref s) => write!(f, "unexpected «{}»", s),
Error::MultiColon(ref s) => write!(f, "«{}» has multiple instances of «:»", s),
Error::MultiAt(ref s) => write!(f, "«{}» has multiple instances of «@»", s),
Error::AtOutsideOr(ref s) => write!(f, "«{}» contains «@» in non-or() context", s),
Error::LikelyFalse => write!(f, "0 is not very likely (use «u:0»)"),
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::MissingHash(ref h) => write!(f, "missing preimage of hash {}", h),
Error::MissingSig(ref pk) => write!(f, "missing signature for key {:?}", pk),
Error::RelativeLocktimeNotMet(n) => {
write!(f, "required relative locktime CSV of {} blocks, not met", n)
}
Error::AbsoluteLocktimeNotMet(n) => write!(
f,
"required absolute locktime CLTV of {} blocks, not met",
n
),
Error::CouldNotSatisfy => f.write_str("could not satisfy"),
Error::BadPubkey(ref e) => fmt::Display::fmt(e, f),
Error::TypeCheck(ref e) => write!(f, "typecheck: {}", e),
Error::BadDescriptor(ref e) => write!(f, "Invalid descriptor: {}", e),
Error::Secp(ref e) => fmt::Display::fmt(e, f),
Error::ContextError(ref e) => fmt::Display::fmt(e, f),
#[cfg(feature = "compiler")]
Error::CompilerError(ref e) => fmt::Display::fmt(e, f),
Error::PolicyError(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::ScriptSizeTooLarge => write!(
f,
"Standardness rules imply bitcoin than {} bytes",
MAX_SCRIPT_SIZE
),
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::MultiATooManyKeys(k) => {
write!(f, "MultiA too many keys {}", k)
}
Error::TaprootSpendInfoUnavialable => {
write!(f, "Taproot Spend Info not computed. Hint: Did you call `compute_spend_info` before calling methods from DescriptorTrait")
}
Error::TrNoScriptCode => {
write!(f, "No script code for Tr descriptors")
}
Error::TrNoExplicitScript => {
write!(f, "No script code for Tr descriptors")
}
}
}
}
#[doc(hidden)]
#[cfg(feature = "compiler")]
impl From<policy::compiler::CompilerError> for Error {
fn from(e: policy::compiler::CompilerError) -> Error {
Error::CompilerError(e)
}
}
#[doc(hidden)]
impl From<policy::concrete::PolicyError> for Error {
fn from(e: policy::concrete::PolicyError) -> Error {
Error::PolicyError(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::Script {
let v: Vec<u8> = bitcoin::hashes::hex::FromHex::from_hex(s).unwrap();
bitcoin::Script::from(v)
}