From 6387350a09722bf578315e87771706f1b656bd87 Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 12:05:45 -0600 Subject: [PATCH 01/23] bitcoin 0.33: bump dependency versions Start of the 0.33 port. Prior attempt in PR #874 is preserved locally as branch pr-874. --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1a5f8d039..80cde86fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,15 +23,15 @@ base64 = ["bitcoin/base64"] [dependencies] bech32 = { version = "0.11.0", default-features = false, features = ["alloc"] } -bitcoin = { version = "0.32.6", default-features = false } +bitcoin = { version = "0.33.0-beta", default-features = false } hex = { package = "hex-conservative", default-features = false, features = ["alloc"], version = "1.0.0" } serde = { version = "1.0.103", optional = true } [dev-dependencies] serde_test = "1.0.147" -bitcoin = { version = "0.32.0", features = ["base64"] } -secp256k1 = {version = "0.29.0", features = ["rand-std"]} +bitcoin = { version = "0.33.0-beta", features = ["base64"] } +secp256k1 = { version = "0.32.0-beta.2", features = ["rand", "global-context"] } [[example]] name = "htlc" From 68b3d3b5d0f9a2c266acd15aa747e9ae6b72ee31 Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 13:18:03 -0600 Subject: [PATCH 02/23] bitcoin 0.33: migrate library to new API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrates the miniscript library (src/) to bitcoin 0.33.0-beta. The prior commit only bumped Cargo.toml; this commit ports every call site. Highlights: - Introduce crate-level aliases ScriptBuf, Script, ScriptBuilder bound to the new tagged ScriptPubKey variants, keeping the miniscript surface stable across the bitcoin 0.32/0.33 transition. - Hash256 newtype now also invokes impl_hex_for_newtype! and defines its own hash()/all_zeros() since bitcoin_hashes 0.20 no longer derives Display/Debug/FromStr from hash_newtype!. - Add MiniscriptKey and ToPublicKey impls for bitcoin::XOnlyPublicKey (distinct from secp256k1::XOnlyPublicKey in 0.33, now wraps + parity). - Script tagging: route scriptPubKey/witness/redeem/tap scripts through their tagged counterparts (ScriptPubKeyBuf, WitnessScriptBuf, RedeemScriptBuf, TapScriptBuf) and the corresponding *Ext traits for is_p2wsh/to_p2sh/etc. - Remove unused secp arguments from InnerXKey::xkey_fingerprint, SinglePriv::to_public, DescriptorXKey::to_public, DescriptorMultiXKey::to_public, DescriptorXKey::matches, DefiniteDescriptorKey::derive_public_key, Descriptor::derived_descriptor, Descriptor::find_derivation_index_for_spk — tracking the upstream bitcoin 0.33 change of dropping secp from bip32/key APIs. - Rewrite psbt GetKey impls for the new `fn get_key(&self, &KeyRequest)` trait signature and drop the KeySourceLookUp secp field. - Fix PublicKey field privacy (to_inner/compressed()), Transaction.inputs/ outputs, TxOut.amount, bip32 error renames, ecdsa::DecodeError, and misc moves (read_scriptint_non_minimal, MAX_SCRIPT_ELEMENT_SIZE in miniscript limits, Witness iter().rev().nth(1) for second_to_last). - TaprootMerkleBranch is now unsized; switch to TaprootMerkleBranchBuf. Library builds cleanly with no errors and no warnings under the default feature set. Examples, tests, and fuzz targets still need migration in follow-up commits. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/descriptor/bare.rs | 12 +-- src/descriptor/key.rs | 100 +++++++++----------- src/descriptor/key_map.rs | 32 +++---- src/descriptor/mod.rs | 36 +++---- src/descriptor/segwitv0.rs | 22 +++-- src/descriptor/sh.rs | 32 +++++-- src/descriptor/tr/mod.rs | 8 +- src/descriptor/tr/spend_info.rs | 81 +++++++++------- src/descriptor/tr/taptree.rs | 8 +- src/interpreter/error.rs | 19 ++-- src/interpreter/inner.rs | 154 ++++++++++++++++++------------ src/interpreter/mod.rs | 39 ++++---- src/interpreter/stack.rs | 7 +- src/lib.rs | 53 +++++++++-- src/miniscript/astelem.rs | 37 ++++---- src/miniscript/decode.rs | 7 +- src/miniscript/lex.rs | 40 +++++--- src/miniscript/mod.rs | 50 ++++++---- src/miniscript/satisfy.rs | 18 ++-- src/plan.rs | 61 ++++++++---- src/policy/compiler.rs | 13 +-- src/primitives/threshold.rs | 4 +- src/psbt/finalizer.rs | 91 ++++++++++++------ src/psbt/mod.rs | 160 ++++++++++++++++++++------------ src/test_utils.rs | 6 +- src/util.rs | 35 ++++--- 26 files changed, 680 insertions(+), 445 deletions(-) diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index b41ee2850..32f86b894 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -9,8 +9,8 @@ use core::fmt; -use bitcoin::script::{self, PushBytes}; -use bitcoin::{Address, Network, ScriptBuf, Weight}; +use bitcoin::script::PushBytes; +use bitcoin::{Address, Network, Weight}; use crate::descriptor::{write_descriptor, DefiniteDescriptorKey}; use crate::expression::{self, FromTree}; @@ -21,8 +21,8 @@ use crate::policy::{semantic, Liftable}; use crate::prelude::*; use crate::util::{varint_len, witness_to_scriptsig}; use crate::{ - BareCtx, Error, ForEachKey, FromStrKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey, - TranslateErr, Translator, + BareCtx, Error, ForEachKey, FromStrKey, Miniscript, MiniscriptKey, Satisfier, ScriptBuf, + ScriptBuilder, ToPublicKey, TranslateErr, Translator, }; /// Create a Bare Descriptor. That is descriptor that is @@ -293,12 +293,12 @@ impl Pkh { S: Satisfier, { if let Some(sig) = satisfier.lookup_ecdsa_sig(&self.pk) { - let script_sig = script::Builder::new() + let script_sig = ScriptBuilder::new() .push_slice::<&PushBytes>( // serialize() does not allocate here sig.serialize().as_ref(), ) - .push_key(&self.pk.to_public_key()) + .push_key(self.pk.to_public_key()) .into_script(); let witness = vec![]; Ok((witness, script_sig)) diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index ff856f89d..a6e7e6f57 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -6,10 +6,10 @@ use core::str::FromStr; #[cfg(feature = "std")] use std::error; -use bitcoin::bip32::{self, XKeyIdentifier}; -use bitcoin::hashes::{hash160, ripemd160, sha256, Hash, HashEngine}; +use bitcoin::bip32; +use bitcoin::hashes::{hash160, ripemd160, sha256, HashEngine}; use bitcoin::key::{PublicKey, XOnlyPublicKey}; -use bitcoin::secp256k1::{Secp256k1, Signing, Verification}; +use bitcoin::secp256k1::{Secp256k1, Signing}; use bitcoin::NetworkKind; use super::WalletPolicyError; @@ -167,7 +167,7 @@ impl fmt::Display for DescriptorSecretKey { /// handling of `bip32::Xpub` and `bip32::Xpriv`. pub trait InnerXKey: fmt::Display + FromStr { /// Returns the fingerprint of the key - fn xkey_fingerprint(&self, secp: &Secp256k1) -> bip32::Fingerprint; + fn xkey_fingerprint(&self) -> bip32::Fingerprint; /// Returns whether hardened steps can be derived on the key /// @@ -176,17 +176,13 @@ pub trait InnerXKey: fmt::Display + FromStr { } impl InnerXKey for bip32::Xpub { - fn xkey_fingerprint(&self, _secp: &Secp256k1) -> bip32::Fingerprint { - self.fingerprint() - } + fn xkey_fingerprint(&self) -> bip32::Fingerprint { self.fingerprint() } fn can_derive_hardened() -> bool { false } } impl InnerXKey for bip32::Xpriv { - fn xkey_fingerprint(&self, secp: &Secp256k1) -> bip32::Fingerprint { - self.fingerprint(secp) - } + fn xkey_fingerprint(&self) -> bip32::Fingerprint { self.fingerprint() } fn can_derive_hardened() -> bool { true } } @@ -214,8 +210,8 @@ impl fmt::Display for Wildcard { impl SinglePriv { /// Returns the public key of this key. - fn to_public(&self, secp: &Secp256k1) -> SinglePub { - let pub_key = self.key.public_key(secp); + fn to_public(&self) -> SinglePub { + let pub_key = self.key.public_key(); SinglePub { origin: self.origin.clone(), key: SinglePubKey::FullKey(pub_key) } } @@ -230,7 +226,7 @@ impl DescriptorXKey { /// added with this key's fingerprint and the derivation steps applied. fn to_public( &self, - secp: &Secp256k1, + _secp: &Secp256k1, ) -> Result, DescriptorKeyParseError> { let unhardened = self .derivation_path @@ -245,17 +241,17 @@ impl DescriptorXKey { let xprv = self .xkey - .derive_priv(secp, &hardened_path) + .derive_priv(hardened_path) .map_err(DescriptorKeyParseError::DeriveHardenedKey)?; - let xpub = bip32::Xpub::from_priv(secp, &xprv); + let xpub = bip32::Xpub::from_priv(&xprv); let origin = match &self.origin { Some((fingerprint, path)) => { Some((*fingerprint, path.into_iter().chain(hardened_path).copied().collect())) } None if !hardened_path.is_empty() => { - Some((self.xkey.fingerprint(secp), hardened_path.into())) + Some((self.xkey.fingerprint(), hardened_path.into())) } None => None, }; @@ -276,7 +272,7 @@ impl DescriptorMultiXKey { /// Errors if there are hardened derivation steps that are not shared among all paths. fn to_public( &self, - secp: &Secp256k1, + _secp: &Secp256k1, ) -> Result, DescriptorKeyParseError> { let deriv_paths = self.derivation_paths.paths(); @@ -320,16 +316,16 @@ impl DescriptorMultiXKey { let xprv = self .xkey - .derive_priv(secp, &hardened_path) + .derive_priv(hardened_path) .map_err(DescriptorKeyParseError::DeriveHardenedKey)?; - let xpub = bip32::Xpub::from_priv(secp, &xprv); + let xpub = bip32::Xpub::from_priv(&xprv); let origin = match &self.origin { Some((fingerprint, path)) => { Some((*fingerprint, path.into_iter().chain(hardened_path).copied().collect())) } None if !hardened_path.is_empty() => { - Some((self.xkey.fingerprint(secp), hardened_path.into())) + Some((self.xkey.fingerprint(), hardened_path.into())) } None => None, }; @@ -432,20 +428,20 @@ pub enum DescriptorKeyParseError { /// The invalid index index: String, /// The underlying parse error - err: bip32::Error, + err: bip32::ParseChildNumberError, }, /// Error deriving the hardened private key. - DeriveHardenedKey(bip32::Error), + DeriveHardenedKey(bip32::DerivationError), /// Error indicating the key data was malformed MalformedKeyData(MalformedKeyDataKind), /// Error while parsing the master derivation path. - MasterDerivationPath(bip32::Error), + MasterDerivationPath(bip32::ParseChildNumberError), /// Error indicating a malformed master fingerprint (invalid hex). MasterFingerprint { /// The invalid fingerprint fingerprint: String, - /// The underlying parse error - err: bitcoin::hex::HexToArrayError, + /// The underlying parse error (displayed as a string) + err: String, }, /// Attempt to construct a [`DefiniteDescriptorKey`] from an ambiguous key. NonDefiniteKey(NonDefiniteKeyError), @@ -453,8 +449,8 @@ pub enum DescriptorKeyParseError { FullPublicKey(bitcoin::key::ParsePublicKeyError), /// Error while parsing a WIF private key. WifPrivateKey(bitcoin::key::FromWifError), - /// Error while parsing an X-only public key (Secp256k1 error). - XonlyPublicKey(bitcoin::secp256k1::Error), + /// Error while parsing an X-only public key. + XonlyPublicKey(bitcoin::key::ParseXOnlyPublicKeyError), /// XKey parsing error XKeyParseError(XKeyParseError), } @@ -484,10 +480,10 @@ impl fmt::Display for DescriptorKeyParseError { impl error::Error for DescriptorKeyParseError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match self { - Self::DerivationIndexError { err, .. } - | Self::DeriveHardenedKey(err) - | Self::MasterDerivationPath(err) => Some(err), - Self::MasterFingerprint { err, .. } => Some(err), + Self::DerivationIndexError { err, .. } => Some(err), + Self::DeriveHardenedKey(err) => Some(err), + Self::MasterDerivationPath(err) => Some(err), + Self::MasterFingerprint { .. } => None, Self::NonDefiniteKey(err) => Some(err), Self::FullPublicKey(err) => Some(err), Self::WifPrivateKey(err) => Some(err), @@ -501,7 +497,7 @@ impl error::Error for DescriptorKeyParseError { /// An error when parsing an extended key. #[derive(Debug, PartialEq, Eq, Clone)] pub enum XKeyParseError { - Bip32(bip32::Error), + Bip32(bip32::ParseError), Bip388(WalletPolicyError), } @@ -524,8 +520,8 @@ impl fmt::Display for XKeyParseError { } } -impl From for XKeyParseError { - fn from(err: bip32::Error) -> Self { Self::Bip32(err) } +impl From for XKeyParseError { + fn from(err: bip32::ParseError) -> Self { Self::Bip32(err) } } impl fmt::Display for DescriptorPublicKey { @@ -570,7 +566,7 @@ impl DescriptorSecretKey { secp: &Secp256k1, ) -> Result { let pk = match self { - DescriptorSecretKey::Single(prv) => DescriptorPublicKey::Single(prv.to_public(secp)), + DescriptorSecretKey::Single(prv) => DescriptorPublicKey::Single(prv.to_public()), DescriptorSecretKey::XPrv(xprv) => DescriptorPublicKey::XPub(xprv.to_public(secp)?), DescriptorSecretKey::MultiXPrv(xprv) => { DescriptorPublicKey::MultiXPub(xprv.to_public(secp)?) @@ -759,15 +755,18 @@ impl DescriptorPublicKey { if let Some((fingerprint, _)) = single.origin { fingerprint } else { - let mut engine = XKeyIdentifier::engine(); + let mut engine = hash160::Hash::engine(); match single.key { SinglePubKey::FullKey(pk) => { pk.write_into(&mut engine).expect("engines don't error") } - SinglePubKey::XOnly(x_only_pk) => engine.input(&x_only_pk.serialize()), + SinglePubKey::XOnly(x_only_pk) => { + engine.input(&x_only_pk.serialize().0) + } }; + let hash = hash160::Hash::from_engine(engine); bip32::Fingerprint::from( - &XKeyIdentifier::from_engine(engine)[..4] + &hash.as_byte_array()[..4] .try_into() .expect("4 byte slice"), ) @@ -1059,12 +1058,12 @@ fn parse_key_origin(s: &str) -> Result<(&str, Option), Descrip let parent_fingerprint = bip32::Fingerprint::from_hex(origin_id_hex).map_err(|err| { DescriptorKeyParseError::MasterFingerprint { fingerprint: origin_id_hex.to_owned(), - err, + err: err.to_string(), } })?; let origin_path = raw_origin .map(bip32::ChildNumber::from_str) - .collect::>() + .collect::>() .map_err(DescriptorKeyParseError::MasterDerivationPath)?; let key = parts @@ -1248,11 +1247,7 @@ impl DescriptorXKey { /// # } /// # body().unwrap() /// ``` - pub fn matches( - &self, - keysource: &bip32::KeySource, - secp: &Secp256k1, - ) -> Option { + pub fn matches(&self, keysource: &bip32::KeySource) -> Option { let (fingerprint, path) = keysource; let (compare_fingerprint, compare_path) = match self.origin { @@ -1260,7 +1255,7 @@ impl DescriptorXKey { (fingerprint, path.into_iter().chain(&self.derivation_path).collect()) } None => ( - self.xkey.xkey_fingerprint(secp), + self.xkey.xkey_fingerprint(), self.derivation_path.into_iter().collect::>(), ), }; @@ -1323,7 +1318,7 @@ impl DefiniteDescriptorKey { /// /// Will return an error if the descriptor key has any hardened derivation steps in its path. To /// avoid this error you should replace any such public keys first with [`crate::Descriptor::translate_pk`]. - pub fn derive_public_key(&self, secp: &Secp256k1) -> bitcoin::PublicKey { + pub fn derive_public_key(&self) -> bitcoin::PublicKey { match self.0 { DescriptorPublicKey::Single(ref pk) => match pk.key { SinglePubKey::FullKey(pk) => pk, @@ -1333,9 +1328,9 @@ impl DefiniteDescriptorKey { Wildcard::Unhardened | Wildcard::Hardened => { unreachable!("impossible by construction of DefiniteDescriptorKey") } - Wildcard::None => match xpk.xkey.derive_pub(secp, &xpk.derivation_path.as_ref()) { - Ok(xpub) => bitcoin::PublicKey::new(xpub.public_key), - Err(bip32::Error::CannotDeriveFromHardenedKey) => { + Wildcard::None => match xpk.xkey.derive_pub(xpk.derivation_path.as_ref()) { + Ok(xpub) => bitcoin::PublicKey::from_secp(xpub.public_key), + Err(bip32::DerivationError::CannotDeriveHardenedChild) => { unreachable!("impossible by construction of DefiniteDescriptorKey") } Err(e) => unreachable!("cryptographically unreachable: {}", e), @@ -1410,10 +1405,7 @@ impl MiniscriptKey for DefiniteDescriptorKey { } impl ToPublicKey for DefiniteDescriptorKey { - fn to_public_key(&self) -> bitcoin::PublicKey { - let secp = Secp256k1::verification_only(); - self.derive_public_key(&secp) - } + fn to_public_key(&self) -> bitcoin::PublicKey { self.derive_public_key() } fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash } diff --git a/src/descriptor/key_map.rs b/src/descriptor/key_map.rs index 3e193ec87..942a3658e 100644 --- a/src/descriptor/key_map.rs +++ b/src/descriptor/key_map.rs @@ -81,16 +81,15 @@ impl iter::Extend<(DescriptorPublicKey, DescriptorSecretKey)> for KeyMap { impl GetKey for KeyMap { type Error = GetKeyError; - fn get_key( + fn get_key( &self, - key_request: KeyRequest, - secp: &Secp256k1, + key_request: &KeyRequest, ) -> Result, Self::Error> { Ok(self .map .iter() .find_map(|(_desc_pk, desc_sk)| -> Option { - match desc_sk.get_key(key_request.clone(), secp) { + match desc_sk.get_key(key_request) { Ok(Some(pk)) => Some(pk), // When looking up keys in a map, we eat errors on individual keys, on // the assumption that some other key in the map might not error. @@ -103,26 +102,25 @@ impl GetKey for KeyMap { impl GetKey for DescriptorSecretKey { type Error = GetKeyError; - fn get_key( + fn get_key( &self, - key_request: KeyRequest, - secp: &Secp256k1, + key_request: &KeyRequest, ) -> Result, Self::Error> { match (self, key_request) { (DescriptorSecretKey::Single(single_priv), key_request) => { let sk = single_priv.key; - let pk = sk.public_key(secp); + let pk = sk.public_key(); let pubkey_map = BTreeMap::from([(pk, sk)]); - pubkey_map.get_key(key_request, secp) + pubkey_map.get_key(key_request) } (DescriptorSecretKey::XPrv(descriptor_xkey), KeyRequest::Pubkey(public_key)) => { let xpriv = descriptor_xkey .xkey - .derive_priv(secp, &descriptor_xkey.derivation_path) + .derive_priv(&descriptor_xkey.derivation_path) .map_err(GetKeyError::Bip32)?; - let pk = xpriv.private_key.public_key(secp); + let pk = bitcoin::secp256k1::PublicKey::from_secret_key(&xpriv.private_key); - if public_key.inner.eq(&pk) { + if public_key.to_inner().eq(&pk) { Ok(Some(xpriv.to_priv())) } else { Ok(None) @@ -130,13 +128,13 @@ impl GetKey for DescriptorSecretKey { } ( DescriptorSecretKey::XPrv(descriptor_xkey), - ref key_request @ KeyRequest::Bip32(ref key_source), + KeyRequest::Bip32(key_source), ) => { - if let Some(key) = descriptor_xkey.xkey.get_key(key_request.clone(), secp)? { + if let Some(key) = descriptor_xkey.xkey.get_key(key_request)? { return Ok(Some(key)); } - if let Some(matched_path) = descriptor_xkey.matches(key_source, secp) { + if let Some(matched_path) = descriptor_xkey.matches(key_source) { let (_, full_path) = key_source; let derivation_path = &full_path[matched_path.len()..]; @@ -144,7 +142,7 @@ impl GetKey for DescriptorSecretKey { return Ok(Some( descriptor_xkey .xkey - .derive_priv(secp, &derivation_path) + .derive_priv(derivation_path) .map_err(GetKeyError::Bip32)? .to_priv(), )); @@ -161,7 +159,7 @@ impl GetKey for DescriptorSecretKey { ) => { for desc_sk in &desc_multi_sk.clone().into_single_keys() { // If any key is an error, then all of them will, so here we propagate errors with ?. - if let Some(pk) = desc_sk.get_key(key_request.clone(), secp)? { + if let Some(pk) = desc_sk.get_key(key_request)? { return Ok(Some(pk)); } } diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 2ad51c838..8125c158c 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -16,9 +16,7 @@ use core::ops::Range; use core::str::{self, FromStr}; use bitcoin::hashes::{hash160, ripemd160, sha256}; -use bitcoin::{ - secp256k1, Address, Network, Script, ScriptBuf, TxIn, Weight, Witness, WitnessVersion, -}; +use bitcoin::{secp256k1, Address, Network, TxIn, Weight, Witness, WitnessVersion}; use sync::Arc; use crate::expression::FromTree as _; @@ -29,7 +27,7 @@ use crate::plan::{AssetProvider, Plan}; use crate::prelude::*; use crate::{ expression, hash256, BareCtx, Error, ForEachKey, FromStrKey, MiniscriptKey, ParseError, - Satisfier, Threshold, ToPublicKey, TranslateErr, Translator, + Satisfier, Script, ScriptBuf, Threshold, ToPublicKey, TranslateErr, Translator, }; mod bare; @@ -547,7 +545,7 @@ impl Descriptor { { let (witness, script_sig) = self.get_satisfaction(satisfier)?; txin.witness = Witness::from_slice(&witness); - txin.script_sig = script_sig; + txin.script_sig = bitcoin::script::ScriptSigBuf::from(script_sig.into_bytes()); Ok(()) } } @@ -751,12 +749,11 @@ impl Descriptor { /// This function will return an error for multi-path descriptors /// or if hardened derivation is attempted, #[allow(deprecated)] - pub fn derived_descriptor( + pub fn derived_descriptor( &self, - secp: &secp256k1::Secp256k1, index: u32, ) -> Result, NonDefiniteKeyError> { - Ok(self.at_derivation_index(index)?.derived_descriptor(secp)) + Ok(self.at_derivation_index(index)?.derived_descriptor()) } /// Parse a descriptor that may contain secret keys @@ -887,14 +884,13 @@ impl Descriptor { /// descriptor at that index. If the descriptor is non-derivable then it will simply check the /// script pubkey against the descriptor and return it if it matches (in this case the index /// returned will be meaningless). - pub fn find_derivation_index_for_spk( + pub fn find_derivation_index_for_spk( &self, - secp: &secp256k1::Secp256k1, script_pubkey: &Script, range: Range, ) -> Result)>, NonDefiniteKeyError> { if !self.has_wildcard() { - let concrete = self.into_definite()?.derived_descriptor(secp); + let concrete = self.into_definite()?.derived_descriptor(); if &concrete.script_pubkey() == script_pubkey { return Ok(Some((0, concrete))); } @@ -902,7 +898,7 @@ impl Descriptor { } for i in range { - let concrete = self.derive_at_index(i)?.derived_descriptor(secp); + let concrete = self.derive_at_index(i)?.derived_descriptor(); if &concrete.script_pubkey() == script_pubkey { return Ok(Some((i, concrete))); } @@ -1031,34 +1027,30 @@ impl Descriptor { /// use std::str::FromStr; /// /// // test from bip 86 - /// let secp = secp256k1::Secp256k1::verification_only(); /// let descriptor = Descriptor::::from_str("tr(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)") /// .expect("Valid ranged descriptor"); - /// let result = descriptor.derive_at_index(0).unwrap().derived_descriptor(&secp); + /// let result = descriptor.derive_at_index(0).unwrap().derived_descriptor(); /// assert_eq!(result.to_string(), "tr(03cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115)#6qm9h8ym"); /// ``` /// /// # Errors /// /// This function will return an error if hardened derivation is attempted. - pub fn derived_descriptor( - &self, - secp: &secp256k1::Secp256k1, - ) -> Descriptor { - struct Derivator<'a, C: secp256k1::Verification>(&'a secp256k1::Secp256k1); + pub fn derived_descriptor(&self) -> Descriptor { + struct Derivator; - impl Translator for Derivator<'_, C> { + impl Translator for Derivator { type TargetPk = bitcoin::PublicKey; type Error = core::convert::Infallible; fn pk(&mut self, pk: &DefiniteDescriptorKey) -> Result { - Ok(pk.derive_public_key(self.0)) + Ok(pk.derive_public_key()) } translate_hash_clone!(DefiniteDescriptorKey); } - let derived = self.translate_pk(&mut Derivator(secp)); + let derived = self.translate_pk(&mut Derivator); match derived { Ok(derived) => derived, // Impossible to hit, since deriving keys does not change any Miniscript-relevant diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index b1398ba68..645e585bd 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -8,7 +8,8 @@ use core::convert::TryFrom; use core::fmt; -use bitcoin::{Address, Network, ScriptBuf, Weight}; +use bitcoin::script::{WitnessScriptBuf, WitnessScriptExt as _}; +use bitcoin::{Address, Network, Weight}; use crate::descriptor::{write_descriptor, DefiniteDescriptorKey}; use crate::expression::{self, FromTree}; @@ -20,8 +21,8 @@ use crate::policy::{semantic, Liftable}; use crate::prelude::*; use crate::util::varint_len; use crate::{ - Error, ForEachKey, FromStrKey, Miniscript, MiniscriptKey, Satisfier, Segwitv0, Terminal, - Threshold, ToPublicKey, TranslateErr, Translator, + Error, ForEachKey, FromStrKey, Miniscript, MiniscriptKey, Satisfier, ScriptBuf, Segwitv0, + Terminal, Threshold, ToPublicKey, TranslateErr, Translator, }; /// A Segwitv0 wsh descriptor #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] @@ -120,11 +121,18 @@ impl Wsh { impl Wsh { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { self.inner_script().to_p2wsh() } + pub fn script_pubkey(&self) -> ScriptBuf { + let witness_script = WitnessScriptBuf::from(self.inner_script().into_bytes()); + witness_script + .to_p2wsh() + .expect("witness script size within bounds") + } /// Obtains the corresponding script pubkey for this descriptor. pub fn address(&self, network: Network) -> Address { - Address::p2wsh(&self.ms.encode(), network) + let witness_script = WitnessScriptBuf::from(self.ms.encode().into_bytes()); + Address::p2wsh(&witness_script, network) + .expect("witness script size within bounds") } /// Obtains the underlying miniscript for this descriptor. @@ -311,7 +319,7 @@ impl Wpkh { let compressed = bitcoin::key::CompressedPublicKey::try_from(pk) .expect("wpkh descriptors have compressed keys"); - let addr = Address::p2wpkh(&compressed, Network::Bitcoin); + let addr = Address::p2wpkh(compressed, Network::Bitcoin); addr.script_pubkey() } @@ -321,7 +329,7 @@ impl Wpkh { let compressed = bitcoin::key::CompressedPublicKey::try_from(pk) .expect("Rust Miniscript types don't allow uncompressed pks in segwit descriptors"); - Address::p2wpkh(&compressed, network) + Address::p2wpkh(compressed, network) } /// Obtains the underlying miniscript for this descriptor. diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index 3c235b777..5de7fe34f 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -10,8 +10,10 @@ use core::convert::TryFrom; use core::fmt; -use bitcoin::script::PushBytes; -use bitcoin::{script, Address, Network, ScriptBuf, Weight}; +use bitcoin::script::{ + PushBytes, ScriptExt as _, WitnessScriptBuf, WitnessScriptExt as _, +}; +use bitcoin::{Address, Network, Weight}; use super::{Wpkh, Wsh}; use crate::descriptor::{write_descriptor, DefiniteDescriptorKey}; @@ -25,7 +27,7 @@ use crate::prelude::*; use crate::util::{varint_len, witness_to_scriptsig}; use crate::{ push_opcode_size, Error, ForEachKey, FromStrKey, Legacy, Miniscript, MiniscriptKey, Satisfier, - Segwitv0, Threshold, ToPublicKey, TranslateErr, Translator, + ScriptBuf, ScriptBuilder, Segwitv0, Threshold, ToPublicKey, TranslateErr, Translator, }; /// A Legacy p2sh Descriptor @@ -254,9 +256,18 @@ impl Sh { /// Obtains the corresponding script pubkey for this descriptor. pub fn script_pubkey(&self) -> ScriptBuf { match self.inner { - ShInner::Wsh(ref wsh) => wsh.script_pubkey().to_p2sh(), - ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey().to_p2sh(), - ShInner::Ms(ref ms) => ms.encode().to_p2sh(), + ShInner::Wsh(ref wsh) => wsh + .script_pubkey() + .to_p2sh() + .expect("redeem script within size bounds"), + ShInner::Wpkh(ref wpkh) => wpkh + .script_pubkey() + .to_p2sh() + .expect("redeem script within size bounds"), + ShInner::Ms(ref ms) => ms + .encode() + .to_p2sh() + .expect("redeem script within size bounds"), } } @@ -312,16 +323,19 @@ impl Sh { match self.inner { ShInner::Wsh(ref wsh) => { // wsh explicit must contain exactly 1 element - let witness_script = wsh.inner_script().to_p2wsh(); + let witness_script = + WitnessScriptBuf::from(wsh.inner_script().into_bytes()) + .to_p2wsh() + .expect("Witness script is not too large"); let push_bytes = <&PushBytes>::try_from(witness_script.as_bytes()) .expect("Witness script is not too large"); - script::Builder::new().push_slice(push_bytes).into_script() + ScriptBuilder::new().push_slice(push_bytes).into_script() } ShInner::Wpkh(ref wpkh) => { let redeem_script = wpkh.script_pubkey(); let push_bytes: &PushBytes = <&PushBytes>::try_from(redeem_script.as_bytes()).expect("Script not too large"); - script::Builder::new().push_slice(push_bytes).into_script() + ScriptBuilder::new().push_slice(push_bytes).into_script() } ShInner::Ms(..) => ScriptBuf::new(), } diff --git a/src/descriptor/tr/mod.rs b/src/descriptor/tr/mod.rs index 203e3cee2..fcb222ad7 100644 --- a/src/descriptor/tr/mod.rs +++ b/src/descriptor/tr/mod.rs @@ -3,7 +3,7 @@ use core::{cmp, fmt, hash}; use bitcoin::taproot::{TAPROOT_CONTROL_BASE_SIZE, TAPROOT_CONTROL_NODE_SIZE}; -use bitcoin::{opcodes, Address, Network, ScriptBuf, Weight}; +use bitcoin::{opcodes, Address, Network, Weight}; use sync::Arc; use super::checksum; @@ -17,8 +17,8 @@ use crate::policy::Liftable; use crate::prelude::*; use crate::util::{varint_len, witness_size}; use crate::{ - Error, ForEachKey, FromStrKey, MiniscriptKey, ParseError, Satisfier, ScriptContext, Tap, - Threshold, ToPublicKey, TranslateErr, Translator, + Error, ForEachKey, FromStrKey, MiniscriptKey, ParseError, Satisfier, ScriptBuf, ScriptBuilder, + ScriptContext, Tap, Threshold, ToPublicKey, TranslateErr, Translator, }; mod spend_info; @@ -269,7 +269,7 @@ impl Tr { /// Obtains the corresponding script pubkey for this descriptor. pub fn script_pubkey(&self) -> ScriptBuf { let output_key = self.spend_info().output_key(); - let builder = bitcoin::blockdata::script::Builder::new(); + let builder = ScriptBuilder::new(); builder .push_opcode(opcodes::all::OP_PUSHNUM_1) .push_slice(output_key.serialize()) diff --git a/src/descriptor/tr/spend_info.rs b/src/descriptor/tr/spend_info.rs index b0d23121d..2741d4283 100644 --- a/src/descriptor/tr/spend_info.rs +++ b/src/descriptor/tr/spend_info.rs @@ -7,14 +7,15 @@ //! use bitcoin::key::{Parity, TapTweak as _, TweakedPublicKey, UntweakedPublicKey}; -use bitcoin::secp256k1::Secp256k1; -use bitcoin::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash, TaprootMerkleBranch}; -use bitcoin::{Script, ScriptBuf}; +use bitcoin::script::{TapScript, TapScriptBuf}; +use bitcoin::taproot::{ + ControlBlock, LeafVersion, TapLeafHash, TapNodeHash, TaprootMerkleBranchBuf, +}; use crate::miniscript::context::Tap; use crate::prelude::Vec; use crate::sync::Arc; -use crate::{Miniscript, MiniscriptKey, ToPublicKey}; +use crate::{Miniscript, MiniscriptKey, Script, ScriptBuf, ToPublicKey}; /// Utility structure which maintains a stack of bits (at most 128) using a u128. /// @@ -68,7 +69,8 @@ impl TrSpendInfo { let depth = usize::from(leaf.depth()); let script = leaf.miniscript().encode(); - let leaf_hash = TapLeafHash::from_script(&script, leaf.leaf_version()); + let leaf_hash = + TapLeafHash::from_script(TapScript::from_bytes(script.as_bytes()), leaf.leaf_version()); let mut current_hash = TapNodeHash::from(leaf_hash); // 1. If this node increases our depth, add parents. @@ -138,16 +140,17 @@ impl TrSpendInfo { /// Constructs a [`TrSpendInfo`] for a [`super::Tr`]. pub fn from_tr(tr: &super::Tr) -> Self { - let internal_key = tr.internal_key().to_x_only_pubkey(); + let internal_key: UntweakedPublicKey = + bitcoin::XOnlyPublicKey::from(tr.internal_key().to_x_only_pubkey()); let nodes = match tr.tap_tree() { Some(tree) => Self::nodes_from_tap_tree(tree), None => vec![], }; - let secp = Secp256k1::verification_only(); - let (output_key, output_key_parity) = - internal_key.tap_tweak(&secp, nodes.first().map(|node| node.sibling_hash)); + let output_key = + internal_key.tap_tweak(nodes.first().map(|node| node.sibling_hash)); + let output_key_parity = output_key.as_x_only_public_key().parity(); TrSpendInfo { internal_key, output_key, output_key_parity, nodes } } @@ -204,7 +207,7 @@ impl TrSpendInfo { builder = builder .add_leaf_with_ver( leaf.depth(), - ScriptBuf::from(leaf.script()), + TapScriptBuf::from(leaf.script().to_vec()), leaf.leaf_version(), ) .expect("iterating through tree in correct DFS order") @@ -280,7 +283,7 @@ impl<'sp, Pk: MiniscriptKey> Iterator for TrSpendInfoIter<'sp, Pk> { leaf_version: LeafVersion::TapScript, output_key_parity: self.spend_info.output_key_parity, internal_key: self.spend_info.internal_key, - merkle_branch: TaprootMerkleBranch::try_from(merkle_stack) + merkle_branch: TaprootMerkleBranchBuf::try_from(merkle_stack) .expect("merkle stack guaranteed to be within allowable length"), }, }); @@ -369,11 +372,10 @@ mod tests { #[derive(PartialEq, Eq, Debug)] struct ExpectedLeaf { leaf_hash: TapLeafHash, - branch: TaprootMerkleBranch, + branch: TaprootMerkleBranchBuf, } fn test_cases() -> Vec<(String, ExpectedTree, Vec)> { - let secp = Secp256k1::verification_only(); let pk = "03cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115" .parse::() .unwrap(); @@ -392,7 +394,8 @@ mod tests { // Empty tree let merkle_root = None; let internal_key = pk.to_x_only_pubkey(); - let (output_key, output_key_parity) = internal_key.tap_tweak(&secp, merkle_root); + let output_key = internal_key.tap_tweak(merkle_root); + let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( format!("tr({pk})"), ExpectedTree { internal_key, output_key, output_key_parity, merkle_root }, @@ -402,13 +405,14 @@ mod tests { // Single-leaf tree let merkle_root = Some(TapNodeHash::from(zero_hash)); let internal_key = pk.to_x_only_pubkey(); - let (output_key, output_key_parity) = internal_key.tap_tweak(&secp, merkle_root); + let output_key = internal_key.tap_tweak(merkle_root); + let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( format!("tr({pk},0)"), ExpectedTree { internal_key, output_key, output_key_parity, merkle_root }, vec![ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![]).unwrap(), + branch: TaprootMerkleBranchBuf::try_from(vec![]).unwrap(), }], )); @@ -419,19 +423,20 @@ mod tests { .unwrap(), ); let internal_key = pk.to_x_only_pubkey(); - let (output_key, output_key_parity) = internal_key.tap_tweak(&secp, merkle_root); + let output_key = internal_key.tap_tweak(merkle_root); + let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( format!("tr({pk},{{0,0}})"), ExpectedTree { internal_key, output_key, output_key_parity, merkle_root }, vec![ ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![TapNodeHash::from(zero_hash)]) + branch: TaprootMerkleBranchBuf::try_from(vec![TapNodeHash::from(zero_hash)]) .unwrap(), }, ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![TapNodeHash::from(zero_hash)]) + branch: TaprootMerkleBranchBuf::try_from(vec![TapNodeHash::from(zero_hash)]) .unwrap(), }, ], @@ -444,19 +449,20 @@ mod tests { .unwrap(), ); let internal_key = pk.to_x_only_pubkey(); - let (output_key, output_key_parity) = internal_key.tap_tweak(&secp, merkle_root); + let output_key = internal_key.tap_tweak(merkle_root); + let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( format!("tr({pk},{{0,1}})"), ExpectedTree { internal_key, output_key, output_key_parity, merkle_root }, vec![ ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![TapNodeHash::from(one_hash)]) + branch: TaprootMerkleBranchBuf::try_from(vec![TapNodeHash::from(one_hash)]) .unwrap(), }, ExpectedLeaf { leaf_hash: one_hash, - branch: TaprootMerkleBranch::try_from(vec![TapNodeHash::from(zero_hash)]) + branch: TaprootMerkleBranchBuf::try_from(vec![TapNodeHash::from(zero_hash)]) .unwrap(), }, ], @@ -469,7 +475,8 @@ mod tests { .unwrap(), ); let internal_key = pk.to_x_only_pubkey(); - let (output_key, output_key_parity) = internal_key.tap_tweak(&secp, merkle_root); + let output_key = internal_key.tap_tweak(merkle_root); + let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( format!("tr({pk},{{0,{{0,tv:0}}}})"), @@ -477,7 +484,7 @@ mod tests { vec![ ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "573d619569d58a36b52187e56f168650ac17f66a9a3afaf054900a04001019b3" .parse::() .unwrap(), @@ -486,7 +493,7 @@ mod tests { }, ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "64ac241466a5e7032586718ff7465716f77a88d89946ce472daa4c3d0b81148f" .parse::() .unwrap(), @@ -498,7 +505,7 @@ mod tests { leaf_hash: "64ac241466a5e7032586718ff7465716f77a88d89946ce472daa4c3d0b81148f" .parse() .unwrap(), - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ TapNodeHash::from(zero_hash), TapNodeHash::from(zero_hash), ]) @@ -514,7 +521,8 @@ mod tests { .unwrap(), ); let internal_key = pk.to_x_only_pubkey(); - let (output_key, output_key_parity) = internal_key.tap_tweak(&secp, merkle_root); + let output_key = internal_key.tap_tweak(merkle_root); + let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( format!("tr({pk},{{uuu:0,{{0,uu:0}}}})"), @@ -524,7 +532,7 @@ mod tests { leaf_hash: "6498e1d56640a272493d1d87549f3347dc448ca674556a2110cdfe100e3c238b" .parse() .unwrap(), - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "7e3e98bab404812c8eebd21c5d825527676b8e9f261f7ad479f3a08a83a43fb4" .parse::() .unwrap(), @@ -533,7 +541,7 @@ mod tests { }, ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "19417c32bc6ca7e0f6e65b006ac305107c6add73c8bef31181037e6faaa55e7f" .parse::() .unwrap(), @@ -547,7 +555,7 @@ mod tests { leaf_hash: "19417c32bc6ca7e0f6e65b006ac305107c6add73c8bef31181037e6faaa55e7f" .parse() .unwrap(), - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ TapNodeHash::from(zero_hash), "6498e1d56640a272493d1d87549f3347dc448ca674556a2110cdfe100e3c238b" .parse::() @@ -565,7 +573,8 @@ mod tests { .unwrap(), ); let internal_key = pk.to_x_only_pubkey(); - let (output_key, output_key_parity) = internal_key.tap_tweak(&secp, merkle_root); + let output_key = internal_key.tap_tweak(merkle_root); + let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( format!("tr({pk},{{{{0,{{uuu:0,0}}}},{{0,uu:0}}}})"), @@ -573,7 +582,7 @@ mod tests { vec![ ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "57e3b7d414075ff4864deec9efa99db4462c038706306e02c58e02e957c8a51e" .parse::() .unwrap(), @@ -587,7 +596,7 @@ mod tests { leaf_hash: "6498e1d56640a272493d1d87549f3347dc448ca674556a2110cdfe100e3c238b" .parse() .unwrap(), - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ TapNodeHash::from(zero_hash), TapNodeHash::from(zero_hash), "7e3e98bab404812c8eebd21c5d825527676b8e9f261f7ad479f3a08a83a43fb4" @@ -598,7 +607,7 @@ mod tests { }, ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "6498e1d56640a272493d1d87549f3347dc448ca674556a2110cdfe100e3c238b" .parse::() .unwrap(), @@ -611,7 +620,7 @@ mod tests { }, ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "19417c32bc6ca7e0f6e65b006ac305107c6add73c8bef31181037e6faaa55e7f" .parse::() .unwrap(), @@ -625,7 +634,7 @@ mod tests { leaf_hash: "19417c32bc6ca7e0f6e65b006ac305107c6add73c8bef31181037e6faaa55e7f" .parse() .unwrap(), - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ TapNodeHash::from(zero_hash), "e034d7d8b221034861bf3893c63cb0ff60d28a7a00090d0dc57c26fec91983cb" .parse::() diff --git a/src/descriptor/tr/taptree.rs b/src/descriptor/tr/taptree.rs index 27e860390..0b0a4034d 100644 --- a/src/descriptor/tr/taptree.rs +++ b/src/descriptor/tr/taptree.rs @@ -216,7 +216,7 @@ impl TapTreeIterItem<'_, Pk> { /// all (or many) of the leaves of the tree, you may instead want to call /// [`super::Tr::spend_info`] and use the [`super::TrSpendInfo::leaves`] iterator instead. #[inline] - pub fn compute_script(&self) -> bitcoin::ScriptBuf { self.node.encode() } + pub fn compute_script(&self) -> crate::ScriptBuf { self.node.encode() } /// Computes the [`TapLeafHash`] of the leaf. /// @@ -226,7 +226,11 @@ impl TapTreeIterItem<'_, Pk> { /// [`super::Tr::spend_info`] and use the [`super::TrSpendInfo::leaves`] iterator instead. #[inline] pub fn compute_tap_leaf_hash(&self) -> TapLeafHash { - TapLeafHash::from_script(&self.compute_script(), self.leaf_version()) + let script = self.compute_script(); + TapLeafHash::from_script( + bitcoin::script::TapScript::from_bytes(script.as_bytes()), + self.leaf_version(), + ) } } diff --git a/src/interpreter/error.rs b/src/interpreter/error.rs index 4e47932a6..e47059f11 100644 --- a/src/interpreter/error.rs +++ b/src/interpreter/error.rs @@ -6,7 +6,6 @@ use core::fmt; use std::error; use bitcoin::hashes::hash160; -use bitcoin::hex::DisplayHex; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 use bitcoin::secp256k1; use bitcoin::{absolute, relative, taproot}; @@ -33,7 +32,7 @@ pub enum Error { /// General Interpreter error. CouldNotEvaluate, /// ECDSA Signature related error - EcdsaSig(bitcoin::ecdsa::Error), + EcdsaSig(bitcoin::ecdsa::DecodeError), /// We expected a push (including a `OP_1` but no other numeric pushes) ExpectedPush, /// The preimage to the hash function must be exactly 32 bytes. @@ -143,12 +142,20 @@ impl fmt::Display for Error { Error::IncorrectWScriptHash => f.write_str("witness script did not match scriptpubkey"), Error::InsufficientSignaturesMultiSig => f.write_str("Insufficient signatures for CMS"), Error::InvalidSchnorrSighashType(ref sig) => { - write!(f, "Invalid sighash type for schnorr signature '{:x}'", sig.as_hex()) + write!(f, "Invalid sighash type for schnorr signature '")?; + for b in sig { + write!(f, "{:02x}", b)?; + } + write!(f, "'") } Error::InvalidEcdsaSignature(pk) => write!(f, "bad ecdsa signature with pk {}", pk), Error::InvalidSchnorrSignature(pk) => write!(f, "bad schnorr signature with pk {}", pk), Error::NonStandardSighash(ref sig) => { - write!(f, "Non standard sighash type for signature '{:x}'", sig.as_hex()) + write!(f, "Non standard sighash type for signature '")?; + for b in sig { + write!(f, "{:02x}", b)?; + } + write!(f, "'") } Error::NonEmptyWitness => f.write_str("legacy spend had nonempty witness"), Error::NonEmptyScriptSig => f.write_str("segwit spend had nonempty scriptsig"), @@ -247,8 +254,8 @@ impl From for Error { } #[doc(hidden)] -impl From for Error { - fn from(e: bitcoin::ecdsa::Error) -> Error { Error::EcdsaSig(e) } +impl From for Error { + fn from(e: bitcoin::ecdsa::DecodeError) -> Error { Error::EcdsaSig(e) } } #[doc(hidden)] diff --git a/src/interpreter/inner.rs b/src/interpreter/inner.rs index b65e26a7f..45213dee0 100644 --- a/src/interpreter/inner.rs +++ b/src/interpreter/inner.rs @@ -1,7 +1,12 @@ // Written in 2019 by Sanket Kanjular and Andrew Poelstra // SPDX-License-Identifier: CC0-1.0 -use bitcoin::hashes::{hash160, sha256, Hash}; +use bitcoin::hashes::{hash160, sha256}; +use bitcoin::key::{PubkeyHash, WPubkeyHash}; +use bitcoin::script::{ + ScriptBufExt as _, ScriptExt as _, ScriptHash, ScriptPubKeyBufExt as _, + ScriptPubKeyExt as _, WScriptHash, +}; use bitcoin::taproot::{ControlBlock, TAPROOT_ANNEX_PREFIX}; use bitcoin::Witness; @@ -14,7 +19,7 @@ use crate::{BareCtx, Legacy, Miniscript, Segwitv0, Tap, ToPublicKey, Translator} /// if asked to, but otherwise dropping it fn pk_from_slice(slice: &[u8], require_compressed: bool) -> Result { if let Ok(pk) = bitcoin::PublicKey::from_slice(slice) { - if require_compressed && !pk.compressed { + if require_compressed && !pk.compressed() { Err(Error::UncompressedPubkey) } else { Ok(pk) @@ -43,7 +48,7 @@ fn script_from_stack_elem( ) -> Result, Error> { match *elem { stack::Element::Push(sl) => { - Miniscript::decode_consensus(bitcoin::Script::from_bytes(sl)).map_err(Error::from) + Miniscript::decode_consensus(crate::Script::from_bytes(sl)).map_err(Error::from) } stack::Element::Satisfied => Ok(Miniscript::TRUE), stack::Element::Dissatisfied => Ok(Miniscript::FALSE), @@ -91,10 +96,10 @@ pub(super) enum Inner { /// Tr outputs don't have script code and return None. #[allow(clippy::collapsible_else_if)] pub(super) fn from_txdata<'txin>( - spk: &bitcoin::Script, - script_sig: &'txin bitcoin::Script, + spk: &crate::Script, + script_sig: &'txin crate::Script, witness: &'txin Witness, -) -> Result<(Inner, Stack<'txin>, Option), Error> { +) -> Result<(Inner, Stack<'txin>, Option), Error> { let mut ssig_stack: Stack = script_sig .instructions_minimal() .map(stack::Element::from_instruction) @@ -129,7 +134,9 @@ pub(super) fn from_txdata<'txin>( Some(elem) => { let pk = pk_from_stack_elem(&elem, false)?; if *spk - == bitcoin::ScriptBuf::new_p2pkh(&pk.to_pubkeyhash(SigType::Ecdsa).into()) + == crate::ScriptBuf::new_p2pkh(PubkeyHash::from_byte_array( + pk.to_pubkeyhash(SigType::Ecdsa).to_byte_array(), + )) { Ok(( Inner::PublicKey(pk.into(), PubkeyType::Pkh), @@ -152,11 +159,11 @@ pub(super) fn from_txdata<'txin>( Some(elem) => { let pk = pk_from_stack_elem(&elem, true)?; let hash160 = pk.to_pubkeyhash(SigType::Ecdsa); - if *spk == bitcoin::ScriptBuf::new_p2wpkh(&hash160.into()) { + if *spk == crate::ScriptBuf::new_p2wpkh(WPubkeyHash::from_byte_array(hash160.to_byte_array())) { Ok(( Inner::PublicKey(pk.into(), PubkeyType::Wpkh), wit_stack, - Some(bitcoin::ScriptBuf::new_p2pkh(&hash160.into())), // bip143, why.. + Some(crate::ScriptBuf::new_p2pkh(PubkeyHash::from_byte_array(hash160.to_byte_array()))), // bip143, why.. )) } else { Err(Error::IncorrectWPubkeyHash) @@ -176,7 +183,7 @@ pub(super) fn from_txdata<'txin>( let script = miniscript.encode(); let miniscript = miniscript.to_no_checks_ms(); let scripthash = sha256::Hash::hash(script.as_bytes()); - if *spk == bitcoin::ScriptBuf::new_p2wsh(&scripthash.into()) { + if *spk == crate::ScriptBuf::new_p2wsh(WScriptHash::from_byte_array(scripthash.to_byte_array())) { Ok((Inner::Script(miniscript, ScriptType::Wsh), wit_stack, Some(script))) } else { Err(Error::IncorrectWScriptHash) @@ -190,8 +197,12 @@ pub(super) fn from_txdata<'txin>( if !ssig_stack.is_empty() { Err(Error::NonEmptyScriptSig) } else { - let output_key = bitcoin::key::XOnlyPublicKey::from_slice(spk[2..].as_bytes()) - .map_err(|_| Error::XOnlyPublicKeyParseError)?; + let output_key = { + let arr = <[u8; 32]>::try_from(spk[2..].as_bytes()) + .map_err(|_| Error::XOnlyPublicKeyParseError)?; + bitcoin::key::XOnlyPublicKey::from_byte_array(&arr) + .map_err(|_| Error::XOnlyPublicKeyParseError)? + }; let has_annex = wit_stack .last() .and_then(|x| x.as_push().ok()) @@ -220,10 +231,10 @@ pub(super) fn from_txdata<'txin>( ControlBlock::decode(ctrl_blk).map_err(Error::ControlBlockParse)?; let tap_script = script_from_stack_elem::(&tap_script)?; let ms = tap_script.to_no_checks_ms(); - // Creating new contexts is cheap - let secp = bitcoin::secp256k1::Secp256k1::verification_only(); let tap_script = tap_script.encode(); - if ctrl_blk.verify_taproot_commitment(&secp, output_key, &tap_script) { + let tap_script_tagged = + bitcoin::script::TapScript::from_bytes(tap_script.as_bytes()); + if ctrl_blk.verify_taproot_commitment(output_key, tap_script_tagged) { Ok(( Inner::Script(ms, ScriptType::Tr), wit_stack, @@ -247,7 +258,7 @@ pub(super) fn from_txdata<'txin>( Some(elem) => { if let stack::Element::Push(slice) = elem { let scripthash = hash160::Hash::hash(slice); - if *spk != bitcoin::ScriptBuf::new_p2sh(&scripthash.into()) { + if *spk != crate::ScriptBuf::new_p2sh(ScriptHash::from_byte_array(scripthash.to_byte_array())) { return Err(Error::IncorrectScriptHash); } // ** p2sh-wrapped wpkh ** @@ -260,13 +271,13 @@ pub(super) fn from_txdata<'txin>( let pk = pk_from_stack_elem(&elem, true)?; let hash160 = pk.to_pubkeyhash(SigType::Ecdsa); if slice - == bitcoin::ScriptBuf::new_p2wpkh(&hash160.into()) + == crate::ScriptBuf::new_p2wpkh(WPubkeyHash::from_byte_array(hash160.to_byte_array())) .as_bytes() { Ok(( Inner::PublicKey(pk.into(), PubkeyType::ShWpkh), wit_stack, - Some(bitcoin::ScriptBuf::new_p2pkh(&hash160.into())), // bip143, why.. + Some(crate::ScriptBuf::new_p2pkh(PubkeyHash::from_byte_array(hash160.to_byte_array()))), // bip143, why.. )) } else { Err(Error::IncorrectWScriptHash) @@ -288,7 +299,7 @@ pub(super) fn from_txdata<'txin>( let miniscript = miniscript.to_no_checks_ms(); let scripthash = sha256::Hash::hash(script.as_bytes()); if slice - == bitcoin::ScriptBuf::new_p2wsh(&scripthash.into()) + == crate::ScriptBuf::new_p2wsh(WScriptHash::from_byte_array(scripthash.to_byte_array())) .as_bytes() { Ok(( @@ -311,7 +322,7 @@ pub(super) fn from_txdata<'txin>( let miniscript = miniscript.to_no_checks_ms(); if wit_stack.is_empty() { let scripthash = hash160::Hash::hash(script.as_bytes()); - if *spk == bitcoin::ScriptBuf::new_p2sh(&scripthash.into()) { + if *spk == crate::ScriptBuf::new_p2sh(ScriptHash::from_byte_array(scripthash.to_byte_array())) { Ok((Inner::Script(miniscript, ScriptType::Sh), ssig_stack, Some(script))) } else { Err(Error::IncorrectScriptHash) @@ -387,30 +398,51 @@ impl ToNoChecks for Miniscript ToNoChecks for Miniscript { + fn to_no_checks_ms(&self) -> Miniscript { + struct TranslateSecpXOnlyPk; + + impl Translator for TranslateSecpXOnlyPk { + type TargetPk = BitcoinKey; + type Error = core::convert::Infallible; + + fn pk( + &mut self, + pk: &bitcoin::secp256k1::XOnlyPublicKey, + ) -> Result { + Ok(BitcoinKey::XOnlyPublicKey(bitcoin::key::XOnlyPublicKey::from(*pk))) + } + + translate_hash_clone!(bitcoin::secp256k1::XOnlyPublicKey); + } + self.translate_pk_ctx(&mut TranslateSecpXOnlyPk) + .expect("Translation should succeed") + } +} + #[cfg(test)] mod tests { use core::convert::TryFrom; use core::str::FromStr; - use bitcoin::blockdata::script; use bitcoin::script::PushBytes; - use bitcoin::ScriptBuf; use hex; use super::*; + use crate::{ScriptBuf, ScriptBuilder as ScriptBuilderLocal}; struct KeyTestData { - pk_spk: bitcoin::ScriptBuf, - pk_sig: bitcoin::ScriptBuf, - pkh_spk: bitcoin::ScriptBuf, - pkh_sig: bitcoin::ScriptBuf, - pkh_sig_justkey: bitcoin::ScriptBuf, - wpkh_spk: bitcoin::ScriptBuf, + pk_spk: ScriptBuf, + pk_sig: ScriptBuf, + pkh_spk: ScriptBuf, + pkh_sig: ScriptBuf, + pkh_sig_justkey: ScriptBuf, + wpkh_spk: ScriptBuf, wpkh_stack: Witness, wpkh_stack_justkey: Witness, - sh_wpkh_spk: bitcoin::ScriptBuf, - sh_wpkh_sig: bitcoin::ScriptBuf, + sh_wpkh_spk: ScriptBuf, + sh_wpkh_sig: ScriptBuf, sh_wpkh_stack: Witness, sh_wpkh_stack_justkey: Witness, } @@ -429,23 +461,23 @@ mod tests { let pkhash = key.to_pubkeyhash(SigType::Ecdsa).into(); let wpkhash = key.to_pubkeyhash(SigType::Ecdsa).into(); - let wpkh_spk = bitcoin::ScriptBuf::new_p2wpkh(&wpkhash); + let wpkh_spk = ScriptBuf::new_p2wpkh(wpkhash); let wpkh_scripthash = hash160::Hash::hash(wpkh_spk.as_bytes()).into(); KeyTestData { - pk_spk: bitcoin::ScriptBuf::new_p2pk(&key), - pkh_spk: bitcoin::ScriptBuf::new_p2pkh(&pkhash), - pk_sig: script::Builder::new().push_slice(dummy_sig).into_script(), - pkh_sig: script::Builder::new() + pk_spk: ScriptBuf::new_p2pk(key), + pkh_spk: ScriptBuf::new_p2pkh(pkhash), + pk_sig: ScriptBuilderLocal::new().push_slice(dummy_sig).into_script(), + pkh_sig: ScriptBuilderLocal::new() .push_slice(dummy_sig) - .push_key(&key) + .push_key(key) .into_script(), - pkh_sig_justkey: script::Builder::new().push_key(&key).into_script(), + pkh_sig_justkey: ScriptBuilderLocal::new().push_key(key).into_script(), wpkh_spk: wpkh_spk.clone(), wpkh_stack: Witness::from_slice(&[dummy_sig_vec.clone(), key.to_bytes()]), wpkh_stack_justkey: Witness::from_slice(&[key.to_bytes()]), - sh_wpkh_spk: bitcoin::ScriptBuf::new_p2sh(&wpkh_scripthash), - sh_wpkh_sig: script::Builder::new() + sh_wpkh_spk: ScriptBuf::new_p2sh(wpkh_scripthash), + sh_wpkh_sig: ScriptBuilderLocal::new() .push_slice(<&PushBytes>::try_from(wpkh_spk[..].as_bytes()).unwrap()) .into_script(), sh_wpkh_stack: Witness::from_slice(&[dummy_sig_vec, key.to_bytes()]), @@ -482,7 +514,7 @@ mod tests { let fixed = fixed_test_data(); let comp = KeyTestData::from_key(fixed.pk_comp); let uncomp = KeyTestData::from_key(fixed.pk_uncomp); - let blank_script = bitcoin::ScriptBuf::new(); + let blank_script = ScriptBuf::new(); let empty_wit = Witness::default(); // Compressed pk, empty scriptsig @@ -516,15 +548,15 @@ mod tests { // Scriptpubkey has invalid key let mut spk = comp.pk_spk.to_bytes(); spk[1] = 5; - let spk = bitcoin::ScriptBuf::from(spk); - let err = from_txdata(&spk, &bitcoin::ScriptBuf::new(), &empty_wit).unwrap_err(); + let spk = ScriptBuf::from(spk); + let err = from_txdata(&spk, &ScriptBuf::new(), &empty_wit).unwrap_err(); assert_eq!(err.to_string(), "could not parse pubkey"); // Scriptpubkey has invalid script let mut spk = comp.pk_spk.to_bytes(); spk[0] = 100; - let spk = bitcoin::ScriptBuf::from(spk); - let err = from_txdata(&spk, &bitcoin::ScriptBuf::new(), &empty_wit).unwrap_err(); + let spk = ScriptBuf::from(spk); + let err = from_txdata(&spk, &ScriptBuf::new(), &empty_wit).unwrap_err(); assert_eq!(&err.to_string()[0..12], "parse error:"); // Witness is nonempty @@ -541,7 +573,7 @@ mod tests { let empty_wit = Witness::default(); // pkh, empty scriptsig; this time it errors out - let err = from_txdata(&comp.pkh_spk, &bitcoin::ScriptBuf::new(), &empty_wit).unwrap_err(); + let err = from_txdata(&comp.pkh_spk, &ScriptBuf::new(), &empty_wit).unwrap_err(); assert_eq!(err.to_string(), "unexpected end of stack"); // pkh, wrong pubkey @@ -587,7 +619,7 @@ mod tests { let fixed = fixed_test_data(); let comp = KeyTestData::from_key(fixed.pk_comp); let uncomp = KeyTestData::from_key(fixed.pk_uncomp); - let blank_script = bitcoin::ScriptBuf::new(); + let blank_script = ScriptBuf::new(); // wpkh, empty witness; this time it errors out let err = from_txdata(&comp.wpkh_spk, &blank_script, &Witness::default()).unwrap_err(); @@ -615,7 +647,7 @@ mod tests { let (inner, stack, script_code) = from_txdata(&comp.wpkh_spk, &blank_script, &comp.wpkh_stack).expect("parse txdata"); assert_eq!(inner, Inner::PublicKey(fixed.pk_comp.into(), PubkeyType::Wpkh)); - assert_eq!(stack, Stack::from(vec![comp.wpkh_stack.second_to_last().unwrap().into()])); + assert_eq!(stack, Stack::from(vec![comp.wpkh_stack.iter().rev().nth(1).unwrap().into()])); assert_eq!(script_code, Some(comp.pkh_spk)); // Scriptsig is nonempty @@ -628,7 +660,7 @@ mod tests { let fixed = fixed_test_data(); let comp = KeyTestData::from_key(fixed.pk_comp); let uncomp = KeyTestData::from_key(fixed.pk_uncomp); - let blank_script = bitcoin::ScriptBuf::new(); + let blank_script = ScriptBuf::new(); // sh_wpkh, missing witness or scriptsig let err = from_txdata(&comp.sh_wpkh_spk, &blank_script, &Witness::default()).unwrap_err(); @@ -669,11 +701,11 @@ mod tests { from_txdata(&comp.sh_wpkh_spk, &comp.sh_wpkh_sig, &comp.sh_wpkh_stack) .expect("parse txdata"); assert_eq!(inner, Inner::PublicKey(fixed.pk_comp.into(), PubkeyType::ShWpkh)); - assert_eq!(stack, Stack::from(vec![comp.sh_wpkh_stack.second_to_last().unwrap().into()])); + assert_eq!(stack, Stack::from(vec![comp.sh_wpkh_stack.iter().rev().nth(1).unwrap().into()])); assert_eq!(script_code, Some(comp.pkh_spk.clone())); } - fn ms_inner_script(ms: &str) -> (Miniscript, bitcoin::ScriptBuf) { + fn ms_inner_script(ms: &str) -> (Miniscript, ScriptBuf) { let ms = Miniscript::::from_str_insane(ms).unwrap(); let spk = ms.encode(); let miniscript = ms.to_no_checks_ms(); @@ -684,7 +716,7 @@ mod tests { fn script_bare() { let preimage = b"12345678----____12345678----____"; let hash = hash160::Hash::hash(&preimage[..]); - let blank_script = bitcoin::ScriptBuf::new(); + let blank_script = ScriptBuf::new(); let empty_wit = Witness::default(); let (miniscript, spk) = ms_inner_script(&format!("hash160({})", hash)); @@ -712,11 +744,11 @@ mod tests { let (miniscript, redeem_script) = ms_inner_script(&format!("hash160({})", hash)); let rs_hash = hash160::Hash::hash(redeem_script.as_bytes()).into(); - let spk = ScriptBuf::new_p2sh(&rs_hash); - let script_sig = script::Builder::new() + let spk = ScriptBuf::new_p2sh(rs_hash); + let script_sig = ScriptBuilderLocal::new() .push_slice(<&PushBytes>::try_from(redeem_script.as_bytes()).unwrap()) .into_script(); - let blank_script = bitcoin::ScriptBuf::new(); + let blank_script = ScriptBuf::new(); let empty_wit = Witness::default(); // sh without scriptsig @@ -748,8 +780,8 @@ mod tests { let wit_hash = sha256::Hash::hash(witness_script.as_bytes()).into(); let wit_stack = Witness::from_slice(&[witness_script.to_bytes()]); - let spk = ScriptBuf::new_p2wsh(&wit_hash); - let blank_script = bitcoin::ScriptBuf::new(); + let spk = ScriptBuf::new_p2wsh(wit_hash); + let blank_script = ScriptBuf::new(); // wsh without witness let err = from_txdata(&spk, &blank_script, &Witness::default()).unwrap_err(); @@ -768,7 +800,7 @@ mod tests { assert_eq!(script_code, Some(witness_script.clone())); // nonempty script_sig - let script_sig = script::Builder::new() + let script_sig = ScriptBuilderLocal::new() .push_slice(<&PushBytes>::try_from(witness_script.as_bytes()).unwrap()) .into_script(); let err = from_txdata(&spk, &script_sig, &wit_stack).unwrap_err(); @@ -783,14 +815,14 @@ mod tests { let wit_hash = sha256::Hash::hash(witness_script.as_bytes()).into(); let wit_stack = Witness::from_slice(&[witness_script.to_bytes()]); - let redeem_script = ScriptBuf::new_p2wsh(&wit_hash); - let script_sig = script::Builder::new() + let redeem_script = ScriptBuf::new_p2wsh(wit_hash); + let script_sig = ScriptBuilderLocal::new() .push_slice(<&PushBytes>::try_from(redeem_script.as_bytes()).unwrap()) .into_script(); - let blank_script = bitcoin::ScriptBuf::new(); + let blank_script = ScriptBuf::new(); let rs_hash = hash160::Hash::hash(redeem_script.as_bytes()).into(); - let spk = ScriptBuf::new_p2sh(&rs_hash); + let spk = ScriptBuf::new_p2sh(rs_hash); // shwsh without witness or scriptsig let err = from_txdata(&spk, &blank_script, &Witness::default()).unwrap_err(); diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 5aed49fb0..fdd6509dd 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -11,7 +11,7 @@ use core::fmt; use core::str::FromStr; -use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; +use bitcoin::hashes::{hash160, ripemd160, sha256}; use bitcoin::{absolute, relative, secp256k1, sighash, taproot, Sequence, TxOut, Witness}; use crate::miniscript::context::{NoChecks, SigType}; @@ -34,7 +34,7 @@ pub struct Interpreter<'txin> { stack: Stack<'txin>, /// For non-Taproot spends, the scriptCode; for Taproot script-spends, this /// is the leaf script; for key-spends it is `None`. - script_code: Option, + script_code: Option, sequence: Sequence, lock_time: absolute::LockTime, } @@ -126,7 +126,7 @@ impl MiniscriptKey for BitcoinKey { fn is_uncompressed(&self) -> bool { match *self { - BitcoinKey::Fullkey(pk) => !pk.compressed, + BitcoinKey::Fullkey(pk) => !pk.compressed(), BitcoinKey::XOnlyPublicKey(_) => false, } } @@ -142,8 +142,8 @@ impl<'txin> Interpreter<'txin> { /// function; otherwise, it should be a closure containing a sighash and /// secp context, which can actually verify a given signature. pub fn from_txdata( - spk: &bitcoin::ScriptBuf, - script_sig: &'txin bitcoin::Script, + spk: &crate::ScriptBuf, + script_sig: &'txin crate::Script, witness: &'txin Witness, sequence: Sequence, // CSV, relative lock time. lock_time: absolute::LockTime, // CLTV, absolute lock time. @@ -226,13 +226,16 @@ impl<'txin> Interpreter<'txin> { sighash.map(|hash| secp256k1::Message::from_digest(hash.to_byte_array())) } else if self.is_segwit_v0() { let amt = match get_prevout(prevouts, input_idx) { - Some(txout) => txout.borrow().value, + Some(txout) => txout.borrow().amount, None => return false, }; // TODO: Don't manually handle the script code. + let witness_script = bitcoin::script::WitnessScript::from_bytes( + script_pubkey.as_bytes(), + ); let sighash = cache.p2wsh_signature_hash( input_idx, - script_pubkey, + witness_script, amt, ecdsa_sig.sighash_type, ); @@ -243,7 +246,8 @@ impl<'txin> Interpreter<'txin> { }; let success = msg.map(|msg| { - secp.verify_ecdsa(&msg, &ecdsa_sig.signature, &key.inner) + let inner_pk = key.to_inner(); + secp.verify_ecdsa(msg, &ecdsa_sig.signature, &inner_pk) .is_ok() }); success.unwrap_or(false) // unwrap_or checks for errors, while success would have checksig results @@ -260,6 +264,9 @@ impl<'txin> Interpreter<'txin> { "Internal Hack: Saving leaf script instead\ of script code for script spend", ); + let tap_script = bitcoin::script::TapScript::from_bytes( + tap_script.as_bytes(), + ); let leaf_hash = taproot::TapLeafHash::from_script( tap_script, taproot::LeafVersion::TapScript, @@ -274,10 +281,9 @@ impl<'txin> Interpreter<'txin> { // schnorr sigs in ecdsa descriptors return false; }; - let msg = - sighash_msg.map(|hash| secp256k1::Message::from_digest(hash.to_byte_array())); + let msg = sighash_msg.map(|hash| hash.to_byte_array()); let success = msg.map(|msg| { - secp.verify_schnorr(&schnorr_sig.signature, &msg, xpk) + secp.verify_schnorr(&schnorr_sig.signature, &msg, xpk.as_inner()) .is_ok() }); success.unwrap_or(false) // unwrap_or_default checks for errors, while success would have checksig results @@ -1089,11 +1095,8 @@ mod tests { sk[1] = (i >> 8) as u8; sk[2] = (i >> 16) as u8; - let sk = secp256k1::SecretKey::from_slice(&sk[..]).expect("secret key"); - let pk = bitcoin::PublicKey { - inner: secp256k1::PublicKey::from_secret_key(&secp, &sk), - compressed: true, - }; + let sk = secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"); + let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key(&secp, &sk)); let signature = secp.sign_ecdsa(&msg, &sk); ecdsa_sigs.push(bitcoin::ecdsa::Signature { signature, @@ -1105,7 +1108,7 @@ mod tests { der_sigs.push(sigser); let keypair = bitcoin::key::Keypair::from_secret_key(&secp, &sk); - let (x_only_pk, _parity) = bitcoin::key::XOnlyPublicKey::from_keypair(&keypair); + let x_only_pk = bitcoin::key::XOnlyPublicKey::from_keypair(&keypair); x_only_pks.push(x_only_pk); let schnorr_sig = secp.sign_schnorr_with_aux_rand(&msg, &keypair, &[0u8; 32]); let schnorr_sig = bitcoin::taproot::Signature { @@ -1125,7 +1128,7 @@ mod tests { let secp_ref = &secp; let vfyfn = |pksig: &KeySigPair| match pksig { KeySigPair::Ecdsa(pk, ecdsa_sig) => secp_ref - .verify_ecdsa(&sighash, &ecdsa_sig.signature, &pk.inner) + .verify_ecdsa(&sighash, &ecdsa_sig.signature, pk.as_inner()) .is_ok(), KeySigPair::Schnorr(xpk, schnorr_sig) => secp_ref .verify_schnorr(&schnorr_sig.signature, &sighash, xpk) diff --git a/src/interpreter/stack.rs b/src/interpreter/stack.rs index 647a84713..ee22da361 100644 --- a/src/interpreter/stack.rs +++ b/src/interpreter/stack.rs @@ -4,7 +4,7 @@ //! Interpreter stack use bitcoin::blockdata::{opcodes, script}; -use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; +use bitcoin::hashes::{hash160, ripemd160, sha256}; use bitcoin::{absolute, relative, Sequence}; use super::error::PkEvalErrInner; @@ -152,7 +152,10 @@ impl<'txin> Stack<'txin> { // We don't really store information about which key error. fn bitcoin_key_from_slice(sl: &[u8], sig_type: SigType) -> Option { let key: BitcoinKey = match sig_type { - SigType::Schnorr => bitcoin::key::XOnlyPublicKey::from_slice(sl).ok()?.into(), + SigType::Schnorr => { + let arr = <[u8; 32]>::try_from(sl).ok()?; + bitcoin::key::XOnlyPublicKey::from_byte_array(&arr).ok()?.into() + } SigType::Ecdsa => bitcoin::PublicKey::from_slice(sl).ok()?.into(), }; Some(key) diff --git a/src/lib.rs b/src/lib.rs index 87714e103..3baf13b46 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -130,7 +130,20 @@ mod util; use core::{fmt, hash, str}; -use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; +use bitcoin::hashes::{hash160, ripemd160, sha256}; + +/// Re-export of the tagged `ScriptBuf` used for scriptPubKey values in bitcoin 0.33+. +/// +/// Miniscript emits and consumes scriptPubKeys almost everywhere; this alias keeps +/// the existing `ScriptBuf` spelling working without having to reach into +/// `bitcoin::script` at every call-site. +pub type ScriptBuf = bitcoin::script::ScriptPubKeyBuf; + +/// Re-export of the tagged `Script` corresponding to [`ScriptBuf`]. +pub type Script = bitcoin::script::ScriptPubKey; + +/// Re-export of the tagged `script::Builder` for [`ScriptBuf`]. +pub type ScriptBuilder = bitcoin::script::Builder; pub use crate::blanket_traits::FromStrKey; pub use crate::descriptor::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey}; @@ -189,7 +202,7 @@ impl MiniscriptKey for bitcoin::PublicKey { type Ripemd160 = ripemd160::Hash; type Hash160 = hash160::Hash; - fn is_uncompressed(&self) -> bool { !self.compressed } + fn is_uncompressed(&self) -> bool { !self.compressed() } fn is_x_only_key(&self) -> bool { false } fn num_der_paths(&self) -> usize { 0 } } @@ -204,6 +217,16 @@ impl MiniscriptKey for bitcoin::secp256k1::XOnlyPublicKey { fn num_der_paths(&self) -> usize { 0 } } +impl MiniscriptKey for bitcoin::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 } + fn num_der_paths(&self) -> usize { 0 } +} + impl MiniscriptKey for String { type Sha256 = String; type Hash256 = String; @@ -222,7 +245,7 @@ pub trait ToPublicKey: MiniscriptKey { /// Converts key to an x-only public key. fn to_x_only_pubkey(&self) -> bitcoin::secp256k1::XOnlyPublicKey { let pk = self.to_public_key(); - bitcoin::secp256k1::XOnlyPublicKey::from(pk.inner) + bitcoin::secp256k1::XOnlyPublicKey::from(pk.to_inner()) } /// Obtains the pubkey hash for this key (as a `MiniscriptKey`). @@ -285,6 +308,19 @@ impl ToPublicKey for bitcoin::secp256k1::XOnlyPublicKey { fn to_hash160(hash: &hash160::Hash) -> hash160::Hash { *hash } } +impl ToPublicKey for bitcoin::XOnlyPublicKey { + fn to_public_key(&self) -> bitcoin::PublicKey { + bitcoin::XOnlyPublicKey::to_public_key(self) + } + + fn to_x_only_pubkey(&self) -> bitcoin::secp256k1::XOnlyPublicKey { *self.as_inner() } + + 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 } +} + /// Describes an object that can translate various keys and hashes from one key to the type /// associated with the other key. Used by the [`TranslatePk`] trait to do the actual translations. pub trait Translator { @@ -433,7 +469,7 @@ pub enum Error { /// rust-bitcoin address error AddrError(bitcoin::address::ParseError), /// rust-bitcoin p2sh address error - AddrP2shError(bitcoin::address::P2shError), + AddrP2shError(bitcoin::script::RedeemScriptSizeError), /// While parsing backward, hit beginning of script UnexpectedStart, /// Got something we were not expecting @@ -632,8 +668,8 @@ impl From for Error { } #[doc(hidden)] -impl From for Error { - fn from(e: bitcoin::address::P2shError) -> Error { Error::AddrP2shError(e) } +impl From for Error { + fn from(e: bitcoin::script::RedeemScriptSizeError) -> Error { Error::AddrP2shError(e) } } #[doc(hidden)] @@ -673,7 +709,10 @@ fn push_opcode_size(script_size: usize) -> usize { /// Helper function used by tests #[cfg(test)] -fn hex_script(s: &str) -> bitcoin::ScriptBuf { bitcoin::ScriptBuf::from_hex(s).unwrap() } +fn hex_script(s: &str) -> ScriptBuf { + use bitcoin::script::ScriptBufExt as _; + ScriptBuf::from_hex(s).unwrap() +} #[cfg(test)] mod tests { diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs index 078cfac58..04e05a3b7 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -7,22 +7,21 @@ //! encoding in Bitcoin script, as well as a datatype. Full details //! are given on the Miniscript website. -use bitcoin::hashes::Hash; -use bitcoin::{absolute, opcodes, script}; +use bitcoin::{absolute, opcodes}; use crate::miniscript::context::SigType; use crate::miniscript::ScriptContext; use crate::util::MsKeyBuilder; -use crate::{Miniscript, MiniscriptKey, Terminal, ToPublicKey}; +use crate::{Miniscript, MiniscriptKey, ScriptBuilder, Terminal, ToPublicKey}; -/// Helper trait to add a `push_astelem` method to `script::Builder` +/// Helper trait to add a `push_astelem` method to `ScriptBuilder` trait PushAstElem { fn push_astelem(self, ast: &Miniscript) -> Self where Pk: ToPublicKey; } -impl PushAstElem for script::Builder { +impl PushAstElem for ScriptBuilder { fn push_astelem(self, ast: &Miniscript) -> Self where Pk: ToPublicKey, @@ -35,7 +34,7 @@ impl Terminal { /// Encode the element as a fragment of Bitcoin Script. The inverse /// function, from Script to an AST element, is implemented in the /// `parse` module. - pub fn encode(&self, mut builder: script::Builder) -> script::Builder + pub fn encode(&self, mut builder: ScriptBuilder) -> ScriptBuilder where Pk: ToPublicKey, { @@ -52,41 +51,41 @@ impl Terminal { .push_slice(hash.to_byte_array()) .push_opcode(opcodes::all::OP_EQUALVERIFY), Terminal::After(t) => builder - .push_int(absolute::LockTime::from(t).to_consensus_u32() as i64) + .push_int_unchecked(absolute::LockTime::from(t).to_consensus_u32() as i64) .push_opcode(opcodes::all::OP_CLTV), Terminal::Older(t) => builder - .push_int(t.to_consensus_u32().into()) + .push_int_unchecked(t.to_consensus_u32() as i64) .push_opcode(opcodes::all::OP_CSV), Terminal::Sha256(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) - .push_int(32) + .push_int_unchecked(32) .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_SHA256) .push_slice(Pk::to_sha256(h).to_byte_array()) .push_opcode(opcodes::all::OP_EQUAL), Terminal::Hash256(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) - .push_int(32) + .push_int_unchecked(32) .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_HASH256) .push_slice(Pk::to_hash256(h).to_byte_array()) .push_opcode(opcodes::all::OP_EQUAL), Terminal::Ripemd160(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) - .push_int(32) + .push_int_unchecked(32) .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_RIPEMD160) .push_slice(Pk::to_ripemd160(h).to_byte_array()) .push_opcode(opcodes::all::OP_EQUAL), Terminal::Hash160(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) - .push_int(32) + .push_int_unchecked(32) .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_HASH160) .push_slice(Pk::to_hash160(h).to_byte_array()) .push_opcode(opcodes::all::OP_EQUAL), - Terminal::True => builder.push_opcode(opcodes::OP_TRUE), - Terminal::False => builder.push_opcode(opcodes::OP_FALSE), + Terminal::True => builder.push_opcode(opcodes::all::OP_PUSHNUM_1), + Terminal::False => builder.push_opcode(opcodes::all::OP_0), Terminal::Alt(ref sub) => builder .push_opcode(opcodes::all::OP_TOALTSTACK) .push_astelem(sub) @@ -149,7 +148,7 @@ impl Terminal { builder = builder.push_astelem(sub).push_opcode(opcodes::all::OP_ADD); } builder - .push_int(thresh.k() as i64) + .push_int_unchecked(thresh.k() as i64) .push_opcode(opcodes::all::OP_EQUAL) } Terminal::Multi(ref thresh) | Terminal::SortedMulti(ref thresh) => { @@ -161,12 +160,12 @@ impl Terminal { } else { thresh.iter() }; - builder = builder.push_int(thresh.k() as i64); + builder = builder.push_int_unchecked(thresh.k() as i64); for pk in iter { - builder = builder.push_key(&pk.to_public_key()); + builder = builder.push_key(pk.to_public_key()); } builder - .push_int(thresh.n() as i64) + .push_int_unchecked(thresh.n() as i64) .push_opcode(opcodes::all::OP_CHECKMULTISIG) } Terminal::MultiA(ref thresh) | Terminal::SortedMultiA(ref thresh) => { @@ -188,7 +187,7 @@ impl Terminal { builder = builder.push_opcode(opcodes::all::OP_CHECKSIGADD); } builder - .push_int(thresh.k() as i64) + .push_int_unchecked(thresh.k() as i64) .push_opcode(opcodes::all::OP_NUMEQUAL) } } diff --git a/src/miniscript/decode.rs b/src/miniscript/decode.rs index a8c0b8491..52213d123 100644 --- a/src/miniscript/decode.rs +++ b/src/miniscript/decode.rs @@ -9,7 +9,7 @@ use core::{fmt, mem}; #[cfg(feature = "std")] use std::error; -use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; +use bitcoin::hashes::{hash160, ripemd160, sha256}; use sync::Arc; use crate::iter::TreeLike; @@ -38,7 +38,10 @@ impl ParseableKey for bitcoin::PublicKey { impl ParseableKey for bitcoin::secp256k1::XOnlyPublicKey { fn from_slice(sl: &[u8]) -> Result { - bitcoin::secp256k1::XOnlyPublicKey::from_slice(sl).map_err(KeyError::XOnly) + let arr: [u8; 32] = sl + .try_into() + .map_err(|_| KeyError::XOnly(bitcoin::secp256k1::Error::InvalidPublicKey))?; + bitcoin::secp256k1::XOnlyPublicKey::from_byte_array(arr).map_err(KeyError::XOnly) } } diff --git a/src/miniscript/lex.rs b/src/miniscript/lex.rs index 1df1f2dd4..e1a65e61e 100644 --- a/src/miniscript/lex.rs +++ b/src/miniscript/lex.rs @@ -8,9 +8,10 @@ use core::fmt; use bitcoin::blockdata::{opcodes, script}; -use bitcoin::hex::DisplayHex as _; +use bitcoin::script::ScriptExt as _; use crate::prelude::*; +use crate::Script; /// Atom of a tokenized version of a script #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -50,15 +51,22 @@ pub enum Token { Bytes65([u8; 65]), } +fn fmt_bytes_hex(f: &mut fmt::Formatter<'_>, bytes: &[u8]) -> fmt::Result { + for byte in bytes { + write!(f, "{:02x}", byte)?; + } + Ok(()) +} + impl fmt::Display for Token { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Token::Num(n) => write!(f, "#{}", n), - Token::Hash20(b) => write!(f, "{}", b.as_hex()), - Token::Bytes32(b) => write!(f, "{}", b.as_hex()), - Token::Bytes33(b) => write!(f, "{}", b.as_hex()), - Token::Bytes65(b) => write!(f, "{}", b.as_hex()), - x => write!(f, "{:?}", x), + Token::Hash20(ref b) => fmt_bytes_hex(f, b), + Token::Bytes32(ref b) => fmt_bytes_hex(f, b), + Token::Bytes33(ref b) => fmt_bytes_hex(f, b), + Token::Bytes65(ref b) => fmt_bytes_hex(f, b), + ref x => write!(f, "{:?}", x), } } } @@ -93,7 +101,7 @@ impl Iterator for TokenIter { } /// Tokenize a script -pub fn lex(script: &'_ script::Script) -> Result, Error> { +pub fn lex(script: &'_ Script) -> Result, Error> { let mut ret = Vec::with_capacity(script.len()); for ins in script.instructions_minimal() { @@ -215,11 +223,11 @@ pub fn lex(script: &'_ script::Script) -> Result, Error> { ret.push(Token::Bytes65(bytes)); } else { // check minimality of the number - match script::read_scriptint(bytes.as_bytes()) { + match script::read_scriptint_non_minimal(bytes.as_bytes()) { Ok(v) if v >= 0 => { ret.push(Token::Num(v as u32)); } - Ok(n) => return Err(Error::NegativeInt { bytes: bytes.to_owned(), n }), + Ok(n) => return Err(Error::NegativeInt { bytes: bytes.to_owned(), n: n as i64 }), Err(err) => return Err(Error::InvalidInt { bytes: bytes.to_owned(), err }), } } @@ -289,7 +297,7 @@ pub enum Error { /// The bytes of the push that were attempted to be parsed. bytes: bitcoin::script::PushBytesBuf, /// The error that occurred. - err: bitcoin::script::Error, + err: bitcoin::script::ScriptIntError, }, /// Parsed an opcode outside of the Miniscript language. InvalidOpcode(bitcoin::Opcode), @@ -310,9 +318,17 @@ impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Self::Script(ref e) => e.fmt(f), - Self::InvalidInt { ref bytes, ref err } => write!(f, "push {} of length {} is not a key, hash or minimal integer: {}", bytes.as_bytes().as_hex(), bytes.len(), err), + Self::InvalidInt { ref bytes, ref err } => { + write!(f, "push ")?; + fmt_bytes_hex(f, bytes.as_bytes())?; + write!(f, " of length {} is not a key, hash or minimal integer: {}", bytes.len(), err) + } Self::InvalidOpcode(ref op) => write!(f, "found opcode {} which does not occur in Miniscript", op), - Self::NegativeInt { ref bytes, n } => write!(f, "push {} of length {} parses as a negative number {} which does not occur in Miniscript", bytes.as_bytes().as_hex(), bytes.len(), n), + Self::NegativeInt { ref bytes, n } => { + write!(f, "push ")?; + fmt_bytes_hex(f, bytes.as_bytes())?; + write!(f, " of length {} parses as a negative number {} which does not occur in Miniscript", bytes.len(), n) + }, Self::NonMinimalVerify(ref op) => write!(f, "found {} VERIFY (should be one opcode, {}VERIFY)", op, op), } } diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 4aff8784f..f5559ce82 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -15,14 +15,13 @@ use core::{hash, str}; use bitcoin::hashes::hash160; -use bitcoin::script; use bitcoin::taproot::{LeafVersion, TapLeafHash}; use self::analyzable::ExtParams; pub use self::context::{BareCtx, Legacy, Segwitv0, Tap}; use crate::iter::TreeLike; use crate::prelude::*; -use crate::{script_num_size, TranslateErr}; +use crate::{script_num_size, Script, ScriptBuf, ScriptBuilder, TranslateErr}; pub mod analyzable; pub mod astelem; @@ -362,11 +361,11 @@ impl Miniscript { pub fn as_inner(&self) -> &Terminal { &self.node } /// Encode as a Bitcoin script - pub fn encode(&self) -> script::ScriptBuf + pub fn encode(&self) -> ScriptBuf where Pk: ToPublicKey, { - self.node.encode(script::Builder::new()).into_script() + self.node.encode(ScriptBuilder::new()).into_script() } /// Size, in bytes of the script-pubkey. If this Miniscript is used outside @@ -453,7 +452,9 @@ impl Miniscript { where Pk: ToPublicKey, { - TapLeafHash::from_script(&self.encode(), LeafVersion::TapScript) + let encoded = self.encode(); + let tap_script = bitcoin::script::TapScript::from_bytes(encoded.as_bytes()); + TapLeafHash::from_script(tap_script, LeafVersion::TapScript) } /// Attempt to produce non-malleable satisfying witness for the @@ -549,13 +550,13 @@ impl Miniscript { /// It may make sense to use this method when parsing Script that is already /// embedded in the chain. While it is inadvisable to use insane Miniscripts, /// once it's on the chain you don't have much choice anymore. - pub fn decode_consensus(script: &script::Script) -> Result, Error> { + pub fn decode_consensus(script: &Script) -> Result, Error> { Miniscript::decode_with_ext(script, &ExtParams::allow_all()) } /// Attempt to decode a Miniscript from Script, specifying which validation parameters to apply. pub fn decode_with_ext( - script: &script::Script, + script: &Script, ext: &ExtParams, ) -> Result, Error> { let tokens = lex(script)?; @@ -585,29 +586,30 @@ impl Miniscript { /// /// ```rust /// use miniscript::{Miniscript, Segwitv0, Tap}; + /// use miniscript::bitcoin::script::ScriptBufExt as _; /// use miniscript::bitcoin::secp256k1::XOnlyPublicKey; /// /// type Segwitv0Script = Miniscript; /// type TapScript = Miniscript; /// /// // parse x-only miniscript in Taproot context - /// let tapscript_ms = TapScript::decode(&bitcoin::ScriptBuf::from_hex( + /// let tapscript_ms = TapScript::decode(&miniscript::ScriptBuf::from_hex( /// "202788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac", /// ).expect("Even length hex")) /// .expect("Xonly keys are valid only in taproot context"); /// // tapscript fails decoding when we use them with compressed keys - /// let err = TapScript::decode(&bitcoin::ScriptBuf::from_hex( + /// let err = TapScript::decode(&miniscript::ScriptBuf::from_hex( /// "21022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac", /// ).expect("Even length hex")) /// .expect_err("Compressed keys cannot be used in Taproot context"); /// // Segwitv0 succeeds decoding with full keys. - /// Segwitv0Script::decode(&bitcoin::ScriptBuf::from_hex( + /// Segwitv0Script::decode(&miniscript::ScriptBuf::from_hex( /// "21022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac", /// ).expect("Even length hex")) /// .expect("Compressed keys are allowed in Segwit context"); /// /// ``` - pub fn decode(script: &script::Script) -> Result, Error> { + pub fn decode(script: &Script) -> Result, Error> { let ms = Self::decode_with_ext(script, &ExtParams::sane())?; Ok(ms) } @@ -1076,13 +1078,24 @@ serde_string_impl_pk!(Miniscript, "a miniscript", Ctx; ScriptContext); /// Provides a Double SHA256 `Hash` type that displays forwards. pub mod hash256 { - use bitcoin::hashes::{hash_newtype, sha256d}; + use bitcoin::hashes::{hash_newtype, impl_hex_for_newtype, sha256d}; hash_newtype! { /// A hash256 of preimage. #[hash_newtype(forward)] pub struct Hash(sha256d::Hash); } + + impl_hex_for_newtype!(Hash); + + #[allow(clippy::self_named_constructors)] + impl Hash { + /// Hashes some bytes. + pub fn hash(data: &[u8]) -> Self { Self(sha256d::Hash::hash(data)) } + + /// Construct a zero-filled hash. + pub fn all_zeros() -> Self { Self(sha256d::Hash::from_byte_array([0; 32])) } + } } #[cfg(test)] @@ -1117,13 +1130,10 @@ mod tests { sk[1] = (i >> 8) as u8; sk[2] = (i >> 16) as u8; - let pk = bitcoin::PublicKey { - inner: secp256k1::PublicKey::from_secret_key( - &secp, - &secp256k1::SecretKey::from_slice(&sk[..]).expect("secret key"), - ), - compressed: true, - }; + let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key( + &secp, + &secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"), + )); ret.push(pk); } ret @@ -1926,7 +1936,7 @@ mod tests { #[test] fn test_script_parse_dos() { - let mut script = bitcoin::script::Builder::new().push_opcode(bitcoin::opcodes::OP_TRUE); + let mut script = crate::ScriptBuilder::new().push_opcode(bitcoin::opcodes::all::OP_PUSHNUM_1); for _ in 0..10000 { script = script.push_opcode(bitcoin::opcodes::all::OP_0NOTEQUAL); } diff --git a/src/miniscript/satisfy.rs b/src/miniscript/satisfy.rs index 5a88e4ad3..9e6532506 100644 --- a/src/miniscript/satisfy.rs +++ b/src/miniscript/satisfy.rs @@ -11,7 +11,7 @@ use core::{cmp, fmt, mem}; use bitcoin::hashes::hash160; use bitcoin::key::XOnlyPublicKey; use bitcoin::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash}; -use bitcoin::{absolute, relative, ScriptBuf, Sequence}; +use bitcoin::{absolute, relative, Sequence}; use sync::Arc; use super::context::SigType; @@ -19,8 +19,8 @@ use crate::plan::AssetProvider; use crate::prelude::*; use crate::util::witness_size; use crate::{ - AbsLockTime, Miniscript, MiniscriptKey, RelLockTime, ScriptContext, Terminal, Threshold, - ToPublicKey, + AbsLockTime, Miniscript, MiniscriptKey, RelLockTime, ScriptBuf, ScriptContext, Terminal, + Threshold, ToPublicKey, }; /// Type alias for 32 byte Preimage. @@ -49,7 +49,7 @@ pub trait Satisfier { /// Obtain a reference to the control block for a ver and script fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { None } @@ -247,7 +247,7 @@ macro_rules! impl_satisfier_for_map_hash_tapleafhash_to_key_taproot_sig { pk_hash: &(hash160::Hash, TapLeafHash), ) -> Option<(XOnlyPublicKey, bitcoin::taproot::Signature)> { self.get(pk_hash) - .map(|&(ref pk, sig)| (pk.to_x_only_pubkey(), sig)) + .map(|&(ref pk, sig)| (pk.to_x_only_pubkey().into(), sig)) } } }; @@ -303,7 +303,7 @@ impl> Satisfier for &S { fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { (**self).lookup_tap_control_block_map() } @@ -363,7 +363,7 @@ impl> Satisfier for &mut S fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { (**self).lookup_tap_control_block_map() } @@ -473,7 +473,7 @@ macro_rules! impl_tuple_satisfier { fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { let &($(ref $ty,)*) = self; $( if let Some(result) = $ty.lookup_tap_control_block_map() { @@ -695,7 +695,7 @@ impl Placeholder { Placeholder::HashDissatisfaction => Some(vec![0; 32]), Placeholder::PushZero => Some(vec![]), Placeholder::PushOne => Some(vec![1]), - Placeholder::TapScript(s) => Some(s.to_bytes()), + Placeholder::TapScript(s) => Some(s.to_vec()), Placeholder::TapControlBlock(cb) => Some(cb.serialize()), } } diff --git a/src/plan.rs b/src/plan.rs index 6f56895a4..01d186252 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -20,16 +20,20 @@ use core::iter::FromIterator; use bitcoin::hashes::{hash160, ripemd160, sha256}; use bitcoin::key::XOnlyPublicKey; -use bitcoin::script::PushBytesBuf; +use bitcoin::script::{ + PushBytesBuf, RedeemScriptBuf, TapScriptBuf, WitnessScriptBuf, WitnessScriptExt as _, +}; use bitcoin::taproot::{ControlBlock, LeafVersion, TapLeafHash}; -use bitcoin::{absolute, bip32, psbt, relative, ScriptBuf, WitnessVersion}; +use bitcoin::{absolute, bip32, psbt, relative, WitnessVersion}; use crate::descriptor::{self, Descriptor, DescriptorType, KeyMap}; use crate::miniscript::hash256; use crate::miniscript::satisfy::{Placeholder, Satisfier, SchnorrSigType}; use crate::prelude::*; use crate::util::witness_size; -use crate::{DefiniteDescriptorKey, DescriptorPublicKey, Error, MiniscriptKey, ToPublicKey}; +use crate::{ + DefiniteDescriptorKey, DescriptorPublicKey, Error, MiniscriptKey, ScriptBuf, ToPublicKey, +}; /// Trait describing a present/missing lookup table for constructing witness templates /// @@ -334,7 +338,7 @@ impl Plan { Placeholder::TapScript(script) => data.tap_script = Some(script.clone()), Placeholder::TapControlBlock(cb) => data.control_block = Some(cb.clone()), Placeholder::SchnorrSigPk(pk, sig_type, _) => { - let raw_pk = pk.to_x_only_pubkey(); + let raw_pk: XOnlyPublicKey = pk.to_x_only_pubkey().into(); match (&data.spend_type, sig_type) { // First encountered schnorr sig, update the `TrDescriptorData` accordingly @@ -385,14 +389,18 @@ impl Plan { .or_insert_with(|| (vec![], key_source)); } if let (Some(tap_script), Some(control_block)) = (data.tap_script, data.control_block) { - input - .tap_scripts - .insert(control_block, (tap_script, LeafVersion::TapScript)); + input.tap_scripts.insert( + control_block, + ( + TapScriptBuf::from_bytes(tap_script.into_bytes()), + LeafVersion::TapScript, + ), + ); } } else { for item in &self.template { if let Placeholder::EcdsaSigPk(pk) = item { - let public_key = pk.to_public_key().inner; + let public_key = pk.to_public_key().to_inner(); let master_fingerprint = pk.master_fingerprint(); for derivation_path in pk.full_derivation_paths() { input @@ -406,13 +414,28 @@ impl Plan { Descriptor::Bare(_) | Descriptor::Pkh(_) | Descriptor::Wpkh(_) => {} Descriptor::Sh(sh) => match sh.as_inner() { descriptor::ShInner::Wsh(wsh) => { - input.witness_script = Some(wsh.inner_script()); - input.redeem_script = Some(wsh.inner_script().to_p2wsh()); + let inner = wsh.inner_script(); + let witness_script = + WitnessScriptBuf::from_bytes(inner.to_vec()); + input.redeem_script = witness_script.to_p2wsh().ok().map(|spk| { + RedeemScriptBuf::from_bytes(spk.into_bytes()) + }); + input.witness_script = Some(witness_script); + } + descriptor::ShInner::Wpkh(..) => { + input.redeem_script = + Some(RedeemScriptBuf::from_bytes(sh.inner_script().into_bytes())) + } + descriptor::ShInner::Ms(_) => { + input.redeem_script = + Some(RedeemScriptBuf::from_bytes(sh.inner_script().into_bytes())) } - descriptor::ShInner::Wpkh(..) => input.redeem_script = Some(sh.inner_script()), - descriptor::ShInner::Ms(_) => input.redeem_script = Some(sh.inner_script()), }, - Descriptor::Wsh(wsh) => input.witness_script = Some(wsh.inner_script()), + Descriptor::Wsh(wsh) => { + input.witness_script = Some(WitnessScriptBuf::from_bytes( + wsh.inner_script().into_bytes(), + )) + } Descriptor::Tr(_) => unreachable!("Tr is dealt with separately"), } } @@ -1067,7 +1090,7 @@ mod test { "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c", ) .unwrap()]; - let hashes = vec![hash160::Hash::from_slice(&[0; 20]).unwrap()]; + let hashes = vec![hash160::Hash::from_byte_array([0; 20])]; let desc = format!("wsh(and_v(v:pk({}),hash160({})))", keys[0], hashes[0]); let tests = vec![ @@ -1162,13 +1185,13 @@ mod test { let secp = Secp256k1::new(); let (sks, pks): (Vec<_>, Vec<_>) = [ - &b"sally was a secret key, she said"[..], - &b"polly was a secret key, she said"[..], - &b"bonny was a secret key, she said"[..], + b"sally was a secret key, she said", + b"polly was a secret key, she said", + b"bonny was a secret key, she said", ] .iter() - .map(|d| { - let sk = secp256k1::SecretKey::from_slice(d).unwrap(); + .map(|d: &&[u8; 32]| { + let sk = secp256k1::SecretKey::from_secret_bytes(**d).unwrap(); let pk = bitcoin::PublicKey::new(secp256k1::PublicKey::from_secret_key(&secp, &sk)); (sk, pk) }) diff --git a/src/policy/compiler.rs b/src/policy/compiler.rs index 24b0f0ae1..2d7519d21 100644 --- a/src/policy/compiler.rs +++ b/src/policy/compiler.rs @@ -1275,18 +1275,15 @@ mod tests { sk[1] = (i >> 8) as u8; sk[2] = (i >> 16) as u8; - let pk = bitcoin::PublicKey { - inner: secp256k1::PublicKey::from_secret_key( - &secp, - &secp256k1::SecretKey::from_slice(&sk[..]).expect("sk"), - ), - compressed: true, - }; + let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key( + &secp, + &secp256k1::SecretKey::from_secret_bytes(sk).expect("sk"), + )); ret.push(pk); } let sig = secp.sign_ecdsa( &secp256k1::Message::from_digest(sk), // Not a digest but 32 bytes nonetheless. - &secp256k1::SecretKey::from_slice(&sk[..]).expect("secret key"), + &secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"), ); (ret, sig) } diff --git a/src/primitives/threshold.rs b/src/primitives/threshold.rs index 1ec8c30dd..37271102c 100644 --- a/src/primitives/threshold.rs +++ b/src/primitives/threshold.rs @@ -247,7 +247,7 @@ impl Threshold { /// Lexicographically sorts underlying `Vec` of pubkeys as /// defined by BIP-67 and returns a new `Threshold`. pub fn into_sorted_bip67(self) -> Self { - Self::into_sorted(self, |pk| pk.to_public_key().inner.serialize()) + Self::into_sorted(self, |pk| pk.to_public_key().to_inner().serialize()) } /// Lexicographically sorts underlying `Vec` of x-only pubkeys as @@ -259,7 +259,7 @@ impl Threshold { /// Checks if underlying `Vec` of pubkeys is sorted lexicographically from /// smallest to largest as defined by BIP-67 pub fn is_sorted_bip67(&self) -> bool { - Self::is_sorted(self, |pk| pk.to_public_key().inner.serialize()) + Self::is_sorted(self, |pk| pk.to_public_key().to_inner().serialize()) } /// Checks if underlying `Vec` of x-only pubkeys is sorted lexicographically diff --git a/src/psbt/finalizer.rs b/src/psbt/finalizer.rs index ac9f815e1..acc1bacee 100644 --- a/src/psbt/finalizer.rs +++ b/src/psbt/finalizer.rs @@ -13,19 +13,22 @@ use core::mem; use bitcoin::hashes::hash160; use bitcoin::key::XOnlyPublicKey; +use bitcoin::script::{ + ScriptExt as _, ScriptPubKeyExt as _, WitnessScriptExt as _, +}; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 use bitcoin::secp256k1; use bitcoin::secp256k1::Secp256k1; use bitcoin::sighash::Prevouts; use bitcoin::taproot::LeafVersion; -use bitcoin::{PublicKey, Script, ScriptBuf, TxOut, Witness}; +use bitcoin::{PublicKey, TxOut, Witness}; use super::{sanity_check, Error, InputError, Psbt, PsbtInputSatisfier}; use crate::prelude::*; use crate::util::witness_size; use crate::{ - interpreter, BareCtx, Descriptor, Legacy, Miniscript, Satisfier, Segwitv0, SigType, Tap, - ToPublicKey, + interpreter, BareCtx, Descriptor, Legacy, Miniscript, Satisfier, Script, ScriptBuf, Segwitv0, + SigType, Tap, ToPublicKey, }; // Satisfy the taproot descriptor. It is not possible to infer the complete @@ -39,14 +42,14 @@ fn construct_tap_witness( ) -> Result>, InputError> { // When miniscript tries to finalize the PSBT, it doesn't have the full descriptor (which contained a pkh() fragment) // and instead resorts to parsing the raw script sig, which is translated into a "expr_raw_pkh" internally. - let mut map: BTreeMap = BTreeMap::new(); + let mut map: BTreeMap = BTreeMap::new(); let psbt_inputs = &sat.psbt.inputs; for psbt_input in psbt_inputs { // We need to satisfy or dissatisfy any given key. `tap_key_origin` is the only field of PSBT Input which consist of // all the keys added on a descriptor and thus we get keys from it. let public_keys = psbt_input.tap_key_origins.keys(); for key in public_keys { - let bitcoin_key = *key; + let bitcoin_key: bitcoin::secp256k1::XOnlyPublicKey = *key.as_inner(); let hash = bitcoin_key.to_pubkeyhash(SigType::Schnorr); map.insert(hash, bitcoin_key); } @@ -63,15 +66,17 @@ fn construct_tap_witness( } // Next script spends let (mut min_wit, mut min_wit_len) = (None, None); - if let Some(block_map) = - >::lookup_tap_control_block_map(sat) - { + let block_map = &sat.psbt_input().tap_scripts; + if !block_map.is_empty() { for (control_block, (script, ver)) in block_map { if *ver != LeafVersion::TapScript { // We don't know how to satisfy non default version scripts yet continue; } - let ms = match Miniscript::::decode_consensus(script) { + let script_spk = Script::from_bytes(script.as_bytes()); + let ms = match Miniscript::::decode_consensus( + script_spk, + ) { Ok(ms) => ms.substitute_raw_pkh(&map), Err(..) => continue, // try another script }; @@ -115,8 +120,8 @@ pub(super) fn get_utxo(psbt: &Psbt, index: usize) -> Result<&bitcoin::TxOut, Inp let utxo = if let Some(ref witness_utxo) = inp.witness_utxo { witness_utxo } else if let Some(ref non_witness_utxo) = inp.non_witness_utxo { - let vout = psbt.unsigned_tx.input[index].previous_output.vout; - &non_witness_utxo.output[vout as usize] + let vout = psbt.unsigned_tx.inputs[index].previous_output.vout; + &non_witness_utxo.outputs[vout as usize] } else { return Err(InputError::MissingUtxo); }; @@ -149,7 +154,7 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In let public_keys = psbt_input.bip32_derivation.keys(); for key in public_keys { let bitcoin_key = bitcoin::PublicKey::new(*key); - let hash = bitcoin_key.pubkey_hash().to_raw_hash(); + let hash = hash160::Hash::from_byte_array(bitcoin_key.pubkey_hash().to_byte_array()); map.insert(hash, bitcoin_key); } } @@ -160,7 +165,7 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In // 1. `PK`: creates a `Pk` descriptor(does not check if partial sig is given) if script_pubkey.is_p2pk() { let script_pubkey_len = script_pubkey.len(); - let pk_bytes = &script_pubkey.to_bytes(); + let pk_bytes = &script_pubkey.to_vec(); match bitcoin::PublicKey::from_slice(&pk_bytes[1..script_pubkey_len - 1]) { Ok(pk) => Ok(Descriptor::new_pk(pk)), Err(e) => Err(InputError::from(e)), @@ -188,7 +193,7 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In Ok(compressed) => { // Indirect way to check the equivalence of pubkey-hashes. // Create a pubkey hash and check if they are the same. - let addr = bitcoin::Address::p2wpkh(&compressed, bitcoin::Network::Bitcoin); + let addr = bitcoin::Address::p2wpkh(compressed, bitcoin::Network::Bitcoin); *script_pubkey == addr.script_pubkey() } Err(_) => false, @@ -204,13 +209,22 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In return Err(InputError::NonEmptyRedeemScript); } if let Some(ref witness_script) = inp.witness_script { - if witness_script.to_p2wsh() != *script_pubkey { + let derived = witness_script + .to_p2wsh() + .map_err(|_| InputError::InvalidWitnessScript { + witness_script: witness_script.clone(), + p2wsh_expected: script_pubkey.clone(), + })?; + if derived != *script_pubkey { return Err(InputError::InvalidWitnessScript { witness_script: witness_script.clone(), p2wsh_expected: script_pubkey.clone(), }); } - let ms = Miniscript::::decode_consensus(witness_script)?; + let witness_script_spk = Script::from_bytes(witness_script.as_bytes()); + let ms = Miniscript::::decode_consensus( + witness_script_spk, + )?; Ok(Descriptor::new_wsh(ms.substitute_raw_pkh(&map))?) } else { Err(InputError::MissingWitnessScript) @@ -219,7 +233,14 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In match inp.redeem_script { None => Err(InputError::MissingRedeemScript), Some(ref redeem_script) => { - if redeem_script.to_p2sh() != *script_pubkey { + let derived_p2sh = + redeem_script + .to_p2sh() + .map_err(|_| InputError::InvalidRedeemScript { + redeem: redeem_script.clone(), + p2sh_expected: script_pubkey.clone(), + })?; + if derived_p2sh != *script_pubkey { return Err(InputError::InvalidRedeemScript { redeem: redeem_script.clone(), p2sh_expected: script_pubkey.clone(), @@ -228,14 +249,25 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In if redeem_script.is_p2wsh() { // 5. `ShWsh` case if let Some(ref witness_script) = inp.witness_script { - if witness_script.to_p2wsh() != *redeem_script { + let derived_p2wsh = + witness_script.to_p2wsh().map_err(|_| { + InputError::InvalidWitnessScript { + witness_script: witness_script.clone(), + p2wsh_expected: ScriptBuf::from_bytes( + redeem_script.to_vec(), + ), + } + })?; + if derived_p2wsh.as_bytes() != redeem_script.as_bytes() { return Err(InputError::InvalidWitnessScript { witness_script: witness_script.clone(), - p2wsh_expected: redeem_script.clone(), + p2wsh_expected: ScriptBuf::from_bytes(redeem_script.to_vec()), }); } + let witness_script_spk = + Script::from_bytes(witness_script.as_bytes()); let ms = Miniscript::::decode_consensus( - witness_script, + witness_script_spk, )?; Ok(Descriptor::new_sh_wsh(ms.substitute_raw_pkh(&map))?) } else { @@ -247,10 +279,10 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In match bitcoin::key::CompressedPublicKey::try_from(pk) { Ok(compressed) => { let addr = bitcoin::Address::p2wpkh( - &compressed, + compressed, bitcoin::Network::Bitcoin, ); - *redeem_script == addr.script_pubkey() + redeem_script.as_bytes() == addr.script_pubkey().as_bytes() } Err(_) => false, } @@ -265,8 +297,10 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In return Err(InputError::NonEmptyWitnessScript); } if let Some(ref redeem_script) = inp.redeem_script { + let redeem_script_spk = + Script::from_bytes(redeem_script.as_bytes()); let ms = Miniscript::::decode_consensus( - redeem_script, + redeem_script_spk, )?; Ok(Descriptor::new_sh(ms)?) } else { @@ -302,15 +336,18 @@ pub fn interpreter_check( let utxos = &Prevouts::All(&utxos); for (index, input) in psbt.inputs.iter().enumerate() { let empty_script_sig = ScriptBuf::new(); + let script_sig_spk = match input.final_script_sig.as_ref() { + Some(sig) => ScriptBuf::from_bytes(sig.to_vec()), + None => empty_script_sig, + }; let empty_witness = Witness::default(); - let script_sig = input.final_script_sig.as_ref().unwrap_or(&empty_script_sig); let witness = input .final_script_witness .as_ref() .map(|wit_slice| Witness::from_slice(&wit_slice.to_vec())) // TODO: Update rust-bitcoin psbt API to use witness .unwrap_or(empty_witness); - interpreter_inp_check(psbt, secp, index, utxos, &witness, script_sig)?; + interpreter_inp_check(psbt, secp, index, utxos, &witness, &script_sig_spk)?; } Ok(()) } @@ -331,7 +368,7 @@ fn interpreter_inp_check>( // Interpreter check { let cltv = psbt.unsigned_tx.lock_time; - let csv = psbt.unsigned_tx.input[index].sequence; + let csv = psbt.unsigned_tx.inputs[index].sequence; let interpreter = interpreter::Interpreter::from_txdata(&spk, script_sig, witness, csv, cltv) .map_err(|e| Error::InputError(InputError::Interpreter(e), index))?; @@ -443,7 +480,7 @@ pub(super) fn finalize_input( input.final_script_sig = if script_sig.is_empty() { None } else { - Some(script_sig) + Some(bitcoin::script::ScriptSigBuf::from_bytes(script_sig.into_bytes())) }; input.final_script_witness = if witness.is_empty() { None diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index 554ca9b36..96f7bcb27 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -12,20 +12,25 @@ use core::fmt; #[cfg(feature = "std")] use std::error; -use bitcoin::hashes::{hash160, sha256d, Hash}; +use bitcoin::hashes::{hash160, sha256d}; use bitcoin::psbt::{self, Psbt}; +use bitcoin::script::{ + RedeemScriptBuf, ScriptExt as _, ScriptPubKeyExt as _, TapScriptBuf, WitnessScriptBuf, + WitnessScriptExt as _, +}; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 use bitcoin::secp256k1; -use bitcoin::secp256k1::{Secp256k1, VerifyOnly}; +use bitcoin::secp256k1::Secp256k1; use bitcoin::sighash::{self, SighashCache}; use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapLeafHash}; -use bitcoin::{absolute, bip32, relative, transaction, Script, ScriptBuf}; +use bitcoin::transaction::TxInExt as _; +use bitcoin::{absolute, bip32, relative, transaction}; use crate::miniscript::context::SigType; use crate::prelude::*; use crate::{ descriptor, interpreter, DefiniteDescriptorKey, Descriptor, DescriptorPublicKey, MiniscriptKey, - Preimage32, Satisfier, ToPublicKey, Translator, + Preimage32, Satisfier, Script, ScriptBuf, ToPublicKey, Translator, }; mod finalizer; @@ -99,14 +104,14 @@ pub enum InputError { /// Redeem script does not match the p2sh hash InvalidRedeemScript { /// Redeem script - redeem: ScriptBuf, + redeem: RedeemScriptBuf, /// Expected p2sh Script p2sh_expected: ScriptBuf, }, /// Witness script does not match the p2wsh hash InvalidWitnessScript { /// Witness Script - witness_script: ScriptBuf, + witness_script: WitnessScriptBuf, /// Expected p2wsh script p2wsh_expected: ScriptBuf, }, @@ -263,7 +268,8 @@ impl<'psbt> PsbtInputSatisfier<'psbt> { impl Satisfier for PsbtInputSatisfier<'_> { fn lookup_tap_key_spend_sig(&self, pk: &Pk) -> Option { if let Some(key) = self.psbt_input().tap_internal_key { - if pk.to_x_only_pubkey() == key { + let pk_xonly: bitcoin::key::XOnlyPublicKey = pk.to_x_only_pubkey().into(); + if pk_xonly == key { return self.psbt_input().tap_key_sig; } } @@ -275,9 +281,10 @@ impl Satisfier for PsbtInputSatisfier<'_> { pk: &Pk, lh: &TapLeafHash, ) -> Option { + let pk_xonly: bitcoin::key::XOnlyPublicKey = pk.to_x_only_pubkey().into(); self.psbt_input() .tap_script_sigs - .get(&(pk.to_x_only_pubkey(), *lh)) + .get(&(pk_xonly, *lh)) .copied() } @@ -291,14 +298,18 @@ impl Satisfier for PsbtInputSatisfier<'_> { fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { - Some(&self.psbt_input().tap_scripts) + ) -> Option<&BTreeMap> { + // The PSBT's `tap_scripts` field uses `TapScriptBuf`, which differs in type + // from the `ScriptBuf` (= `ScriptPubKeyBuf`) required by this trait. We do + // not attempt the conversion here; callers that need access to PSBT tap + // scripts should read `psbt_input().tap_scripts` directly. + None } fn lookup_raw_pkh_tap_leaf_script_sig( &self, pkh: &(hash160::Hash, TapLeafHash), - ) -> Option<(bitcoin::secp256k1::XOnlyPublicKey, bitcoin::taproot::Signature)> { + ) -> Option<(bitcoin::key::XOnlyPublicKey, bitcoin::taproot::Signature)> { self.psbt_input() .tap_script_sigs .iter() @@ -327,7 +338,7 @@ impl Satisfier for PsbtInputSatisfier<'_> { } fn check_after(&self, n: absolute::LockTime) -> bool { - if !self.psbt.unsigned_tx.input[self.index].enables_lock_time() { + if !self.psbt.unsigned_tx.inputs[self.index].enables_lock_time() { return false; } @@ -337,7 +348,7 @@ impl Satisfier for PsbtInputSatisfier<'_> { } fn check_older(&self, n: relative::LockTime) -> bool { - let seq = self.psbt.unsigned_tx.input[self.index].sequence; + let seq = self.psbt.unsigned_tx.inputs[self.index].sequence; if self.psbt.unsigned_tx.version < transaction::Version::TWO || !seq.is_relative_lock_time() { @@ -380,9 +391,9 @@ impl Satisfier for PsbtInputSatisfier<'_> { // rust-bitcoin TODO: (Long term) // Brainstorm about how we can enforce these in type system while having a nice API fn sanity_check(psbt: &Psbt) -> Result<(), Error> { - if psbt.unsigned_tx.input.len() != psbt.inputs.len() { + if psbt.unsigned_tx.inputs.len() != psbt.inputs.len() { return Err(Error::WrongInputCount { - in_tx: psbt.unsigned_tx.input.len(), + in_tx: psbt.unsigned_tx.inputs.len(), in_map: psbt.inputs.len(), }); } @@ -714,10 +725,10 @@ impl PsbtExt for Psbt { } if let Some(witness) = input.final_script_witness.as_ref() { - ret.input[n].witness = witness.clone(); + ret.inputs[n].witness = witness.clone(); } if let Some(script_sig) = input.final_script_sig.as_ref() { - ret.input[n].script_sig = script_sig.clone(); + ret.inputs[n].script_sig = script_sig.clone(); } } interpreter_check(self, secp)?; @@ -736,7 +747,7 @@ impl PsbtExt for Psbt { .ok_or(UtxoUpdateError::IndexOutOfBounds(input_index, n_inputs))?; let txin = self .unsigned_tx - .input + .inputs .get(input_index) .ok_or(UtxoUpdateError::MissingInputUtxo)?; @@ -758,7 +769,7 @@ impl PsbtExt for Psbt { } } (None, Some(non_witness_utxo)) => non_witness_utxo - .output + .outputs .get(txin.previous_output.vout as usize) .ok_or(UtxoUpdateError::UtxoCheck)? .script_pubkey @@ -766,7 +777,7 @@ impl PsbtExt for Psbt { (Some(witness_utxo), Some(non_witness_utxo)) => { if witness_utxo != non_witness_utxo - .output + .outputs .get(txin.previous_output.vout as usize) .ok_or(UtxoUpdateError::UtxoCheck)? { @@ -802,7 +813,7 @@ impl PsbtExt for Psbt { .ok_or(OutputUpdateError::IndexOutOfBounds(output_index, n_outputs))?; let txout = self .unsigned_tx - .output + .outputs .get(output_index) .ok_or(OutputUpdateError::MissingTxOut)?; @@ -860,7 +871,7 @@ impl PsbtExt for Psbt { .map_err(|_e| SighashError::InvalidSighashType)?; let amt = finalizer::get_utxo(self, idx) .map_err(|_e| SighashError::MissingInputUtxo)? - .value; + .amount; let is_nested_wpkh = inp_spk.is_p2sh() && inp .redeem_script @@ -892,12 +903,14 @@ impl PsbtExt for Psbt { Ok(PsbtSighashMsg::SegwitV0Sighash(msg)) } else { // legacy sighash case + let inp_spk_as_redeem; let script_code = if inp_spk.is_p2sh() { inp.redeem_script .as_ref() .ok_or(SighashError::MissingRedeemScript)? } else { - &inp_spk + inp_spk_as_redeem = RedeemScriptBuf::from_bytes(inp_spk.to_vec()); + &inp_spk_as_redeem }; let msg = cache.legacy_signature_hash(idx, script_code, hash_ty.to_u32())?; Ok(PsbtSighashMsg::LegacySighash(msg)) @@ -976,19 +989,16 @@ impl PsbtOutputExt for psbt::Output { // Traverse the pkh lookup while maintaining a reverse map for storing the map // hash160 -> (XonlyPublicKey)/PublicKey -struct KeySourceLookUp( - pub BTreeMap, - pub secp256k1::Secp256k1, -); +struct KeySourceLookUp(pub BTreeMap); impl Translator for KeySourceLookUp { type TargetPk = bitcoin::PublicKey; type Error = core::convert::Infallible; fn pk(&mut self, xpk: &DefiniteDescriptorKey) -> Result { - let derived = xpk.derive_public_key(&self.1); + let derived = xpk.derive_public_key(); self.0.insert( - derived.to_public_key().inner, + derived.to_public_key().to_inner(), ( xpk.master_fingerprint(), xpk.full_derivation_path() @@ -1004,8 +1014,8 @@ impl Translator for KeySourceLookUp { // Provides generalized access to PSBT fields common to inputs and outputs trait PsbtFields { // Common fields are returned as a mutable ref of the same type - fn redeem_script(&mut self) -> &mut Option; - fn witness_script(&mut self) -> &mut Option; + fn redeem_script(&mut self) -> &mut Option; + fn witness_script(&mut self) -> &mut Option; fn bip32_derivation(&mut self) -> &mut BTreeMap; fn tap_internal_key(&mut self) -> &mut Option; fn tap_key_origins( @@ -1020,15 +1030,15 @@ trait PsbtFields { fn tap_tree(&mut self) -> Option<&mut Option> { None } // `tap_scripts` and `tap_merkle_root` only appear in psbt::Input - fn tap_scripts(&mut self) -> Option<&mut BTreeMap> { + fn tap_scripts(&mut self) -> Option<&mut BTreeMap> { None } fn tap_merkle_root(&mut self) -> Option<&mut Option> { None } } impl PsbtFields for psbt::Input { - fn redeem_script(&mut self) -> &mut Option { &mut self.redeem_script } - fn witness_script(&mut self) -> &mut Option { &mut self.witness_script } + fn redeem_script(&mut self) -> &mut Option { &mut self.redeem_script } + fn witness_script(&mut self) -> &mut Option { &mut self.witness_script } fn bip32_derivation(&mut self) -> &mut BTreeMap { &mut self.bip32_derivation } @@ -1047,7 +1057,7 @@ impl PsbtFields for psbt::Input { #[allow(dead_code)] fn unknown(&mut self) -> &mut BTreeMap> { &mut self.unknown } - fn tap_scripts(&mut self) -> Option<&mut BTreeMap> { + fn tap_scripts(&mut self) -> Option<&mut BTreeMap> { Some(&mut self.tap_scripts) } fn tap_merkle_root(&mut self) -> Option<&mut Option> { @@ -1056,8 +1066,8 @@ impl PsbtFields for psbt::Input { } impl PsbtFields for psbt::Output { - fn redeem_script(&mut self) -> &mut Option { &mut self.redeem_script } - fn witness_script(&mut self) -> &mut Option { &mut self.witness_script } + fn redeem_script(&mut self) -> &mut Option { &mut self.redeem_script } + fn witness_script(&mut self) -> &mut Option { &mut self.witness_script } fn bip32_derivation(&mut self) -> &mut BTreeMap { &mut self.bip32_derivation } @@ -1089,11 +1099,9 @@ fn update_item_with_descriptor_helper( // `UtxoUpdateError`, and those callers can't get this error anyway because they pass // `None` for `check_script`. ) -> Result<(Descriptor, bool), descriptor::NonDefiniteKeyError> { - let secp = Secp256k1::verification_only(); - // 1. Derive the descriptor, recording each key derivation in a map from xpubs // the keysource used to derive the key. - let mut bip32_derivation = KeySourceLookUp(BTreeMap::new(), secp); + let mut bip32_derivation = KeySourceLookUp(BTreeMap::new()); let derived = descriptor .translate_pk(&mut bip32_derivation) .map_err(crate::TranslateErr::into_outer_err) @@ -1109,19 +1117,23 @@ fn update_item_with_descriptor_helper( // 3. Update the PSBT fields using the derived key map. if let Descriptor::Tr(ref tr_derived) = &derived { let spend_info = tr_derived.spend_info(); - let KeySourceLookUp(xpub_map, _) = bip32_derivation; + let KeySourceLookUp(xpub_map) = bip32_derivation; *item.tap_internal_key() = Some(spend_info.internal_key()); for (derived_key, key_source) in xpub_map { + let xonly: bitcoin::key::XOnlyPublicKey = derived_key.to_x_only_pubkey().into(); item.tap_key_origins() - .insert(derived_key.to_x_only_pubkey(), (vec![], key_source)); + .insert(xonly, (vec![], key_source)); } if let Some(merkle_root) = item.tap_merkle_root() { *merkle_root = spend_info.merkle_root(); } for leaf_derived in spend_info.leaves() { - let leaf_script = (ScriptBuf::from(leaf_derived.script()), leaf_derived.leaf_version()); + let leaf_script = ( + TapScriptBuf::from_bytes(leaf_derived.script().to_vec()), + leaf_derived.leaf_version(), + ); let tapleaf_hash = leaf_derived.leaf_hash(); if let Some(tap_scripts) = item.tap_scripts() { let control_block = leaf_derived.control_block().clone(); @@ -1129,9 +1141,10 @@ fn update_item_with_descriptor_helper( } for leaf_pk in leaf_derived.miniscript().iter_pk() { + let xonly: bitcoin::key::XOnlyPublicKey = leaf_pk.to_x_only_pubkey().into(); let tapleaf_hashes = &mut item .tap_key_origins() - .get_mut(&leaf_pk.to_x_only_pubkey()) + .get_mut(&xonly) .expect("inserted all keys above") .0; if tapleaf_hashes.last() != Some(&tapleaf_hash) { @@ -1160,13 +1173,27 @@ fn update_item_with_descriptor_helper( Descriptor::Bare(_) | Descriptor::Pkh(_) | Descriptor::Wpkh(_) => {} Descriptor::Sh(sh) => match sh.as_inner() { descriptor::ShInner::Wsh(wsh) => { - *item.witness_script() = Some(wsh.inner_script()); - *item.redeem_script() = Some(wsh.inner_script().to_p2wsh()); + let inner = wsh.inner_script(); + let witness_script = WitnessScriptBuf::from_bytes(inner.to_vec()); + if let Ok(p2wsh_spk) = witness_script.to_p2wsh() { + *item.redeem_script() = + Some(RedeemScriptBuf::from_bytes(p2wsh_spk.into_bytes())); + } + *item.witness_script() = Some(witness_script); + } + descriptor::ShInner::Wpkh(..) => { + *item.redeem_script() = + Some(RedeemScriptBuf::from_bytes(sh.inner_script().into_bytes())) + } + descriptor::ShInner::Ms(_) => { + *item.redeem_script() = + Some(RedeemScriptBuf::from_bytes(sh.inner_script().into_bytes())) } - descriptor::ShInner::Wpkh(..) => *item.redeem_script() = Some(sh.inner_script()), - descriptor::ShInner::Ms(_) => *item.redeem_script() = Some(sh.inner_script()), }, - Descriptor::Wsh(wsh) => *item.witness_script() = Some(wsh.inner_script()), + Descriptor::Wsh(wsh) => { + *item.witness_script() = + Some(WitnessScriptBuf::from_bytes(wsh.inner_script().into_bytes())) + } Descriptor::Tr(_) => unreachable!("Tr is dealt with separately"), } }; @@ -1370,6 +1397,7 @@ mod tests { use bitcoin::bip32::{DerivationPath, Xpub}; use bitcoin::consensus::encode::deserialize; use bitcoin::key::XOnlyPublicKey; + use bitcoin::script::ScriptBufExt as _; use bitcoin::secp256k1::PublicKey; use bitcoin::{Amount, OutPoint, TxIn, TxOut}; use hex; @@ -1527,7 +1555,12 @@ mod tests { psbt_output.update_with_descriptor_unchecked(&desc).unwrap(); assert_eq!(expected_bip32, psbt_input.bip32_derivation); - assert_eq!(psbt_input.witness_script, Some(derived.explicit_script().unwrap())); + assert_eq!( + psbt_input.witness_script, + Some(WitnessScriptBuf::from_bytes( + derived.explicit_script().unwrap().into_bytes() + )) + ); assert_eq!(psbt_output.bip32_derivation, psbt_input.bip32_derivation); assert_eq!(psbt_output.witness_script, psbt_input.witness_script); @@ -1548,7 +1581,12 @@ mod tests { assert_eq!(psbt_input.bip32_derivation, expected_bip32); assert_eq!(psbt_input.witness_script, None); - assert_eq!(psbt_input.redeem_script, Some(derived.explicit_script().unwrap())); + assert_eq!( + psbt_input.redeem_script, + Some(RedeemScriptBuf::from_bytes( + derived.explicit_script().unwrap().into_bytes() + )) + ); assert_eq!(psbt_output.bip32_derivation, psbt_input.bip32_derivation); assert_eq!(psbt_output.witness_script, psbt_input.witness_script); @@ -1564,9 +1602,9 @@ mod tests { let mut non_witness_utxo = bitcoin::Transaction { version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, - input: vec![], - output: vec![TxOut { - value: Amount::from_sat(1_000), + inputs: vec![], + outputs: vec![TxOut { + amount: Amount::from_sat(1_000), script_pubkey: ScriptBuf::from_hex( "5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c", ) @@ -1577,11 +1615,11 @@ mod tests { let tx = bitcoin::Transaction { version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, - input: vec![TxIn { + inputs: vec![TxIn { previous_output: OutPoint { txid: non_witness_utxo.compute_txid(), vout: 0 }, ..Default::default() }], - output: vec![], + outputs: vec![], }; let mut psbt = Psbt::from_unsigned_tx(tx).unwrap(); @@ -1590,7 +1628,7 @@ mod tests { Err(UtxoUpdateError::UtxoCheck), "neither *_utxo are not set" ); - psbt.inputs[0].witness_utxo = Some(non_witness_utxo.output[0].clone()); + psbt.inputs[0].witness_utxo = Some(non_witness_utxo.outputs[0].clone()); assert_eq!( psbt.update_input_with_descriptor(0, &desc), Ok(()), @@ -1626,9 +1664,9 @@ mod tests { let tx = bitcoin::Transaction { version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, - input: vec![], - output: vec![TxOut { - value: Amount::from_sat(1_000), + inputs: vec![], + outputs: vec![TxOut { + amount: Amount::from_sat(1_000), script_pubkey: ScriptBuf::from_hex( "5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c", ) @@ -1647,7 +1685,7 @@ mod tests { Ok(()), "script_pubkey should match" ); - psbt.unsigned_tx.output[0].script_pubkey = ScriptBuf::default(); + psbt.unsigned_tx.outputs[0].script_pubkey = ScriptBuf::default(); assert_eq!( psbt.update_output_with_descriptor(0, &desc), Err(OutputUpdateError::MismatchedScriptPubkey), diff --git a/src/test_utils.rs b/src/test_utils.rs index 9d52b7c25..febece545 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -129,7 +129,7 @@ fn random_sks(n: usize) -> Vec { sk[2] = (i >> 16) as u8; sk[3] = (i >> 24) as u8; - let sk = secp256k1::SecretKey::from_slice(&sk[..]).expect("secret key"); + let sk = secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"); sks.push(sk) } sks @@ -170,8 +170,8 @@ impl StrXOnlyKeyTranslator { .iter() .map(|sk| { let keypair = secp256k1::Keypair::from_secret_key(&secp, sk); - let (pk, _parity) = XOnlyPublicKey::from_keypair(&keypair); - pk + let (pk, _parity) = secp256k1::XOnlyPublicKey::from_keypair(&keypair); + XOnlyPublicKey::from(pk) }) .collect(); let mut pk_map = HashMap::new(); diff --git a/src/util.rs b/src/util.rs index 5de37b780..dab4b028f 100644 --- a/src/util.rs +++ b/src/util.rs @@ -2,16 +2,27 @@ use core::convert::TryFrom; -use bitcoin::constants::MAX_SCRIPT_ELEMENT_SIZE; -use bitcoin::hashes::Hash; -use bitcoin::script::{self, PushBytes, ScriptBuf}; -use bitcoin::PubkeyHash; +use bitcoin::hashes::hash160; +use bitcoin::script::PushBytes; use crate::miniscript::context; +use crate::miniscript::limits::MAX_SCRIPT_ELEMENT_SIZE; use crate::miniscript::satisfy::Placeholder; use crate::prelude::*; -use crate::{MiniscriptKey, ScriptContext, ToPublicKey}; -pub(crate) fn varint_len(n: usize) -> usize { bitcoin::VarInt(n as u64).size() } +use crate::{MiniscriptKey, ScriptBuf, ScriptBuilder, ScriptContext, ToPublicKey}; + +pub(crate) fn varint_len(n: usize) -> usize { + // Equivalent to the CompactSize / VarInt length used by Bitcoin consensus encoding. + if n < 0xFD { + 1 + } else if n <= u16::MAX as usize { + 3 + } else if n <= u32::MAX as usize { + 5 + } else { + 9 + } +} pub(crate) trait ItemSize { fn size(&self) -> usize; @@ -52,10 +63,10 @@ pub(crate) fn witness_size(wit: &[T]) -> usize { } pub(crate) fn witness_to_scriptsig(witness: &[Vec]) -> ScriptBuf { - let mut b = script::Builder::new(); + let mut b = ScriptBuilder::new(); for (i, wit) in witness.iter().enumerate() { - if let Ok(n) = script::read_scriptint(wit) { - b = b.push_int(n); + if let Ok(n) = bitcoin::script::read_scriptint_non_minimal(wit) { + b = b.push_int(n).expect("not i32::MIN"); } else { if i != witness.len() - 1 { assert!(wit.len() < 73, "All pushes in miniscript are < 73 bytes"); @@ -84,14 +95,14 @@ pub(crate) trait MsKeyBuilder { Ctx: ScriptContext; } -impl MsKeyBuilder for script::Builder { +impl MsKeyBuilder for ScriptBuilder { fn push_ms_key(self, key: &Pk) -> Self where Pk: ToPublicKey, Ctx: ScriptContext, { match Ctx::sig_type() { - context::SigType::Ecdsa => self.push_key(&key.to_public_key()), + context::SigType::Ecdsa => self.push_key(key.to_public_key()), context::SigType::Schnorr => self.push_slice(key.to_x_only_pubkey().serialize()), } } @@ -104,7 +115,7 @@ impl MsKeyBuilder for script::Builder { match Ctx::sig_type() { context::SigType::Ecdsa => self.push_slice(key.to_public_key().pubkey_hash()), context::SigType::Schnorr => { - self.push_slice(PubkeyHash::hash(&key.to_x_only_pubkey().serialize())) + self.push_slice(hash160::Hash::hash(&key.to_x_only_pubkey().serialize()).to_byte_array()) } } } From 2b20742fe5b1a8e4e8c531eafda351880d26816e Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 13:20:49 -0600 Subject: [PATCH 03/23] style: cargo +nightly fmt Apply the project's nightly-only rustfmt config to the files touched in the bitcoin 0.33 migration. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/descriptor/key.rs | 11 ++---- src/descriptor/key_map.rs | 10 ++---- src/descriptor/segwitv0.rs | 3 +- src/descriptor/sh.rs | 11 +++--- src/descriptor/tr/spend_info.rs | 9 ++--- src/interpreter/inner.rs | 61 +++++++++++++++++++++++++-------- src/interpreter/mod.rs | 12 +++---- src/interpreter/stack.rs | 4 ++- src/lib.rs | 4 +-- src/miniscript/lex.rs | 21 +++++++++--- src/miniscript/mod.rs | 3 +- src/plan.rs | 20 +++++------ src/psbt/finalizer.rs | 49 +++++++++++--------------- src/psbt/mod.rs | 11 ++---- src/util.rs | 6 ++-- 15 files changed, 123 insertions(+), 112 deletions(-) diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index a6e7e6f57..7e5075917 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -6,11 +6,10 @@ use core::str::FromStr; #[cfg(feature = "std")] use std::error; -use bitcoin::bip32; use bitcoin::hashes::{hash160, ripemd160, sha256, HashEngine}; use bitcoin::key::{PublicKey, XOnlyPublicKey}; use bitcoin::secp256k1::{Secp256k1, Signing}; -use bitcoin::NetworkKind; +use bitcoin::{bip32, NetworkKind}; use super::WalletPolicyError; use crate::prelude::*; @@ -760,15 +759,11 @@ impl DescriptorPublicKey { SinglePubKey::FullKey(pk) => { pk.write_into(&mut engine).expect("engines don't error") } - SinglePubKey::XOnly(x_only_pk) => { - engine.input(&x_only_pk.serialize().0) - } + SinglePubKey::XOnly(x_only_pk) => engine.input(&x_only_pk.serialize().0), }; let hash = hash160::Hash::from_engine(engine); bip32::Fingerprint::from( - &hash.as_byte_array()[..4] - .try_into() - .expect("4 byte slice"), + &hash.as_byte_array()[..4].try_into().expect("4 byte slice"), ) } } diff --git a/src/descriptor/key_map.rs b/src/descriptor/key_map.rs index 942a3658e..572c88e37 100644 --- a/src/descriptor/key_map.rs +++ b/src/descriptor/key_map.rs @@ -102,10 +102,7 @@ impl GetKey for KeyMap { impl GetKey for DescriptorSecretKey { type Error = GetKeyError; - fn get_key( - &self, - key_request: &KeyRequest, - ) -> Result, Self::Error> { + fn get_key(&self, key_request: &KeyRequest) -> Result, Self::Error> { match (self, key_request) { (DescriptorSecretKey::Single(single_priv), key_request) => { let sk = single_priv.key; @@ -126,10 +123,7 @@ impl GetKey for DescriptorSecretKey { Ok(None) } } - ( - DescriptorSecretKey::XPrv(descriptor_xkey), - KeyRequest::Bip32(key_source), - ) => { + (DescriptorSecretKey::XPrv(descriptor_xkey), KeyRequest::Bip32(key_source)) => { if let Some(key) = descriptor_xkey.xkey.get_key(key_request)? { return Ok(Some(key)); } diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index 645e585bd..80533e1ae 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -131,8 +131,7 @@ impl Wsh { /// Obtains the corresponding script pubkey for this descriptor. pub fn address(&self, network: Network) -> Address { let witness_script = WitnessScriptBuf::from(self.ms.encode().into_bytes()); - Address::p2wsh(&witness_script, network) - .expect("witness script size within bounds") + Address::p2wsh(&witness_script, network).expect("witness script size within bounds") } /// Obtains the underlying miniscript for this descriptor. diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index 5de7fe34f..dec366723 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -10,9 +10,7 @@ use core::convert::TryFrom; use core::fmt; -use bitcoin::script::{ - PushBytes, ScriptExt as _, WitnessScriptBuf, WitnessScriptExt as _, -}; +use bitcoin::script::{PushBytes, ScriptExt as _, WitnessScriptBuf, WitnessScriptExt as _}; use bitcoin::{Address, Network, Weight}; use super::{Wpkh, Wsh}; @@ -323,10 +321,9 @@ impl Sh { match self.inner { ShInner::Wsh(ref wsh) => { // wsh explicit must contain exactly 1 element - let witness_script = - WitnessScriptBuf::from(wsh.inner_script().into_bytes()) - .to_p2wsh() - .expect("Witness script is not too large"); + let witness_script = WitnessScriptBuf::from(wsh.inner_script().into_bytes()) + .to_p2wsh() + .expect("Witness script is not too large"); let push_bytes = <&PushBytes>::try_from(witness_script.as_bytes()) .expect("Witness script is not too large"); ScriptBuilder::new().push_slice(push_bytes).into_script() diff --git a/src/descriptor/tr/spend_info.rs b/src/descriptor/tr/spend_info.rs index 2741d4283..ab5776c36 100644 --- a/src/descriptor/tr/spend_info.rs +++ b/src/descriptor/tr/spend_info.rs @@ -69,8 +69,10 @@ impl TrSpendInfo { let depth = usize::from(leaf.depth()); let script = leaf.miniscript().encode(); - let leaf_hash = - TapLeafHash::from_script(TapScript::from_bytes(script.as_bytes()), leaf.leaf_version()); + let leaf_hash = TapLeafHash::from_script( + TapScript::from_bytes(script.as_bytes()), + leaf.leaf_version(), + ); let mut current_hash = TapNodeHash::from(leaf_hash); // 1. If this node increases our depth, add parents. @@ -148,8 +150,7 @@ impl TrSpendInfo { None => vec![], }; - let output_key = - internal_key.tap_tweak(nodes.first().map(|node| node.sibling_hash)); + let output_key = internal_key.tap_tweak(nodes.first().map(|node| node.sibling_hash)); let output_key_parity = output_key.as_x_only_public_key().parity(); TrSpendInfo { internal_key, output_key, output_key_parity, nodes } diff --git a/src/interpreter/inner.rs b/src/interpreter/inner.rs index 45213dee0..77b5147b5 100644 --- a/src/interpreter/inner.rs +++ b/src/interpreter/inner.rs @@ -4,8 +4,8 @@ use bitcoin::hashes::{hash160, sha256}; use bitcoin::key::{PubkeyHash, WPubkeyHash}; use bitcoin::script::{ - ScriptBufExt as _, ScriptExt as _, ScriptHash, ScriptPubKeyBufExt as _, - ScriptPubKeyExt as _, WScriptHash, + ScriptBufExt as _, ScriptExt as _, ScriptHash, ScriptPubKeyBufExt as _, ScriptPubKeyExt as _, + WScriptHash, }; use bitcoin::taproot::{ControlBlock, TAPROOT_ANNEX_PREFIX}; use bitcoin::Witness; @@ -159,11 +159,17 @@ pub(super) fn from_txdata<'txin>( Some(elem) => { let pk = pk_from_stack_elem(&elem, true)?; let hash160 = pk.to_pubkeyhash(SigType::Ecdsa); - if *spk == crate::ScriptBuf::new_p2wpkh(WPubkeyHash::from_byte_array(hash160.to_byte_array())) { + if *spk + == crate::ScriptBuf::new_p2wpkh(WPubkeyHash::from_byte_array( + hash160.to_byte_array(), + )) + { Ok(( Inner::PublicKey(pk.into(), PubkeyType::Wpkh), wit_stack, - Some(crate::ScriptBuf::new_p2pkh(PubkeyHash::from_byte_array(hash160.to_byte_array()))), // bip143, why.. + Some(crate::ScriptBuf::new_p2pkh(PubkeyHash::from_byte_array( + hash160.to_byte_array(), + ))), // bip143, why.. )) } else { Err(Error::IncorrectWPubkeyHash) @@ -183,7 +189,11 @@ pub(super) fn from_txdata<'txin>( let script = miniscript.encode(); let miniscript = miniscript.to_no_checks_ms(); let scripthash = sha256::Hash::hash(script.as_bytes()); - if *spk == crate::ScriptBuf::new_p2wsh(WScriptHash::from_byte_array(scripthash.to_byte_array())) { + if *spk + == crate::ScriptBuf::new_p2wsh(WScriptHash::from_byte_array( + scripthash.to_byte_array(), + )) + { Ok((Inner::Script(miniscript, ScriptType::Wsh), wit_stack, Some(script))) } else { Err(Error::IncorrectWScriptHash) @@ -258,7 +268,11 @@ pub(super) fn from_txdata<'txin>( Some(elem) => { if let stack::Element::Push(slice) = elem { let scripthash = hash160::Hash::hash(slice); - if *spk != crate::ScriptBuf::new_p2sh(ScriptHash::from_byte_array(scripthash.to_byte_array())) { + if *spk + != crate::ScriptBuf::new_p2sh(ScriptHash::from_byte_array( + scripthash.to_byte_array(), + )) + { return Err(Error::IncorrectScriptHash); } // ** p2sh-wrapped wpkh ** @@ -271,13 +285,19 @@ pub(super) fn from_txdata<'txin>( let pk = pk_from_stack_elem(&elem, true)?; let hash160 = pk.to_pubkeyhash(SigType::Ecdsa); if slice - == crate::ScriptBuf::new_p2wpkh(WPubkeyHash::from_byte_array(hash160.to_byte_array())) - .as_bytes() + == crate::ScriptBuf::new_p2wpkh( + WPubkeyHash::from_byte_array(hash160.to_byte_array()), + ) + .as_bytes() { Ok(( Inner::PublicKey(pk.into(), PubkeyType::ShWpkh), wit_stack, - Some(crate::ScriptBuf::new_p2pkh(PubkeyHash::from_byte_array(hash160.to_byte_array()))), // bip143, why.. + Some(crate::ScriptBuf::new_p2pkh( + PubkeyHash::from_byte_array( + hash160.to_byte_array(), + ), + )), // bip143, why.. )) } else { Err(Error::IncorrectWScriptHash) @@ -299,8 +319,12 @@ pub(super) fn from_txdata<'txin>( let miniscript = miniscript.to_no_checks_ms(); let scripthash = sha256::Hash::hash(script.as_bytes()); if slice - == crate::ScriptBuf::new_p2wsh(WScriptHash::from_byte_array(scripthash.to_byte_array())) - .as_bytes() + == crate::ScriptBuf::new_p2wsh( + WScriptHash::from_byte_array( + scripthash.to_byte_array(), + ), + ) + .as_bytes() { Ok(( Inner::Script(miniscript, ScriptType::ShWsh), @@ -322,7 +346,11 @@ pub(super) fn from_txdata<'txin>( let miniscript = miniscript.to_no_checks_ms(); if wit_stack.is_empty() { let scripthash = hash160::Hash::hash(script.as_bytes()); - if *spk == crate::ScriptBuf::new_p2sh(ScriptHash::from_byte_array(scripthash.to_byte_array())) { + if *spk + == crate::ScriptBuf::new_p2sh(ScriptHash::from_byte_array( + scripthash.to_byte_array(), + )) + { Ok((Inner::Script(miniscript, ScriptType::Sh), ssig_stack, Some(script))) } else { Err(Error::IncorrectScriptHash) @@ -467,7 +495,9 @@ mod tests { KeyTestData { pk_spk: ScriptBuf::new_p2pk(key), pkh_spk: ScriptBuf::new_p2pkh(pkhash), - pk_sig: ScriptBuilderLocal::new().push_slice(dummy_sig).into_script(), + pk_sig: ScriptBuilderLocal::new() + .push_slice(dummy_sig) + .into_script(), pkh_sig: ScriptBuilderLocal::new() .push_slice(dummy_sig) .push_key(key) @@ -701,7 +731,10 @@ mod tests { from_txdata(&comp.sh_wpkh_spk, &comp.sh_wpkh_sig, &comp.sh_wpkh_stack) .expect("parse txdata"); assert_eq!(inner, Inner::PublicKey(fixed.pk_comp.into(), PubkeyType::ShWpkh)); - assert_eq!(stack, Stack::from(vec![comp.sh_wpkh_stack.iter().rev().nth(1).unwrap().into()])); + assert_eq!( + stack, + Stack::from(vec![comp.sh_wpkh_stack.iter().rev().nth(1).unwrap().into()]) + ); assert_eq!(script_code, Some(comp.pkh_spk.clone())); } diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index fdd6509dd..367f1cdb0 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -230,9 +230,8 @@ impl<'txin> Interpreter<'txin> { None => return false, }; // TODO: Don't manually handle the script code. - let witness_script = bitcoin::script::WitnessScript::from_bytes( - script_pubkey.as_bytes(), - ); + let witness_script = + bitcoin::script::WitnessScript::from_bytes(script_pubkey.as_bytes()); let sighash = cache.p2wsh_signature_hash( input_idx, witness_script, @@ -264,9 +263,7 @@ impl<'txin> Interpreter<'txin> { "Internal Hack: Saving leaf script instead\ of script code for script spend", ); - let tap_script = bitcoin::script::TapScript::from_bytes( - tap_script.as_bytes(), - ); + let tap_script = bitcoin::script::TapScript::from_bytes(tap_script.as_bytes()); let leaf_hash = taproot::TapLeafHash::from_script( tap_script, taproot::LeafVersion::TapScript, @@ -1096,7 +1093,8 @@ mod tests { sk[2] = (i >> 16) as u8; let sk = secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"); - let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key(&secp, &sk)); + let pk = + bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key(&secp, &sk)); let signature = secp.sign_ecdsa(&msg, &sk); ecdsa_sigs.push(bitcoin::ecdsa::Signature { signature, diff --git a/src/interpreter/stack.rs b/src/interpreter/stack.rs index ee22da361..c5213f166 100644 --- a/src/interpreter/stack.rs +++ b/src/interpreter/stack.rs @@ -154,7 +154,9 @@ impl<'txin> Stack<'txin> { let key: BitcoinKey = match sig_type { SigType::Schnorr => { let arr = <[u8; 32]>::try_from(sl).ok()?; - bitcoin::key::XOnlyPublicKey::from_byte_array(&arr).ok()?.into() + bitcoin::key::XOnlyPublicKey::from_byte_array(&arr) + .ok()? + .into() } SigType::Ecdsa => bitcoin::PublicKey::from_slice(sl).ok()?.into(), }; diff --git a/src/lib.rs b/src/lib.rs index 3baf13b46..508ace16d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -309,9 +309,7 @@ impl ToPublicKey for bitcoin::secp256k1::XOnlyPublicKey { } impl ToPublicKey for bitcoin::XOnlyPublicKey { - fn to_public_key(&self) -> bitcoin::PublicKey { - bitcoin::XOnlyPublicKey::to_public_key(self) - } + fn to_public_key(&self) -> bitcoin::PublicKey { bitcoin::XOnlyPublicKey::to_public_key(self) } fn to_x_only_pubkey(&self) -> bitcoin::secp256k1::XOnlyPublicKey { *self.as_inner() } diff --git a/src/miniscript/lex.rs b/src/miniscript/lex.rs index e1a65e61e..3c0964afd 100644 --- a/src/miniscript/lex.rs +++ b/src/miniscript/lex.rs @@ -227,7 +227,9 @@ pub fn lex(script: &'_ Script) -> Result, Error> { Ok(v) if v >= 0 => { ret.push(Token::Num(v as u32)); } - Ok(n) => return Err(Error::NegativeInt { bytes: bytes.to_owned(), n: n as i64 }), + Ok(n) => { + return Err(Error::NegativeInt { bytes: bytes.to_owned(), n: n as i64 }) + } Err(err) => return Err(Error::InvalidInt { bytes: bytes.to_owned(), err }), } } @@ -321,15 +323,24 @@ impl fmt::Display for Error { Self::InvalidInt { ref bytes, ref err } => { write!(f, "push ")?; fmt_bytes_hex(f, bytes.as_bytes())?; - write!(f, " of length {} is not a key, hash or minimal integer: {}", bytes.len(), err) + write!( + f, + " of length {} is not a key, hash or minimal integer: {}", + bytes.len(), + err + ) + } + Self::InvalidOpcode(ref op) => { + write!(f, "found opcode {} which does not occur in Miniscript", op) } - Self::InvalidOpcode(ref op) => write!(f, "found opcode {} which does not occur in Miniscript", op), Self::NegativeInt { ref bytes, n } => { write!(f, "push ")?; fmt_bytes_hex(f, bytes.as_bytes())?; write!(f, " of length {} parses as a negative number {} which does not occur in Miniscript", bytes.len(), n) - }, - Self::NonMinimalVerify(ref op) => write!(f, "found {} VERIFY (should be one opcode, {}VERIFY)", op, op), + } + Self::NonMinimalVerify(ref op) => { + write!(f, "found {} VERIFY (should be one opcode, {}VERIFY)", op, op) + } } } } diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index f5559ce82..6539f998c 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -1936,7 +1936,8 @@ mod tests { #[test] fn test_script_parse_dos() { - let mut script = crate::ScriptBuilder::new().push_opcode(bitcoin::opcodes::all::OP_PUSHNUM_1); + let mut script = + crate::ScriptBuilder::new().push_opcode(bitcoin::opcodes::all::OP_PUSHNUM_1); for _ in 0..10000 { script = script.push_opcode(bitcoin::opcodes::all::OP_0NOTEQUAL); } diff --git a/src/plan.rs b/src/plan.rs index 01d186252..87f9f0aa6 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -391,10 +391,7 @@ impl Plan { if let (Some(tap_script), Some(control_block)) = (data.tap_script, data.control_block) { input.tap_scripts.insert( control_block, - ( - TapScriptBuf::from_bytes(tap_script.into_bytes()), - LeafVersion::TapScript, - ), + (TapScriptBuf::from_bytes(tap_script.into_bytes()), LeafVersion::TapScript), ); } } else { @@ -415,11 +412,11 @@ impl Plan { Descriptor::Sh(sh) => match sh.as_inner() { descriptor::ShInner::Wsh(wsh) => { let inner = wsh.inner_script(); - let witness_script = - WitnessScriptBuf::from_bytes(inner.to_vec()); - input.redeem_script = witness_script.to_p2wsh().ok().map(|spk| { - RedeemScriptBuf::from_bytes(spk.into_bytes()) - }); + let witness_script = WitnessScriptBuf::from_bytes(inner.to_vec()); + input.redeem_script = witness_script + .to_p2wsh() + .ok() + .map(|spk| RedeemScriptBuf::from_bytes(spk.into_bytes())); input.witness_script = Some(witness_script); } descriptor::ShInner::Wpkh(..) => { @@ -432,9 +429,8 @@ impl Plan { } }, Descriptor::Wsh(wsh) => { - input.witness_script = Some(WitnessScriptBuf::from_bytes( - wsh.inner_script().into_bytes(), - )) + input.witness_script = + Some(WitnessScriptBuf::from_bytes(wsh.inner_script().into_bytes())) } Descriptor::Tr(_) => unreachable!("Tr is dealt with separately"), } diff --git a/src/psbt/finalizer.rs b/src/psbt/finalizer.rs index acc1bacee..235e0eefd 100644 --- a/src/psbt/finalizer.rs +++ b/src/psbt/finalizer.rs @@ -13,9 +13,7 @@ use core::mem; use bitcoin::hashes::hash160; use bitcoin::key::XOnlyPublicKey; -use bitcoin::script::{ - ScriptExt as _, ScriptPubKeyExt as _, WitnessScriptExt as _, -}; +use bitcoin::script::{ScriptExt as _, ScriptPubKeyExt as _, WitnessScriptExt as _}; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 use bitcoin::secp256k1; use bitcoin::secp256k1::Secp256k1; @@ -209,12 +207,13 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In return Err(InputError::NonEmptyRedeemScript); } if let Some(ref witness_script) = inp.witness_script { - let derived = witness_script - .to_p2wsh() - .map_err(|_| InputError::InvalidWitnessScript { - witness_script: witness_script.clone(), - p2wsh_expected: script_pubkey.clone(), - })?; + let derived = + witness_script + .to_p2wsh() + .map_err(|_| InputError::InvalidWitnessScript { + witness_script: witness_script.clone(), + p2wsh_expected: script_pubkey.clone(), + })?; if derived != *script_pubkey { return Err(InputError::InvalidWitnessScript { witness_script: witness_script.clone(), @@ -222,9 +221,8 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In }); } let witness_script_spk = Script::from_bytes(witness_script.as_bytes()); - let ms = Miniscript::::decode_consensus( - witness_script_spk, - )?; + let ms = + Miniscript::::decode_consensus(witness_script_spk)?; Ok(Descriptor::new_wsh(ms.substitute_raw_pkh(&map))?) } else { Err(InputError::MissingWitnessScript) @@ -249,23 +247,19 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In if redeem_script.is_p2wsh() { // 5. `ShWsh` case if let Some(ref witness_script) = inp.witness_script { - let derived_p2wsh = - witness_script.to_p2wsh().map_err(|_| { - InputError::InvalidWitnessScript { - witness_script: witness_script.clone(), - p2wsh_expected: ScriptBuf::from_bytes( - redeem_script.to_vec(), - ), - } - })?; + let derived_p2wsh = witness_script.to_p2wsh().map_err(|_| { + InputError::InvalidWitnessScript { + witness_script: witness_script.clone(), + p2wsh_expected: ScriptBuf::from_bytes(redeem_script.to_vec()), + } + })?; if derived_p2wsh.as_bytes() != redeem_script.as_bytes() { return Err(InputError::InvalidWitnessScript { witness_script: witness_script.clone(), p2wsh_expected: ScriptBuf::from_bytes(redeem_script.to_vec()), }); } - let witness_script_spk = - Script::from_bytes(witness_script.as_bytes()); + let witness_script_spk = Script::from_bytes(witness_script.as_bytes()); let ms = Miniscript::::decode_consensus( witness_script_spk, )?; @@ -278,10 +272,8 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In let partial_sig_contains_pk = inp.partial_sigs.iter().find(|&(&pk, _sig)| { match bitcoin::key::CompressedPublicKey::try_from(pk) { Ok(compressed) => { - let addr = bitcoin::Address::p2wpkh( - compressed, - bitcoin::Network::Bitcoin, - ); + let addr = + bitcoin::Address::p2wpkh(compressed, bitcoin::Network::Bitcoin); redeem_script.as_bytes() == addr.script_pubkey().as_bytes() } Err(_) => false, @@ -297,8 +289,7 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In return Err(InputError::NonEmptyWitnessScript); } if let Some(ref redeem_script) = inp.redeem_script { - let redeem_script_spk = - Script::from_bytes(redeem_script.as_bytes()); + let redeem_script_spk = Script::from_bytes(redeem_script.as_bytes()); let ms = Miniscript::::decode_consensus( redeem_script_spk, )?; diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index 96f7bcb27..7c4775d68 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -1122,8 +1122,7 @@ fn update_item_with_descriptor_helper( *item.tap_internal_key() = Some(spend_info.internal_key()); for (derived_key, key_source) in xpub_map { let xonly: bitcoin::key::XOnlyPublicKey = derived_key.to_x_only_pubkey().into(); - item.tap_key_origins() - .insert(xonly, (vec![], key_source)); + item.tap_key_origins().insert(xonly, (vec![], key_source)); } if let Some(merkle_root) = item.tap_merkle_root() { *merkle_root = spend_info.merkle_root(); @@ -1557,9 +1556,7 @@ mod tests { assert_eq!(expected_bip32, psbt_input.bip32_derivation); assert_eq!( psbt_input.witness_script, - Some(WitnessScriptBuf::from_bytes( - derived.explicit_script().unwrap().into_bytes() - )) + Some(WitnessScriptBuf::from_bytes(derived.explicit_script().unwrap().into_bytes())) ); assert_eq!(psbt_output.bip32_derivation, psbt_input.bip32_derivation); @@ -1583,9 +1580,7 @@ mod tests { assert_eq!(psbt_input.witness_script, None); assert_eq!( psbt_input.redeem_script, - Some(RedeemScriptBuf::from_bytes( - derived.explicit_script().unwrap().into_bytes() - )) + Some(RedeemScriptBuf::from_bytes(derived.explicit_script().unwrap().into_bytes())) ); assert_eq!(psbt_output.bip32_derivation, psbt_input.bip32_derivation); diff --git a/src/util.rs b/src/util.rs index dab4b028f..06d4f07f0 100644 --- a/src/util.rs +++ b/src/util.rs @@ -114,9 +114,9 @@ impl MsKeyBuilder for ScriptBuilder { { match Ctx::sig_type() { context::SigType::Ecdsa => self.push_slice(key.to_public_key().pubkey_hash()), - context::SigType::Schnorr => { - self.push_slice(hash160::Hash::hash(&key.to_x_only_pubkey().serialize()).to_byte_array()) - } + context::SigType::Schnorr => self.push_slice( + hash160::Hash::hash(&key.to_x_only_pubkey().serialize()).to_byte_array(), + ), } } } From 3dab1094acf80f2b138fc203e1c66e21ef25f1b6 Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 13:38:49 -0600 Subject: [PATCH 04/23] bitcoin 0.33: migrate descriptor tests and test_utils MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ports the test modules inside src/descriptor/ and the shared src/test_utils.rs to the bitcoin 0.33.0-beta API surface that landed in the preceding library migration commit. Notable changes: - Drop `&secp` from call sites of the APIs whose secp argument was removed in the library: `PrivateKey::public_key`, `Xpriv::fingerprint`, `Xpriv::derive_priv`, `Xpub::derive_pub`, `GetKey::get_key`, `DescriptorXKey::matches`, `Descriptor::derived_descriptor`, and `Descriptor::find_derivation_index_for_spk`. - Route `ms.encode()` through `WitnessScriptBuf::from(...)` so the new `to_p2wsh` method on the witness-script tagged type resolves. - Replace `bitcoin::ScriptBuf::new()` with the appropriate tagged constructor (`ScriptSigBuf::new()` for scriptSig fields, `ScriptBuf` alias for scriptPubKey). - `bitcoin::OutPoint::default()` → `COINBASE_PREVOUT`. - `PublicKey` field literal / `.inner` accesses rewritten as `PublicKey::from_secp(...)` and `.to_inner()` / `.as_inner()`. - Tap spend-info tests: wrap `to_x_only_pubkey()` (secp type) in `UntweakedPublicKey::from(...)` so `.tap_tweak()` is in scope. - `SecretKey::from_slice(&sk[..])` → `from_secret_bytes(sk)` in test_utils.rs, and drop the secp argument from `Keypair::from_secret_key`. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/descriptor/key.rs | 2 +- src/descriptor/key_map.rs | 56 ++++++++-------- src/descriptor/mod.rs | 109 ++++++++++++++++---------------- src/descriptor/tr/spend_info.rs | 14 ++-- src/test_utils.rs | 6 +- 5 files changed, 93 insertions(+), 94 deletions(-) diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index 7e5075917..58e636996 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -1812,7 +1812,7 @@ mod test { .unwrap(); if let DescriptorSecretKey::Single(single) = secret_key { assert_eq!( - single.key.inner, + *single.key.as_inner(), "0C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D" .parse() .unwrap() diff --git a/src/descriptor/key_map.rs b/src/descriptor/key_map.rs index 572c88e37..60e14396b 100644 --- a/src/descriptor/key_map.rs +++ b/src/descriptor/key_map.rs @@ -189,10 +189,10 @@ mod tests { let descriptor_s = format!("wpkh({})", descriptor_sk_s); let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap(); - let pk = want_sk.public_key(&secp); + let pk = want_sk.public_key(); let request = KeyRequest::Pubkey(pk); let got_sk = keymap - .get_key(request, &secp) + .get_key(&request) .expect("get_key call errored") .expect("failed to find the key"); assert_eq!(got_sk, want_sk) @@ -205,7 +205,7 @@ mod tests { let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"; let xpriv = s.parse::().unwrap(); - let xpriv_fingerprint = xpriv.fingerprint(&secp); + let xpriv_fingerprint = xpriv.fingerprint(); // Sanity check. { @@ -222,10 +222,10 @@ mod tests { let descriptor_s = format!("wpkh([{}]{})", xpriv_fingerprint, xpriv); let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap(); - let pk = want_sk.public_key(&secp); + let pk = want_sk.public_key(); let request = KeyRequest::Pubkey(pk); let got_sk = keymap - .get_key(request, &secp) + .get_key(&request) .expect("get_key call errored") .expect("failed to find the key"); assert_eq!(got_sk, want_sk) @@ -237,10 +237,10 @@ mod tests { let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"; let master = s.parse::().unwrap(); - let master_fingerprint = master.fingerprint(&secp); + let master_fingerprint = master.fingerprint(); let child_number = ChildNumber::from_hardened_idx(44).unwrap(); - let child = master.derive_priv(&secp, &[child_number]).unwrap(); + let child = master.derive_priv(&[child_number][..]).unwrap(); // Sanity check. { @@ -257,10 +257,10 @@ mod tests { let descriptor_s = format!("wpkh({}/44')", s); let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap(); - let pk = want_sk.public_key(&secp); + let pk = want_sk.public_key(); let request = KeyRequest::Pubkey(pk); let got_sk = keymap - .get_key(request, &secp) + .get_key(&request) .expect("get_key call errored") .expect("failed to find the key"); assert_eq!(got_sk, want_sk) @@ -272,12 +272,12 @@ mod tests { let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"; let master = s.parse::().unwrap(); - let master_fingerprint = master.fingerprint(&secp); + let master_fingerprint = master.fingerprint(); let first_external_child = "44'/0'/0'/0/0"; let derivation_path = first_external_child.into_derivation_path().unwrap(); - let child = master.derive_priv(&secp, &derivation_path).unwrap(); + let child = master.derive_priv(&derivation_path).unwrap(); // Sanity check. { @@ -298,7 +298,7 @@ mod tests { let key_source = (master_fingerprint, derivation_path); let request = KeyRequest::Bip32(key_source); let got_sk = keymap - .get_key(request, &secp) + .get_key(&request) .expect("get_key call errored") .expect("failed to find the key"); @@ -321,7 +321,7 @@ mod tests { let expected_deriv_path: DerivationPath = (&[ChildNumber::Normal { index: 0 }][..]).into(); let expected_pk = xpriv .xkey - .derive_priv(&secp, &expected_deriv_path) + .derive_priv(&expected_deriv_path) .unwrap() .to_priv(); @@ -330,7 +330,7 @@ mod tests { let key_request = KeyRequest::Bip32((fp, derivation_path)); let pk = keymap - .get_key(key_request, &secp) + .get_key(&key_request) .expect("get_key should not fail") .expect("get_key should return a `PrivateKey`"); @@ -348,10 +348,10 @@ mod tests { // Request a different public key that doesn't exist in the keymap let different_sk = PrivateKey::from_str("cNJFgo1driFnPcBdBX8BrJrpxchBWXwXCvNH5SoSkdcF6JXXwHMm").unwrap(); - let different_pk = different_sk.public_key(&secp); + let different_pk = different_sk.public_key(); let request = KeyRequest::Pubkey(different_pk); - let result = keymap.get_key(request, &secp).unwrap(); + let result = keymap.get_key(&request).unwrap(); assert!(result.is_none(), "Should return None when no matching key is found"); } @@ -364,10 +364,10 @@ mod tests { // Create an x-only public key request let sk = PrivateKey::from_str("cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij").unwrap(); - let xonly_pk = sk.public_key(&secp).inner.x_only_public_key().0; - let request = KeyRequest::XOnlyPubkey(xonly_pk); + let xonly_pk = sk.public_key().to_inner().x_only_public_key().0; + let request = KeyRequest::XOnlyPubkey(bitcoin::XOnlyPublicKey::from(xonly_pk)); - let result = descriptor_sk.get_key(request.clone(), &secp); + let result = descriptor_sk.get_key(&request); assert!(matches!(result, Err(GetKeyError::NotSupported))); // Also test with KeyMap @@ -377,7 +377,7 @@ mod tests { // While requesting an x-only key from an individual xpriv, that's an error. // But from a keymap, which might have both x-only keys and regular xprivs, // we treat errors as "key not found". - let result = keymap.get_key(request, &secp); + let result = keymap.get_key(&request); assert!(matches!(result, Ok(None))); } @@ -392,29 +392,29 @@ mod tests { let path = DerivationPath::from_str("84'/1'/0'/0").unwrap(); let request = KeyRequest::Bip32((different_fingerprint, path)); - let result = descriptor_sk.get_key(request.clone(), &secp).unwrap(); + let result = descriptor_sk.get_key(&request).unwrap(); assert!(result.is_none(), "Should return None when fingerprint doesn't match"); // Create an x-only public key request -- now we get "not supported". let sk = PrivateKey::from_str("cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij").unwrap(); - let xonly_pk = sk.public_key(&secp).inner.x_only_public_key().0; - let request_x = KeyRequest::XOnlyPubkey(xonly_pk); + let xonly_pk = sk.public_key().to_inner().x_only_public_key().0; + let request_x = KeyRequest::XOnlyPubkey(bitcoin::XOnlyPublicKey::from(xonly_pk)); - let result = descriptor_sk.get_key(request_x.clone(), &secp); + let result = descriptor_sk.get_key(&request_x); assert!(matches!(result, Err(GetKeyError::NotSupported))); // Also test with KeyMap; as in the previous test, the error turns to None. let descriptor_s = "wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/<0;1>/*)"; let (_, keymap) = Descriptor::parse_descriptor(&secp, descriptor_s).unwrap(); - let result = keymap.get_key(request.clone(), &secp).unwrap(); + let result = keymap.get_key(&request).unwrap(); assert!(result.is_none(), "Should return None when fingerprint doesn't match"); - let result = keymap.get_key(request, &secp).unwrap(); + let result = keymap.get_key(&request).unwrap(); assert!(result.is_none(), "Should return None when fingerprint doesn't match"); - let result = descriptor_sk.get_key(request_x.clone(), &secp); + let result = descriptor_sk.get_key(&request_x); assert!(matches!(result, Err(GetKeyError::NotSupported))); - let result = keymap.get_key(request_x, &secp).unwrap(); + let result = keymap.get_key(&request_x).unwrap(); assert!(result.is_none(), "Should return None even on error"); } } diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 8125c158c..582e37255 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -1170,7 +1170,7 @@ mod tests { use bitcoin::blockdata::script::Instruction; use bitcoin::blockdata::{opcodes, script}; use bitcoin::hashes::Hash; - use bitcoin::script::PushBytes; + use bitcoin::script::{PushBytes, ScriptExt as _, WitnessScriptExt as _}; use bitcoin::sighash::EcdsaSighashType; use bitcoin::{bip32, PublicKey, Sequence, XOnlyPublicKey}; @@ -1287,7 +1287,7 @@ mod tests { .unwrap(); assert_eq!( pkh.script_pubkey(), - script::Builder::new() + crate::ScriptBuilder::new() .push_opcode(opcodes::all::OP_DUP) .push_opcode(opcodes::all::OP_HASH160) .push_slice( @@ -1312,7 +1312,7 @@ mod tests { .unwrap(); assert_eq!( wpkh.script_pubkey(), - script::Builder::new() + crate::ScriptBuilder::new() .push_opcode(opcodes::all::OP_PUSHBYTES_0) .push_slice( hash160::Hash::from_str("84e9ed95a38613f0527ff685a9928abe2d4754d4",) @@ -1334,7 +1334,7 @@ mod tests { .unwrap(); assert_eq!( shwpkh.script_pubkey(), - script::Builder::new() + crate::ScriptBuilder::new() .push_opcode(opcodes::all::OP_HASH160) .push_slice( hash160::Hash::from_str("f1c3b9a431134cb90a500ec06e0067cfa9b8bba7",) @@ -1357,7 +1357,7 @@ mod tests { .unwrap(); assert_eq!( sh.script_pubkey(), - script::Builder::new() + crate::ScriptBuilder::new() .push_opcode(opcodes::all::OP_HASH160) .push_slice( hash160::Hash::from_str("aa5282151694d3f2f32ace7d00ad38f927a33ac8",) @@ -1380,7 +1380,7 @@ mod tests { .unwrap(); assert_eq!( wsh.script_pubkey(), - script::Builder::new() + crate::ScriptBuilder::new() .push_opcode(opcodes::all::OP_PUSHBYTES_0) .push_slice( sha256::Hash::from_str( @@ -1407,7 +1407,7 @@ mod tests { .unwrap(); assert_eq!( shwsh.script_pubkey(), - script::Builder::new() + crate::ScriptBuilder::new() .push_opcode(opcodes::all::OP_HASH160) .push_slice( hash160::Hash::from_str("4bec5d7feeed99e1d0a23fe32a4afe126a7ff07e",) @@ -1426,12 +1426,14 @@ mod tests { #[test] fn satisfy() { let secp = secp256k1::Secp256k1::new(); - let sk = - secp256k1::SecretKey::from_slice(&b"sally was a secret key, she said"[..]).unwrap(); - let pk = bitcoin::PublicKey::new(secp256k1::PublicKey::from_secret_key(&secp, &sk)); - let msg = secp256k1::Message::from_digest_slice(&b"michael was a message, amusingly"[..]) - .expect("32 bytes"); - let sig = secp.sign_ecdsa(&msg, &sk); + let mut sk_bytes = [0u8; 32]; + sk_bytes.copy_from_slice(&b"sally was a secret key, she said"[..]); + let sk = secp256k1::SecretKey::from_secret_bytes(sk_bytes).unwrap(); + let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key(&sk)); + let mut msg_bytes = [0u8; 32]; + msg_bytes.copy_from_slice(&b"michael was a message, amusingly"[..]); + let msg = secp256k1::Message::from_digest(msg_bytes); + let sig = secp.sign_ecdsa(msg, &sk); let mut sigser = sig.serialize_der().to_vec(); sigser.push(0x01); // sighash_all @@ -1460,8 +1462,8 @@ mod tests { let ms = ms_str!("c:pk_k({})", pk); let mut txin = bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: bitcoin::ScriptBuf::new(), + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::ScriptSigBuf::new(), sequence: Sequence::from_height(100), witness: Witness::default(), }; @@ -1471,48 +1473,48 @@ mod tests { assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: script::Builder::new() + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::script::Builder::::new() .push_slice(<&PushBytes>::try_from(sigser.as_slice()).unwrap()) .into_script(), sequence: Sequence::from_height(100), witness: Witness::default(), } ); - assert_eq!(bare.unsigned_script_sig(), bitcoin::ScriptBuf::new()); + assert_eq!(bare.unsigned_script_sig(), ScriptBuf::new()); let pkh = Descriptor::new_pkh(pk).unwrap(); pkh.satisfy(&mut txin, &satisfier).expect("satisfaction"); assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: script::Builder::new() + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::script::Builder::::new() .push_slice(<&PushBytes>::try_from(sigser.as_slice()).unwrap()) - .push_key(&pk) + .push_key(pk) .into_script(), sequence: Sequence::from_height(100), witness: Witness::default(), } ); - assert_eq!(pkh.unsigned_script_sig(), bitcoin::ScriptBuf::new()); + assert_eq!(pkh.unsigned_script_sig(), ScriptBuf::new()); let wpkh = Descriptor::new_wpkh(pk).unwrap(); wpkh.satisfy(&mut txin, &satisfier).expect("satisfaction"); assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: bitcoin::ScriptBuf::new(), + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::ScriptSigBuf::new(), sequence: Sequence::from_height(100), witness: Witness::from_slice(&[sigser.clone(), pk.to_bytes()]), } ); - assert_eq!(wpkh.unsigned_script_sig(), bitcoin::ScriptBuf::new()); + assert_eq!(wpkh.unsigned_script_sig(), ScriptBuf::new()); let shwpkh = Descriptor::new_sh_wpkh(pk).unwrap(); shwpkh.satisfy(&mut txin, &satisfier).expect("satisfaction"); - let redeem_script = script::Builder::new() + let redeem_script = crate::ScriptBuilder::new() .push_opcode(opcodes::all::OP_PUSHBYTES_0) .push_slice( hash160::Hash::from_str("d1b2a1faf62e73460af885c687dee3b7189cd8ab") @@ -1523,8 +1525,8 @@ mod tests { assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: script::Builder::new() + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::script::Builder::::new() .push_slice(<&PushBytes>::try_from(redeem_script.as_bytes()).unwrap()) .into_script(), sequence: Sequence::from_height(100), @@ -1533,7 +1535,7 @@ mod tests { ); assert_eq!( shwpkh.unsigned_script_sig(), - script::Builder::new() + crate::ScriptBuilder::new() .push_slice(<&PushBytes>::try_from(redeem_script.as_bytes()).unwrap()) .into_script() ); @@ -1544,8 +1546,8 @@ mod tests { assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: script::Builder::new() + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::script::Builder::::new() .push_slice(<&PushBytes>::try_from(sigser.as_slice()).unwrap()) .push_slice(<&PushBytes>::try_from(ms.encode().as_bytes()).unwrap()) .into_script(), @@ -1553,7 +1555,7 @@ mod tests { witness: Witness::default(), } ); - assert_eq!(sh.unsigned_script_sig(), bitcoin::ScriptBuf::new()); + assert_eq!(sh.unsigned_script_sig(), ScriptBuf::new()); let ms = ms_str!("c:pk_k({})", pk); @@ -1562,22 +1564,22 @@ mod tests { assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: bitcoin::ScriptBuf::new(), + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::ScriptSigBuf::new(), sequence: Sequence::from_height(100), witness: Witness::from_slice(&[sigser.clone(), ms.encode().into_bytes()]), } ); - assert_eq!(wsh.unsigned_script_sig(), bitcoin::ScriptBuf::new()); + assert_eq!(wsh.unsigned_script_sig(), ScriptBuf::new()); let shwsh = Descriptor::new_sh_wsh(ms.clone()).unwrap(); shwsh.satisfy(&mut txin, &satisfier).expect("satisfaction"); assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: script::Builder::new() - .push_slice(<&PushBytes>::try_from(ms.encode().to_p2wsh().as_bytes()).unwrap()) + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::script::Builder::::new() + .push_slice(<&PushBytes>::try_from(bitcoin::WitnessScriptBuf::from(ms.encode().into_bytes()).to_p2wsh().unwrap().as_bytes()).unwrap()) .into_script(), sequence: Sequence::from_height(100), witness: Witness::from_slice(&[sigser.clone(), ms.encode().into_bytes()]), @@ -1585,8 +1587,8 @@ mod tests { ); assert_eq!( shwsh.unsigned_script_sig(), - script::Builder::new() - .push_slice(<&PushBytes>::try_from(ms.encode().to_p2wsh().as_bytes()).unwrap()) + crate::ScriptBuilder::new() + .push_slice(<&PushBytes>::try_from(bitcoin::WitnessScriptBuf::from(ms.encode().into_bytes()).to_p2wsh().unwrap().as_bytes()).unwrap()) .into_script() ); } @@ -1722,8 +1724,8 @@ mod tests { .unwrap(); let mut txin = bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: bitcoin::ScriptBuf::new(), + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::ScriptSigBuf::new(), sequence: Sequence::ZERO, witness: Witness::default(), }; @@ -1930,13 +1932,13 @@ mod tests { let addr_one = desc_one .derive_at_index(index) .unwrap() - .derived_descriptor(&secp_ctx) + .derived_descriptor() .address(bitcoin::Network::Bitcoin) .unwrap(); let addr_two = desc_two .derive_at_index(index) .unwrap() - .derived_descriptor(&secp_ctx) + .derived_descriptor() .address(bitcoin::Network::Bitcoin) .unwrap(); let addr_expected = bitcoin::Address::from_str(raw_addr_expected) @@ -1961,7 +1963,7 @@ mod tests { let desc = Descriptor::::from_str(desc_str).unwrap(); assert_eq!(desc.to_string(), desc_str); let addr = desc - .derived_descriptor(&secp_ctx) + .derived_descriptor() .address(bitcoin::Network::Bitcoin) .unwrap(); assert_eq!(addr, addr_expected); @@ -1983,7 +1985,7 @@ mod tests { let desc = Descriptor::::from_str(desc_str).unwrap(); assert_eq!(desc.to_string(), desc_str); let addr = desc - .derived_descriptor(&secp_ctx) + .derived_descriptor() .address(bitcoin::Network::Bitcoin) .unwrap(); assert_eq!(addr, addr_expected); @@ -2101,24 +2103,23 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))"; #[test] fn test_find_derivation_index_for_spk() { - let secp = secp256k1::Secp256k1::verification_only(); let descriptor = Descriptor::from_str("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)").unwrap(); - let script_at_0_1 = ScriptBuf::from_hex( - "5120a82f29944d65b86ae6b5e5cc75e294ead6c59391a1edc5e016e3498c67fc7bbb", - ) - .unwrap(); + let script_at_0_1 = ScriptBuf::from_bytes( + hex::decode_to_vec("5120a82f29944d65b86ae6b5e5cc75e294ead6c59391a1edc5e016e3498c67fc7bbb") + .unwrap(), + ); let expected_concrete = Descriptor::from_str( "tr(0283dfe85a3151d2517290da461fe2815591ef69f2b18a2ce63f01697a8b313145)", ) .unwrap(); - assert_eq!(descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..1), Ok(None)); + assert_eq!(descriptor.find_derivation_index_for_spk(&script_at_0_1, 0..1), Ok(None)); assert_eq!( - descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..2), + descriptor.find_derivation_index_for_spk(&script_at_0_1, 0..2), Ok(Some((1, expected_concrete.clone()))) ); assert_eq!( - descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..10), + descriptor.find_derivation_index_for_spk(&script_at_0_1, 0..10), Ok(Some((1, expected_concrete))) ); } diff --git a/src/descriptor/tr/spend_info.rs b/src/descriptor/tr/spend_info.rs index ab5776c36..16030ab6e 100644 --- a/src/descriptor/tr/spend_info.rs +++ b/src/descriptor/tr/spend_info.rs @@ -394,7 +394,7 @@ mod tests { // Empty tree let merkle_root = None; - let internal_key = pk.to_x_only_pubkey(); + let internal_key = UntweakedPublicKey::from(pk.to_x_only_pubkey()); let output_key = internal_key.tap_tweak(merkle_root); let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( @@ -405,7 +405,7 @@ mod tests { // Single-leaf tree let merkle_root = Some(TapNodeHash::from(zero_hash)); - let internal_key = pk.to_x_only_pubkey(); + let internal_key = UntweakedPublicKey::from(pk.to_x_only_pubkey()); let output_key = internal_key.tap_tweak(merkle_root); let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( @@ -423,7 +423,7 @@ mod tests { .parse() .unwrap(), ); - let internal_key = pk.to_x_only_pubkey(); + let internal_key = UntweakedPublicKey::from(pk.to_x_only_pubkey()); let output_key = internal_key.tap_tweak(merkle_root); let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( @@ -449,7 +449,7 @@ mod tests { .parse() .unwrap(), ); - let internal_key = pk.to_x_only_pubkey(); + let internal_key = UntweakedPublicKey::from(pk.to_x_only_pubkey()); let output_key = internal_key.tap_tweak(merkle_root); let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( @@ -475,7 +475,7 @@ mod tests { .parse() .unwrap(), ); - let internal_key = pk.to_x_only_pubkey(); + let internal_key = UntweakedPublicKey::from(pk.to_x_only_pubkey()); let output_key = internal_key.tap_tweak(merkle_root); let output_key_parity = output_key.as_x_only_public_key().parity(); @@ -521,7 +521,7 @@ mod tests { .parse() .unwrap(), ); - let internal_key = pk.to_x_only_pubkey(); + let internal_key = UntweakedPublicKey::from(pk.to_x_only_pubkey()); let output_key = internal_key.tap_tweak(merkle_root); let output_key_parity = output_key.as_x_only_public_key().parity(); @@ -573,7 +573,7 @@ mod tests { .parse() .unwrap(), ); - let internal_key = pk.to_x_only_pubkey(); + let internal_key = UntweakedPublicKey::from(pk.to_x_only_pubkey()); let output_key = internal_key.tap_tweak(merkle_root); let output_key_parity = output_key.as_x_only_public_key().parity(); diff --git a/src/test_utils.rs b/src/test_utils.rs index febece545..0ac3992f7 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -137,11 +137,10 @@ fn random_sks(n: usize) -> Vec { impl StrKeyTranslator { pub fn new() -> Self { - let secp = secp256k1::Secp256k1::new(); let sks = random_sks(26); let pks: Vec<_> = sks .iter() - .map(|sk| bitcoin::PublicKey::new(secp256k1::PublicKey::from_secret_key(&secp, sk))) + .map(|sk| bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key(sk))) .collect(); let mut pk_map = HashMap::new(); let mut pkh_map = HashMap::new(); @@ -164,12 +163,11 @@ impl StrKeyTranslator { impl StrXOnlyKeyTranslator { pub fn new() -> Self { - let secp = secp256k1::Secp256k1::new(); let sks = random_sks(26); let pks: Vec<_> = sks .iter() .map(|sk| { - let keypair = secp256k1::Keypair::from_secret_key(&secp, sk); + let keypair = secp256k1::Keypair::from_secret_key(sk); let (pk, _parity) = secp256k1::XOnlyPublicKey::from_keypair(&keypair); XOnlyPublicKey::from(pk) }) From 0326000c3a6b65e5898e659c955bd1ac6b9bef64 Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 13:42:09 -0600 Subject: [PATCH 05/23] bitcoin 0.33: migrate examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ports every file under `examples/` to the bitcoin 0.33.0-beta API (transaction/txout field renames, tagged scripts, PublicKey accessor methods, secp-less key/descriptor APIs, etc). - `Transaction.input/.output` → `.inputs/.outputs`; `TxOut.value` → `.amount` (wrapping the new `Amount::from_sat` Result); `OutPoint::default()` → `OutPoint::COINBASE_PREVOUT`; `TxIn { ..Default::default() }` → explicit field form. - `bitcoin::ScriptBuf::new()` → `bitcoin::ScriptSigBuf::new()` for scriptSig fields, `miniscript::ScriptBuf::new()` for scriptPubKey. - `pk.inner` / `pk.public_key(&secp)` → `pk.to_inner()` / `pk.public_key()`; construct via `PublicKey::from_secp(...)`. - `Descriptor::derived_descriptor` no longer takes `&secp` — drop at call sites in `xpub_descriptors.rs`. - `Keypair::new(&secp, rng)` → `bitcoin::Keypair::from_secp( secp256k1::Keypair::new(&mut rand::rng()))`; `XOnlyPublicKey::from_slice` → `from_byte_array` + `.into()`; `XOnlyPublicKey::from_keypair` now returns the key directly. - `bitcoin::hex::{Case, DisplayHex}` → `bitcoin::hashes::hex::prelude:: DisplayHex` and `to_lower_hex_string()`. - `LockTime::from_time` (deprecated) → `from_mtp` in `taptree_of_horror`. - `message` passed owned (not `&message`) into `Secp256k1::verify_ecdsa` since `&Message` no longer auto-converts. All example binaries now compile with `cargo check --examples` (deprecation warnings for `sign_ecdsa`/`verify_ecdsa` remain — those are API changes to follow up on separately). Co-Authored-By: Claude Opus 4.7 (1M context) --- examples/big.rs | 2 +- examples/psbt_sign_finalize.rs | 53 ++++++++++--------- examples/sign_multisig.rs | 37 ++++++------- examples/taproot.rs | 10 ++-- examples/taptree_of_horror/helper_fns.rs | 2 +- .../taptree_of_horror/taptree_of_horror.rs | 43 +++++++-------- examples/verify_tx.rs | 13 +++-- examples/xpub_descriptors.rs | 6 +-- 8 files changed, 87 insertions(+), 79 deletions(-) diff --git a/examples/big.rs b/examples/big.rs index a5057937b..1015d3284 100644 --- a/examples/big.rs +++ b/examples/big.rs @@ -58,7 +58,7 @@ fn main() { let d = miniscript::Descriptor::::from_str(&i).unwrap(); let sigs = HashMap::::new(); - d.satisfy(&mut tx.input[0], &sigs).unwrap(); + d.satisfy(&mut tx.inputs[0], &sigs).unwrap(); let pol = Concrete::::from_str(&i).unwrap(); let desc = pol.compile_tr(Some("UNSPENDABLE_KEY".to_string())).unwrap(); diff --git a/examples/psbt_sign_finalize.rs b/examples/psbt_sign_finalize.rs index 29bf8bc4e..82f23c123 100644 --- a/examples/psbt_sign_finalize.rs +++ b/examples/psbt_sign_finalize.rs @@ -8,9 +8,11 @@ use miniscript::bitcoin::psbt::{self, Psbt}; use miniscript::bitcoin::sighash::SighashCache; //use miniscript::bitcoin::secp256k1; // https://github.com/rust-lang/rust/issues/121684 use miniscript::bitcoin::{ - transaction, Address, Amount, Network, OutPoint, PrivateKey, Script, Sequence, Transaction, + transaction, Address, Amount, Network, OutPoint, PrivateKey, Sequence, Transaction, TxIn, TxOut, }; +use miniscript::bitcoin::ScriptPubKey; +use miniscript::bitcoin::blockdata::witness::Witness; use miniscript::psbt::{PsbtExt, PsbtInputExt}; use miniscript::Descriptor; @@ -31,31 +33,31 @@ fn main() { let master_private_key_str = "cQhdvB3McbBJdx78VSSumqoHQiSXs75qwLptqwxSQBNBMDxafvaw"; let _master_private_key = PrivateKey::from_str(master_private_key_str).expect("Can't create private key"); - println!("Master public key: {}", _master_private_key.public_key(&secp256k1)); + println!("Master public key: {}", _master_private_key.public_key()); let backup1_private_key_str = "cWA34TkfWyHa3d4Vb2jNQvsWJGAHdCTNH73Rht7kAz6vQJcassky"; let backup1_private = PrivateKey::from_str(backup1_private_key_str).expect("Can't create private key"); - println!("Backup1 public key: {}", backup1_private.public_key(&secp256k1)); + println!("Backup1 public key: {}", backup1_private.public_key()); let backup2_private_key_str = "cPJFWUKk8sdL7pcDKrmNiWUyqgovimmhaaZ8WwsByDaJ45qLREkh"; let backup2_private = PrivateKey::from_str(backup2_private_key_str).expect("Can't create private key"); - println!("Backup2 public key: {}", backup2_private.public_key(&secp256k1)); + println!("Backup2 public key: {}", backup2_private.public_key()); let backup3_private_key_str = "cT5cH9UVm81W5QAf5KABXb23RKNSMbMzMx85y6R2mF42L94YwKX6"; let _backup3_private = PrivateKey::from_str(backup3_private_key_str).expect("Can't create private key"); - println!("Backup3 public key: {}", _backup3_private.public_key(&secp256k1)); + println!("Backup3 public key: {}", _backup3_private.public_key()); let spend_tx = Transaction { version: transaction::Version::TWO, lock_time: bitcoin::absolute::LockTime::from_consensus(5000), - input: vec![], - output: vec![], + inputs: vec![], + outputs: vec![], }; // Spend one input and spend one output for simplicity. @@ -82,19 +84,20 @@ fn main() { let txin = TxIn { previous_output: outpoint, + script_sig: bitcoin::ScriptSigBuf::new(), sequence: Sequence::from_height(26), - ..Default::default() + witness: Witness::default(), }; - psbt.unsigned_tx.input.push(txin); + psbt.unsigned_tx.inputs.push(txin); - psbt.unsigned_tx.output.push(TxOut { + psbt.unsigned_tx.outputs.push(TxOut { script_pubkey: receiver.script_pubkey(), - value: Amount::from_sat(amount / 5 - 500), + amount: Amount::from_sat(amount / 5 - 500).expect("in range"), }); - psbt.unsigned_tx.output.push(TxOut { + psbt.unsigned_tx.outputs.push(TxOut { script_pubkey: bridge_descriptor.script_pubkey(), - value: Amount::from_sat(amount * 4 / 5), + amount: Amount::from_sat(amount * 4 / 5).expect("in range"), }); // Generating signatures & witness data @@ -118,18 +121,18 @@ fn main() { // Fixme: Take a parameter let hash_ty = bitcoin::sighash::EcdsaSighashType::All; - let sk1 = backup1_private.inner; - let sk2 = backup2_private.inner; + let sk1 = *backup1_private.as_inner(); + let sk2 = *backup2_private.as_inner(); // Finally construct the signature and add to psbt - let sig1 = secp256k1.sign_ecdsa(&msg, &sk1); - let pk1 = backup1_private.public_key(&secp256k1); - assert!(secp256k1.verify_ecdsa(&msg, &sig1, &pk1.inner).is_ok()); + let sig1 = secp256k1.sign_ecdsa(msg, &sk1); + let pk1 = backup1_private.public_key(); + assert!(secp256k1.verify_ecdsa(msg, &sig1, &pk1.to_inner()).is_ok()); // Second key just in case - let sig2 = secp256k1.sign_ecdsa(&msg, &sk2); - let pk2 = backup2_private.public_key(&secp256k1); - assert!(secp256k1.verify_ecdsa(&msg, &sig2, &pk2.inner).is_ok()); + let sig2 = secp256k1.sign_ecdsa(msg, &sk2); + let pk2 = backup2_private.public_key(); + assert!(secp256k1.verify_ecdsa(msg, &sig2, &pk2.to_inner()).is_ok()); psbt.inputs[0] .partial_sigs @@ -146,10 +149,10 @@ fn main() { } // Find the Outpoint by spk -fn get_vout(tx: &Transaction, spk: &Script) -> (OutPoint, TxOut) { - for (i, txout) in tx.clone().output.into_iter().enumerate() { - if spk == &txout.script_pubkey { - return (OutPoint::new(tx.compute_txid(), i as u32), txout); +fn get_vout(tx: &Transaction, spk: &ScriptPubKey) -> (OutPoint, TxOut) { + for (i, txout) in tx.clone().outputs.into_iter().enumerate() { + if spk == AsRef::::as_ref(&txout.script_pubkey) { + return (OutPoint { txid: tx.compute_txid(), vout: i as u32 }, txout); } } panic!("Only call get vout on functions which have the expected outpoint"); diff --git a/examples/sign_multisig.rs b/examples/sign_multisig.rs index b1117c102..e10cd3e1c 100644 --- a/examples/sign_multisig.rs +++ b/examples/sign_multisig.rs @@ -6,7 +6,8 @@ use std::collections::HashMap; use std::str::FromStr; use bitcoin::blockdata::witness::Witness; -use bitcoin::{absolute, ecdsa, transaction, Amount, Sequence}; +use bitcoin::{absolute, ecdsa, transaction, Amount, OutPoint, Sequence}; +use miniscript::ScriptBuf; fn main() { let mut tx = spending_transaction(); @@ -49,30 +50,30 @@ fn main() { ); // Attempt to satisfy at age 0, height 0. - let original_txin = tx.input[0].clone(); + let original_txin = tx.inputs[0].clone(); let mut sigs = HashMap::::new(); // Doesn't work with no signatures. - assert!(descriptor.satisfy(&mut tx.input[0], &sigs).is_err()); - assert_eq!(tx.input[0], original_txin); + assert!(descriptor.satisfy(&mut tx.inputs[0], &sigs).is_err()); + assert_eq!(tx.inputs[0], original_txin); // ...or one signature... sigs.insert(pks[1], sig); - assert!(descriptor.satisfy(&mut tx.input[0], &sigs).is_err()); - assert_eq!(tx.input[0], original_txin); + assert!(descriptor.satisfy(&mut tx.inputs[0], &sigs).is_err()); + assert_eq!(tx.inputs[0], original_txin); // ...but two signatures is ok. sigs.insert(pks[2], sig); - assert!(descriptor.satisfy(&mut tx.input[0], &sigs).is_ok()); - assert_ne!(tx.input[0], original_txin); - assert_eq!(tx.input[0].witness.len(), 4); // 0, sig, sig, witness script + assert!(descriptor.satisfy(&mut tx.inputs[0], &sigs).is_ok()); + assert_ne!(tx.inputs[0], original_txin); + assert_eq!(tx.inputs[0].witness.len(), 4); // 0, sig, sig, witness script // ...and even if we give it a third signature, only two are used. sigs.insert(pks[0], sig); - assert!(descriptor.satisfy(&mut tx.input[0], &sigs).is_ok()); - assert_ne!(tx.input[0], original_txin); - assert_eq!(tx.input[0].witness.len(), 4); // 0, sig, sig, witness script + assert!(descriptor.satisfy(&mut tx.inputs[0], &sigs).is_ok()); + assert_ne!(tx.inputs[0], original_txin); + assert_eq!(tx.inputs[0].witness.len(), 4); // 0, sig, sig, witness script } // Transaction which spends some output. @@ -80,15 +81,15 @@ fn spending_transaction() -> bitcoin::Transaction { bitcoin::Transaction { version: transaction::Version::TWO, lock_time: absolute::LockTime::ZERO, - input: vec![bitcoin::TxIn { - previous_output: Default::default(), - script_sig: bitcoin::ScriptBuf::new(), + inputs: vec![bitcoin::TxIn { + previous_output: OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::ScriptSigBuf::new(), sequence: Sequence::MAX, witness: Witness::default(), }], - output: vec![bitcoin::TxOut { - script_pubkey: bitcoin::ScriptBuf::new(), - value: Amount::from_sat(100_000_000), + outputs: vec![bitcoin::TxOut { + script_pubkey: ScriptBuf::new(), + amount: Amount::from_sat(100_000_000).expect("in range"), }], } } diff --git a/examples/taproot.rs b/examples/taproot.rs index aea13f6ce..534413ab5 100644 --- a/examples/taproot.rs +++ b/examples/taproot.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use std::str::FromStr; use miniscript::bitcoin::key::{Keypair, XOnlyPublicKey}; -use miniscript::bitcoin::secp256k1::rand; +use miniscript::bitcoin::secp256k1::{self, rand}; use miniscript::bitcoin::{Network, WitnessVersion}; use miniscript::descriptor::DescriptorType; use miniscript::policy::Concrete; @@ -86,10 +86,10 @@ fn main() { let mut pk_map = HashMap::new(); // We require secp for generating a random XOnlyPublicKey - let secp = secp256k1::Secp256k1::new(); - let key_pair = Keypair::new(&secp, &mut rand::thread_rng()); + let _secp = secp256k1::Secp256k1::new(); + let key_pair = Keypair::from_secp(secp256k1::Keypair::new(&mut rand::rng())); // Random unspendable XOnlyPublicKey provided for compilation to Taproot Descriptor - let (unspendable_pubkey, _parity) = XOnlyPublicKey::from_keypair(&key_pair); + let unspendable_pubkey = XOnlyPublicKey::from_keypair(&key_pair); pk_map.insert("UNSPENDABLE_KEY".to_string(), unspendable_pubkey); let pubkeys = hardcoded_xonlypubkeys(); @@ -142,7 +142,7 @@ fn hardcoded_xonlypubkeys() -> Vec { ]; let mut keys: Vec = vec![]; for key in serialized_keys { - keys.push(XOnlyPublicKey::from_slice(&key).unwrap()); + keys.push(secp256k1::XOnlyPublicKey::from_byte_array(key).unwrap().into()); } keys } diff --git a/examples/taptree_of_horror/helper_fns.rs b/examples/taptree_of_horror/helper_fns.rs index d0ca62dad..9834ea1f0 100644 --- a/examples/taptree_of_horror/helper_fns.rs +++ b/examples/taptree_of_horror/helper_fns.rs @@ -50,7 +50,7 @@ pub fn produce_key_pairs( let derivation_with_index = format!("{}/{}", derivation_without_index, i); let derivation_path = DerivationPath::from_str(&derivation_with_index).unwrap(); - let derived_xpriv: Xpriv = xprv.xkey.derive_priv(secp, &derivation_path).unwrap(); + let derived_xpriv: Xpriv = xprv.xkey.derive_priv(&derivation_path).unwrap(); pks.push(pk); prvs.push(derived_xpriv); diff --git a/examples/taptree_of_horror/taptree_of_horror.rs b/examples/taptree_of_horror/taptree_of_horror.rs index 5248bb689..fa7bc70cb 100644 --- a/examples/taptree_of_horror/taptree_of_horror.rs +++ b/examples/taptree_of_horror/taptree_of_horror.rs @@ -3,9 +3,10 @@ use std::str::FromStr; use bitcoin::absolute::LockTime; use bitcoin::consensus::encode::serialize; use bitcoin::hashes::Hash; -use bitcoin::hex::{Case, DisplayHex}; +use bitcoin::hashes::hex::prelude::DisplayHex; use bitcoin::transaction::Version; use bitcoin::{Address, Amount, Network, Psbt, PublicKey, Sequence, TxIn, TxOut}; +use bitcoin::blockdata::witness::Witness; use helper_fns::{produce_grim_hash, produce_kelly_hash, produce_key_pairs}; use miniscript::descriptor::DescriptorSecretKey; use miniscript::policy::Concrete; @@ -211,20 +212,20 @@ fn main() { .unwrap(), vout: 0, }, + script_sig: bitcoin::ScriptSigBuf::new(), sequence: Sequence(0), - // sequence: Sequence(40), - ..Default::default() + witness: Witness::default(), }; - let prev_amount = Amount::from_sat(100_000_000); + let prev_amount = Amount::from_sat(100_000_000).expect("in range"); let witness_utxo = - TxOut { value: prev_amount, script_pubkey: derived_descriptor.clone().script_pubkey() }; + TxOut { amount: prev_amount, script_pubkey: derived_descriptor.clone().script_pubkey() }; let destination_address = Address::from_str("bcrt1p2tl8zasepqe3j6m7hx4tdmqzndddr5wa9ugglpdzgenjwv42rkws66dk5a") .unwrap(); let destination_output: TxOut = TxOut { - value: bitcoin::Amount::from_sat(99_999_000), + amount: bitcoin::Amount::from_sat(99_999_000).expect("in range"), script_pubkey: destination_address.assume_checked().script_pubkey(), }; @@ -232,12 +233,12 @@ fn main() { let unsigned_tx = bitcoin::Transaction { version: Version::TWO, - lock_time: LockTime::from_time(time).unwrap(), - input: vec![tx_in], - output: vec![destination_output], + lock_time: LockTime::from_mtp(time).unwrap(), + inputs: vec![tx_in], + outputs: vec![destination_output], }; - let unsigned_tx_test_string = serialize(&unsigned_tx).to_hex_string(Case::Lower); + let unsigned_tx_test_string = serialize(&unsigned_tx).to_lower_hex_string(); assert!(unsigned_tx_test_string == "0200000001ffffffffeeeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa99999999888888880000000000000000000118ddf5050000000022512052fe7176190833196b7eb9aab6ec029b5ad1d1dd2f108f85a246672732aa1d9d60011967"); let mut psbt = Psbt::from_unsigned_tx(unsigned_tx).unwrap(); @@ -253,16 +254,16 @@ fn main() { //let _res = psbt.sign(&intneral_xpriv.xkey, secp).unwrap(); // how you would sign using the leaf that uses index 0 keys - let _res = psbt.sign(&a_prvs[0], secp).unwrap(); - let _res = psbt.sign(&b_prvs[0], secp).unwrap(); - let _res = psbt.sign(&c_prvs[0], secp).unwrap(); - let _res = psbt.sign(&d_prvs[0], secp).unwrap(); - let _res = psbt.sign(&e_prvs[0], secp).unwrap(); - let _res = psbt.sign(&f_prvs[0], secp).unwrap(); - let _res = psbt.sign(&h_prvs[0], secp).unwrap(); - let _res = psbt.sign(&i_prvs[0], secp).unwrap(); - let _res = psbt.sign(&j_prvs[0], secp).unwrap(); - let _res = psbt.sign(&l_prvs[0], secp).unwrap(); + let _res = psbt.sign(&a_prvs[0]).unwrap(); + let _res = psbt.sign(&b_prvs[0]).unwrap(); + let _res = psbt.sign(&c_prvs[0]).unwrap(); + let _res = psbt.sign(&d_prvs[0]).unwrap(); + let _res = psbt.sign(&e_prvs[0]).unwrap(); + let _res = psbt.sign(&f_prvs[0]).unwrap(); + let _res = psbt.sign(&h_prvs[0]).unwrap(); + let _res = psbt.sign(&i_prvs[0]).unwrap(); + let _res = psbt.sign(&j_prvs[0]).unwrap(); + let _res = psbt.sign(&l_prvs[0]).unwrap(); psbt.inputs[0] .sha256_preimages @@ -277,7 +278,7 @@ fn main() { // Now extract the tx let signed_tx = psbt.extract_tx().unwrap(); - let raw_tx = bitcoin::consensus::encode::serialize(&signed_tx).to_hex_string(Case::Lower); + let raw_tx = bitcoin::consensus::encode::serialize(&signed_tx).to_lower_hex_string(); assert!(raw_tx == "02000000000101ffffffffeeeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa99999999888888880000000000000000000118ddf5050000000022512052fe7176190833196b7eb9aab6ec029b5ad1d1dd2f108f85a246672732aa1d9d0e209250ecce1169d94cf17baaecddcef779ff1b0d07d347d24afcd5b2231f95a500209562ef4e826d891eaa72f2cee753b80a3f7f6b5aed07b850227e83546fa6185740a5da084901627205e860d6530ff5ff580fc3841b779ad8535ffd7b466664aa0280c218aa05a1054c73b1f717b6c5badf70e71e5091b4b34e25ec3584243fd0604032a0bad48af9b3263d331ba2c789a931af81755c67dfefab28f8e40658545e6659eeb93d2c501ac79914ca82f4dbdcd669d34c7de73b4c243400926cffeb42b640015f5b58eb820676382521bb38b9d0c16d40c6a1b710242232d3d8276145aee859667d3caf9b72acecbfa3be33ce7afb9bda70b19451c58550bb1076125463c240ba0ba063d92ef71a35a1bdbd41b165d71825d6b5d9555781a3a6c35aba5864c82c4e53a7656458dc8bd586a6de749b6ab59cbb5ec4e2264a185ef7b79db3ea9c408176c65f6486f5c9a7d466fe86dfed7d55f8fc480b5843414696842f1efc689e74fce36a0b318535ef86864d8f83ac4bb60085c2b45c0547b9657def51b52b8e40b5f95b03c77b685314848a292d05bf350cdad506bcb2601b634779e956235aef3bade98a812f046d47060fbf9965ac0ef016e6ef09540c1c7d5b2fe447192cbd405ea9e1a58685ef958db8aa529d3fbfcc1182e252a35715bf9b2c35a30c73e718a65e8a8c0141eaac72af71a1dd7f19c53aaead75ae5b963a4eee5d1228c389844094a38c8574e6089c33d2c37d6f889adb671ef09a188e91cf032e97a3e25e9636901096e1cc92d17fbf4c581e5a1915de53f807f3198f4a2b829fc3a4479f6bb54017e68b70fd9e5c94c6f99abf284f5da42365a2e5fd4f0971bf5cb68aea3408c0d05ace043c15e70958c73f7455db3a22e3e5fb0240749a9dc52aa66a554fb06b40c478230871c12b60bc7cae151e411aa779780a8e6a7afd57aa763185809259fc7853f65e712d1ef178d4750f66e1b6db3cae7efcec5308b815b39fe8498f404afd9c0120fe88003d0bcb15d1628edff84046255758baf205d42ce460b6fb4595b983f2ecad20eecd6dba68fd0ec5d4baa0052db8084cb15a55503b78cfee5ef31c35cd98d846ad20529c1e24d86bf35b35133a81bf1e8c21759f3a83cfb38f18eae1d5b8292ff4bead2083835dbe036944f18783e0a525babe23965a2b4fdeca2d2d84997fc6ff0fb06aad204aeb360d05ad743b838ad27c56b78f08668aeba77f2f1fc439ac80f970e57328ad2062c4d094ce7a28414102bacccb06947053e07e4da53ad96e5724565f09436dfcad20f6e5c74176d69d44a97220a694237d8e719fae4a029942aadb28a9b491b40e31ad20dc7ea580c6887971614260d91069c4d398cc80ecc6cbb4ab59099e110ad3bb8bad2059fa3dfd7286d59f9b3853fb0cdd13c4760508f672435be40057b9e02eb937bdad20aa90f13a1c98abc5620d3f379d20b8c28ddf8f46772a0d0af6b7deb7bf3a1ee1ad82012088a8202db9cdb5e102541f19b455fa798e0cb009f5faa6358b9d3507858caf797bca418882012088a6148d60757ec290d055be92da400cff617b0423cb14880460011967b141c1259b7a61aa66c551a6cd35ccc35e9e011ecbbddbbb673acba71e2e4cc11e8883326f8afc8b0ef3f1cc0428893a40e48b9419807a4fd8f8673b62840ef216d5f660011967"); } diff --git a/examples/verify_tx.rs b/examples/verify_tx.rs index f2a63f447..8ebff73d2 100644 --- a/examples/verify_tx.rs +++ b/examples/verify_tx.rs @@ -8,6 +8,7 @@ use miniscript::bitcoin::consensus::Decodable; use miniscript::bitcoin::secp256k1::Secp256k1; use miniscript::bitcoin::{absolute, sighash, Sequence}; use miniscript::interpreter::KeySigPair; +use miniscript::ScriptBuf; fn main() { // @@ -17,10 +18,12 @@ fn main() { let tx = hard_coded_transaction(); let spk_input_1 = hard_coded_script_pubkey(); + let script_sig_as_spk = + bitcoin::script::ScriptPubKey::from_bytes(tx.inputs[0].script_sig.as_bytes()); let interpreter = miniscript::Interpreter::from_txdata( &spk_input_1, - &tx.input[0].script_sig, - &tx.input[0].witness, + script_sig_as_spk, + &tx.inputs[0].witness, Sequence::ZERO, absolute::LockTime::ZERO, ) @@ -89,7 +92,7 @@ fn main() { let (pk, ecdsa_sig) = key_sig.as_ecdsa().expect("Ecdsa Sig"); ecdsa_sig.sighash_type == bitcoin::sighash::EcdsaSighashType::All && secp - .verify_ecdsa(&message, &ecdsa_sig.signature, &pk.inner) + .verify_ecdsa(message, &ecdsa_sig.signature, &pk.to_inner()) .is_ok() })); @@ -161,8 +164,8 @@ fn hard_coded_transaction() -> bitcoin::Transaction { bitcoin::Transaction::consensus_decode(&mut &tx_bytes[..]).expect("decode transaction") } -fn hard_coded_script_pubkey() -> bitcoin::ScriptBuf { - bitcoin::ScriptBuf::from(vec![ +fn hard_coded_script_pubkey() -> ScriptBuf { + ScriptBuf::from(vec![ 0xa9, 0x14, 0x92, 0x09, 0xa8, 0xf9, 0x0c, 0x58, 0x4b, 0xb5, 0x97, 0x4d, 0x58, 0x68, 0x72, 0x49, 0xe5, 0x32, 0xde, 0x59, 0xf4, 0xbc, 0x87, ]) diff --git a/examples/xpub_descriptors.rs b/examples/xpub_descriptors.rs index d7be9cc4f..2afec2819 100644 --- a/examples/xpub_descriptors.rs +++ b/examples/xpub_descriptors.rs @@ -33,7 +33,7 @@ fn p2wsh(secp: &Secp256k1) -> Address { let address = Descriptor::::from_str(&s) .unwrap() - .derived_descriptor(secp) + .derived_descriptor() .address(Network::Bitcoin) .unwrap(); @@ -55,7 +55,7 @@ fn p2sh_p2wsh(secp: &Secp256k1) -> Address { let address = Descriptor::::from_str(&s) .unwrap() - .derived_descriptor(secp, 5) + .derived_descriptor(5) .unwrap() .address(Network::Bitcoin) .unwrap(); @@ -80,7 +80,7 @@ fn p2tr_sortedmulti_a(secp: &Secp256k1) -> Address { .map(|s| { Descriptor::::from_str(&s) .unwrap() - .derived_descriptor(secp, 5) + .derived_descriptor(5) .unwrap() .address(Network::Bitcoin) .unwrap() From 64562ba5dab94443bc786e4c66f9091bbd27d71d Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 13:42:55 -0600 Subject: [PATCH 06/23] bitcoin 0.33: migrate interpreter/miniscript/psbt/plan/policy tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ports the test modules across `src/interpreter/`, `src/miniscript/`, `src/psbt/`, `src/plan.rs`, and `src/policy/`, plus a final tweak to `src/test_utils.rs` so that `StrXOnlyKeyTranslator` emits `secp256k1::XOnlyPublicKey` (matching `Tap::Key`) and therefore `Miniscript::::decode_consensus` resolves. - Drop `&secp` from test call sites of APIs whose secp argument was removed in the library migration (`Xpriv::fingerprint/derive_priv`, `PrivateKey::public_key`, `Keypair::from_secret_key`, etc). - Replace `PubkeyHash`/`WPubkeyHash`/`ScriptHash`/`WScriptHash` constructions that used a hash160/sha256 `.into()` with explicit `::from_byte_array(..to_byte_array())` so the stricter 0.33 `From<...>` bounds are satisfied. - `witness.iter().rev().nth(1)` → `witness.get_back(1)` (the new direct accessor for "second-to-last" stack element). - Wrap `ms.encode()` as `TapScriptBuf::from_bytes(...)` when calling `TapLeafHash::from_script` / comparing `tap_scripts` entries. - `Amount::from_sat(n)` now returns `Result`; add `.expect("in range")` on test-only call sites. `TxIn::default()` → `TxIn::EMPTY_COINBASE`. `TransactionVersion::non_standard` → `maybe_non_standard`. - `pk.inner` → `pk.to_inner()` / `pk.as_inner()`; `PublicKey` struct literal replaced with `PublicKey::from_secp(...)` in `miniscript/iter.rs` tests. - `pk.pubkey_hash().to_raw_hash()` → explicit `hash160::Hash::from_byte_array(pk.pubkey_hash().to_byte_array())`. - `SecretKey::from_slice(&[u8])` → `from_secret_bytes([u8; 32])`. - `secp.sign_schnorr_with_aux_rand(&sighash, ...)` → `sign_schnorr_with_aux_rand(sighash.as_ref(), ...)` (raw byte input) against the `bitcoin::Keypair::to_inner()` secp keypair. All library, test, and example targets now compile cleanly with `cargo check --lib`, `cargo check --tests`, and `cargo check --examples`. Deprecation warnings for `sign_ecdsa`, `verify_ecdsa`, `Message::from_digest_slice`, and `LockTime::from_time` remain in test code. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/interpreter/inner.rs | 32 +++++++++++++++++++++++--------- src/interpreter/mod.rs | 15 ++++++++------- src/miniscript/iter.rs | 12 ++++++++---- src/miniscript/mod.rs | 6 +++--- src/plan.rs | 4 ++-- src/policy/mod.rs | 2 +- src/psbt/mod.rs | 10 +++++----- src/test_utils.rs | 4 ++-- 8 files changed, 52 insertions(+), 33 deletions(-) diff --git a/src/interpreter/inner.rs b/src/interpreter/inner.rs index 77b5147b5..256fb2b96 100644 --- a/src/interpreter/inner.rs +++ b/src/interpreter/inner.rs @@ -487,10 +487,16 @@ mod tests { .unwrap(); let dummy_sig = <[u8; 48]>::try_from(&dummy_sig_vec[..]).unwrap(); - let pkhash = key.to_pubkeyhash(SigType::Ecdsa).into(); - let wpkhash = key.to_pubkeyhash(SigType::Ecdsa).into(); + let pkhash = bitcoin::key::PubkeyHash::from_byte_array( + key.to_pubkeyhash(SigType::Ecdsa).to_byte_array(), + ); + let wpkhash = bitcoin::key::WPubkeyHash::from_byte_array( + key.to_pubkeyhash(SigType::Ecdsa).to_byte_array(), + ); let wpkh_spk = ScriptBuf::new_p2wpkh(wpkhash); - let wpkh_scripthash = hash160::Hash::hash(wpkh_spk.as_bytes()).into(); + let wpkh_scripthash = bitcoin::script::ScriptHash::from_byte_array( + hash160::Hash::hash(wpkh_spk.as_bytes()).to_byte_array(), + ); KeyTestData { pk_spk: ScriptBuf::new_p2pk(key), @@ -677,7 +683,7 @@ mod tests { let (inner, stack, script_code) = from_txdata(&comp.wpkh_spk, &blank_script, &comp.wpkh_stack).expect("parse txdata"); assert_eq!(inner, Inner::PublicKey(fixed.pk_comp.into(), PubkeyType::Wpkh)); - assert_eq!(stack, Stack::from(vec![comp.wpkh_stack.iter().rev().nth(1).unwrap().into()])); + assert_eq!(stack, Stack::from(vec![comp.wpkh_stack.get_back(1).unwrap().into()])); assert_eq!(script_code, Some(comp.pkh_spk)); // Scriptsig is nonempty @@ -733,7 +739,7 @@ mod tests { assert_eq!(inner, Inner::PublicKey(fixed.pk_comp.into(), PubkeyType::ShWpkh)); assert_eq!( stack, - Stack::from(vec![comp.sh_wpkh_stack.iter().rev().nth(1).unwrap().into()]) + Stack::from(vec![comp.sh_wpkh_stack.get_back(1).unwrap().into()]) ); assert_eq!(script_code, Some(comp.pkh_spk.clone())); } @@ -775,7 +781,9 @@ mod tests { let hash = hash160::Hash::hash(&preimage[..]); let (miniscript, redeem_script) = ms_inner_script(&format!("hash160({})", hash)); - let rs_hash = hash160::Hash::hash(redeem_script.as_bytes()).into(); + let rs_hash = bitcoin::script::ScriptHash::from_byte_array( + hash160::Hash::hash(redeem_script.as_bytes()).to_byte_array(), + ); let spk = ScriptBuf::new_p2sh(rs_hash); let script_sig = ScriptBuilderLocal::new() @@ -810,7 +818,9 @@ mod tests { let preimage = b"12345678----____12345678----____"; let hash = hash160::Hash::hash(&preimage[..]); let (miniscript, witness_script) = ms_inner_script(&format!("hash160({})", hash)); - let wit_hash = sha256::Hash::hash(witness_script.as_bytes()).into(); + let wit_hash = bitcoin::script::WScriptHash::from_byte_array( + sha256::Hash::hash(witness_script.as_bytes()).to_byte_array(), + ); let wit_stack = Witness::from_slice(&[witness_script.to_bytes()]); let spk = ScriptBuf::new_p2wsh(wit_hash); @@ -845,7 +855,9 @@ mod tests { let preimage = b"12345678----____12345678----____"; let hash = hash160::Hash::hash(&preimage[..]); let (miniscript, witness_script) = ms_inner_script(&format!("hash160({})", hash)); - let wit_hash = sha256::Hash::hash(witness_script.as_bytes()).into(); + let wit_hash = bitcoin::script::WScriptHash::from_byte_array( + sha256::Hash::hash(witness_script.as_bytes()).to_byte_array(), + ); let wit_stack = Witness::from_slice(&[witness_script.to_bytes()]); let redeem_script = ScriptBuf::new_p2wsh(wit_hash); @@ -854,7 +866,9 @@ mod tests { .into_script(); let blank_script = ScriptBuf::new(); - let rs_hash = hash160::Hash::hash(redeem_script.as_bytes()).into(); + let rs_hash = bitcoin::script::ScriptHash::from_byte_array( + hash160::Hash::hash(redeem_script.as_bytes()).to_byte_array(), + ); let spk = ScriptBuf::new_p2sh(rs_hash); // shwsh without witness or scriptsig diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 367f1cdb0..f44d57c85 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -1093,9 +1093,8 @@ mod tests { sk[2] = (i >> 16) as u8; let sk = secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"); - let pk = - bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key(&secp, &sk)); - let signature = secp.sign_ecdsa(&msg, &sk); + let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key(&sk)); + let signature = secp.sign_ecdsa(msg, &sk); ecdsa_sigs.push(bitcoin::ecdsa::Signature { signature, sighash_type: bitcoin::sighash::EcdsaSighashType::All, @@ -1105,10 +1104,12 @@ mod tests { pks.push(pk); der_sigs.push(sigser); - let keypair = bitcoin::key::Keypair::from_secret_key(&secp, &sk); + let secp_keypair = secp256k1::Keypair::from_secret_key(&sk); + let keypair = bitcoin::key::Keypair::from_secp(secp_keypair); let x_only_pk = bitcoin::key::XOnlyPublicKey::from_keypair(&keypair); x_only_pks.push(x_only_pk); - let schnorr_sig = secp.sign_schnorr_with_aux_rand(&msg, &keypair, &[0u8; 32]); + let schnorr_sig = + secp.sign_schnorr_with_aux_rand(msg.as_ref(), &secp_keypair, &[0u8; 32]); let schnorr_sig = bitcoin::taproot::Signature { signature: schnorr_sig, sighash_type: bitcoin::sighash::TapSighashType::Default, @@ -1126,10 +1127,10 @@ mod tests { let secp_ref = &secp; let vfyfn = |pksig: &KeySigPair| match pksig { KeySigPair::Ecdsa(pk, ecdsa_sig) => secp_ref - .verify_ecdsa(&sighash, &ecdsa_sig.signature, pk.as_inner()) + .verify_ecdsa(sighash, &ecdsa_sig.signature, &pk.to_inner()) .is_ok(), KeySigPair::Schnorr(xpk, schnorr_sig) => secp_ref - .verify_schnorr(&schnorr_sig.signature, &sighash, xpk) + .verify_schnorr(&schnorr_sig.signature, sighash.as_ref(), xpk.as_inner()) .is_ok(), }; diff --git a/src/miniscript/iter.rs b/src/miniscript/iter.rs index 0ef2272af..fe8f4ace2 100644 --- a/src/miniscript/iter.rs +++ b/src/miniscript/iter.rs @@ -227,7 +227,6 @@ pub mod test { /// Generate a deterministic list of public keys of the given length. pub fn gen_secp_pubkeys(n: usize) -> Vec { let mut ret = Vec::with_capacity(n); - let secp = secp256k1::Secp256k1::new(); let mut sk = [0; 32]; for i in 1..n + 1 { @@ -236,8 +235,7 @@ pub mod test { sk[2] = (i >> 16) as u8; ret.push(secp256k1::PublicKey::from_secret_key( - &secp, - &secp256k1::SecretKey::from_slice(&sk[..]).unwrap(), + &secp256k1::SecretKey::from_secret_bytes(sk).unwrap(), )); } ret @@ -247,7 +245,13 @@ pub mod test { pub fn gen_bitcoin_pubkeys(n: usize, compressed: bool) -> Vec { gen_secp_pubkeys(n) .into_iter() - .map(|inner| bitcoin::PublicKey { inner, compressed }) + .map(|inner| { + if compressed { + bitcoin::PublicKey::from_secp(inner) + } else { + bitcoin::PublicKey::from_secp_uncompressed(inner) + } + }) .collect() } diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 6539f998c..91e235b57 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -1123,7 +1123,6 @@ mod tests { fn pubkeys(n: usize) -> Vec { let mut ret = Vec::with_capacity(n); - let secp = secp256k1::Secp256k1::new(); let mut sk = [0; 32]; for i in 1..n + 1 { sk[0] = i as u8; @@ -1131,7 +1130,6 @@ mod tests { sk[2] = (i >> 16) as u8; let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key( - &secp, &secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"), )); ret.push(pk); @@ -1735,7 +1733,9 @@ mod tests { "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c", ) .unwrap(); - let hash160 = pk.pubkey_hash().to_raw_hash(); + let hash160 = bitcoin::hashes::hash160::Hash::from_byte_array( + pk.pubkey_hash().to_byte_array(), + ); let ms_str = &format!("c:expr_raw_pkh({})", hash160); type SegwitMs = Miniscript; diff --git a/src/plan.rs b/src/plan.rs index 87f9f0aa6..413a050f3 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -1188,7 +1188,7 @@ mod test { .iter() .map(|d: &&[u8; 32]| { let sk = secp256k1::SecretKey::from_secret_bytes(**d).unwrap(); - let pk = bitcoin::PublicKey::new(secp256k1::PublicKey::from_secret_key(&secp, &sk)); + let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key(&sk)); (sk, pk) }) .unzip(); @@ -1202,7 +1202,7 @@ mod test { secp256k1::Message::from_digest_slice(&b"michael was a message, amusingly"[..]) .expect("32 bytes"); bitcoin::ecdsa::Signature { - signature: secp.sign_ecdsa(&sighash, sk), + signature: secp.sign_ecdsa(sighash, sk), sighash_type: bitcoin::sighash::EcdsaSighashType::All, } }) diff --git a/src/policy/mod.rs b/src/policy/mod.rs index 073c3aa40..e993e56d2 100644 --- a/src/policy/mod.rs +++ b/src/policy/mod.rs @@ -354,7 +354,7 @@ mod tests { .unwrap(); let ms_str: Miniscript = - format!("andor(multi(1,{}),older(42),c:pk_k({}))", key_a.inner, key_b.inner) + format!("andor(multi(1,{}),older(42),c:pk_k({}))", key_a.to_inner(), key_b.to_inner()) .parse() .unwrap(); assert_eq!( diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index 7c4775d68..6125879e0 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -1481,7 +1481,7 @@ mod tests { let first_leaf_hash = { let ms = Miniscript::::from_str(&format!("pkh({})", &key_0_1)).unwrap(); - let first_script = ms.encode(); + let first_script = TapScriptBuf::from_bytes(ms.encode().into_bytes()); assert!(psbt_input .tap_scripts .values() @@ -1599,7 +1599,7 @@ mod tests { lock_time: absolute::LockTime::ZERO, inputs: vec![], outputs: vec![TxOut { - amount: Amount::from_sat(1_000), + amount: Amount::from_sat(1_000).expect("in range"), script_pubkey: ScriptBuf::from_hex( "5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c", ) @@ -1612,7 +1612,7 @@ mod tests { lock_time: absolute::LockTime::ZERO, inputs: vec![TxIn { previous_output: OutPoint { txid: non_witness_utxo.compute_txid(), vout: 0 }, - ..Default::default() + ..TxIn::EMPTY_COINBASE }], outputs: vec![], }; @@ -1635,7 +1635,7 @@ mod tests { Ok(()), "matching non_witness_utxo" ); - non_witness_utxo.version = transaction::Version::non_standard(0); + non_witness_utxo.version = transaction::Version::maybe_non_standard(0); psbt.inputs[0].non_witness_utxo = Some(non_witness_utxo); assert_eq!( psbt.update_input_with_descriptor(0, &desc), @@ -1661,7 +1661,7 @@ mod tests { lock_time: absolute::LockTime::ZERO, inputs: vec![], outputs: vec![TxOut { - amount: Amount::from_sat(1_000), + amount: Amount::from_sat(1_000).expect("in range"), script_pubkey: ScriptBuf::from_hex( "5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c", ) diff --git a/src/test_utils.rs b/src/test_utils.rs index 0ac3992f7..ac922195f 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -7,7 +7,7 @@ use std::collections::HashMap; use std::str::FromStr; use bitcoin::hashes::{hash160, ripemd160, sha256}; -use bitcoin::key::XOnlyPublicKey; +use bitcoin::secp256k1::XOnlyPublicKey; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 use bitcoin::secp256k1; @@ -169,7 +169,7 @@ impl StrXOnlyKeyTranslator { .map(|sk| { let keypair = secp256k1::Keypair::from_secret_key(sk); let (pk, _parity) = secp256k1::XOnlyPublicKey::from_keypair(&keypair); - XOnlyPublicKey::from(pk) + pk }) .collect(); let mut pk_map = HashMap::new(); From 36b7721cb20941dd669b3a79b1decb0778f9f2ac Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 13:50:20 -0600 Subject: [PATCH 07/23] bitcoin 0.33: migrate fuzz crate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fuzz crate pulls both the current `miniscript` (bitcoin 0.33) and `old_miniscript` 12.3 (bitcoin 0.32) to run regression comparisons. Since those are distinct versions of `bitcoin`, every `PublicKey`, `XOnlyPublicKey`, `hash256::Hash`, etc. from the two sides are *different types even though they look the same* — so the `FuzzPk` impls have to be written twice, against each crate's types. Changes: - `fuzz/src/lib.rs`: split the two `ToPublicKey` impls so each uses its own crate's `PublicKey`, `secp256k1`, and hash types. The new-side `PublicKey` is constructed with `::from_secp(...)` / `::from_secp_ uncompressed(...)` (fields are private); `hash256::Hash` now uses `hash256::Hash::hash(...)` since `from_byte_array` is only exposed via the `Hash` trait. - `fuzz_targets/roundtrip_miniscript_script_tap.rs`: switch to `miniscript::Script::from_bytes` (tagged) and spell the key type as `bitcoin::secp256k1::XOnlyPublicKey` (Tap::Key is still the secp variant even though `bitcoin::XOnlyPublicKey` now wraps a parity). - `fuzz_targets/miniscript_satisfy.rs`: `pk.inner` is private; use `pk.to_inner()`, and wrap the resulting secp xonly with `bitcoin::XOnlyPublicKey::from(...)` for the trait return type. Replace deprecated `schnorr::Signature::from_slice` with `from_byte_array`. - `fuzz_targets/regression_taptree.rs`: the old/new spend_info values aren't directly comparable — compare via serialized bytes: `internal_key().serialize()` (old: `[u8;32]`; new: `([u8;32], Parity)` so index into `.0`), `output_key().serialize()` (both `[u8;32]`), `merkle_root().map(to_byte_array)`, `control_block().serialize()` into a `HashMap, HashSet>>`. Bridge `LeafVersion` between the two crates via `from_consensus(to_consensus(...))`. `cargo check --manifest-path fuzz/Cargo.toml` passes with no errors or warnings. Co-Authored-By: Claude Opus 4.7 (1M context) --- fuzz/fuzz_targets/miniscript_satisfy.rs | 5 +- fuzz/fuzz_targets/regression_taptree.rs | 56 +++++++++++++------ .../roundtrip_miniscript_script_tap.rs | 7 ++- fuzz/src/lib.rs | 37 +++++++----- 4 files changed, 68 insertions(+), 37 deletions(-) diff --git a/fuzz/fuzz_targets/miniscript_satisfy.rs b/fuzz/fuzz_targets/miniscript_satisfy.rs index d22bde00c..157f213c8 100644 --- a/fuzz/fuzz_targets/miniscript_satisfy.rs +++ b/fuzz/fuzz_targets/miniscript_satisfy.rs @@ -26,8 +26,7 @@ impl Satisfier for FuzzSatisfier<'_> { fn lookup_tap_key_spend_sig(&self, _: &FuzzPk) -> Option { let b = self.read_byte()?; if b & 1 == 1 { - // FIXME in later version of rust-secp we can use from_byte_array - let secp_sig = secp256k1::schnorr::Signature::from_slice(&[0xab; 64]).unwrap(); + let secp_sig = secp256k1::schnorr::Signature::from_byte_array([0xab; 64]); Some(Signature { signature: secp_sig, sighash_type: TapSighashType::Default }) } else { None @@ -74,7 +73,7 @@ impl Satisfier for FuzzSatisfier<'_> { fn lookup_raw_pkh_x_only_pk(&self, h: &hash160::Hash) -> Option { self.lookup_raw_pkh_pk(h) - .map(|pk| pk.inner.x_only_public_key().0) + .map(|pk| XOnlyPublicKey::from(pk.to_inner().x_only_public_key().0)) } // todo diff --git a/fuzz/fuzz_targets/regression_taptree.rs b/fuzz/fuzz_targets/regression_taptree.rs index ab50d06bd..8afe74eea 100644 --- a/fuzz/fuzz_targets/regression_taptree.rs +++ b/fuzz/fuzz_targets/regression_taptree.rs @@ -14,36 +14,58 @@ fn do_test(data: &[u8]) { (Ok(new), Ok(old)) => { let new_si = new.spend_info(); let old_si = old.spend_info(); + // The old and new crates each carry their own copy of `bitcoin` types, so we can't + // compare the typed values directly. Compare their serialized byte representations + // instead. + // `internal_key()` yields an `UntweakedPublicKey` in both crates, but since new + // bitcoin's `XOnlyPublicKey::serialize()` returns `([u8; 32], Parity)` while the old + // one returns `[u8; 32]`, discard the parity on the new side to compare x-coords. assert_eq!( - old_si.internal_key(), - new_si.internal_key(), - "merkle root mismatch (left is old, new is right)", + old_si.internal_key().serialize(), + new_si.internal_key().serialize().0, + "internal key mismatch (left is old, new is right)", ); assert_eq!( - old_si.merkle_root(), - new_si.merkle_root(), + old_si.merkle_root().as_ref().map(|h| { + use old_miniscript::bitcoin::hashes::Hash as _; + h.to_byte_array() + }), + new_si.merkle_root().as_ref().map(|h| h.to_byte_array()), "merkle root mismatch (left is old, new is right)", ); assert_eq!( - old_si.output_key(), - new_si.output_key(), - "merkle root mismatch (left is old, new is right)", + old_si.output_key().serialize(), + new_si.output_key().serialize(), + "output key mismatch (left is old, new is right)", ); - // Map every leaf script to a set of all the control blocks - let mut new_cbs = HashMap::new(); + // Map every leaf script to a set of all the control blocks (keyed by script bytes). + let mut new_cbs: HashMap, HashSet>> = HashMap::new(); for leaf in new_si.leaves() { new_cbs - .entry(leaf.script()) - .or_insert(HashSet::new()) - .insert(leaf.control_block().clone()); + .entry(leaf.script().to_vec()) + .or_default() + .insert(leaf.control_block().serialize()); } // ...the old code will only ever yield one of them and it's not easy to predict which one for leaf in new_si.leaves() { - let old_cb = old_si - .control_block(&(leaf.script().into(), leaf.leaf_version())) - .unwrap(); - assert!(new_cbs[leaf.script()].contains(&old_cb)); + let old_cb_bytes = { + use old_miniscript::bitcoin::taproot::LeafVersion; + let leaf_bytes: Vec = leaf.script().to_vec(); + let script_buf = + old_miniscript::bitcoin::ScriptBuf::from_bytes(leaf_bytes.clone()); + let leaf_ver = LeafVersion::from_consensus( + miniscript::bitcoin::taproot::LeafVersion::to_consensus( + leaf.leaf_version(), + ), + ) + .expect("valid leaf version"); + old_si + .control_block(&(script_buf, leaf_ver)) + .unwrap() + .serialize() + }; + assert!(new_cbs[&leaf.script().to_vec()].contains(&old_cb_bytes)); } } } diff --git a/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs b/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs index 7dd16fc9c..4a0fc3a49 100644 --- a/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs +++ b/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs @@ -1,14 +1,15 @@ #![allow(unexpected_cfgs)] use honggfuzz::fuzz; -use miniscript::bitcoin::blockdata::script; use miniscript::{Miniscript, Tap}; fn do_test(data: &[u8]) { // Try round-tripping as a script - let script = script::Script::from_bytes(data); + let script = miniscript::Script::from_bytes(data); - if let Ok(pt) = Miniscript::::decode(script) { + if let Ok(pt) = + Miniscript::::decode(script) + { let output = pt.encode(); assert_eq!(pt.script_size(), output.len()); assert_eq!(&output, script); diff --git a/fuzz/src/lib.rs b/fuzz/src/lib.rs index 616dc2254..8951aa291 100644 --- a/fuzz/src/lib.rs +++ b/fuzz/src/lib.rs @@ -7,8 +7,7 @@ use core::{fmt, str}; -use miniscript::bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; -use miniscript::bitcoin::{secp256k1, PublicKey}; +use miniscript::bitcoin::hashes::{hash160, ripemd160, sha256}; use miniscript::{hash256, MiniscriptKey, ToPublicKey}; /// A public key which is encoded as a single hex byte (two hex characters). @@ -46,7 +45,8 @@ impl MiniscriptKey for FuzzPk { } impl ToPublicKey for FuzzPk { - fn to_public_key(&self) -> PublicKey { + fn to_public_key(&self) -> miniscript::bitcoin::PublicKey { + use miniscript::bitcoin::secp256k1; let secp_pk = secp256k1::PublicKey::from_slice(&[ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce, 0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, @@ -55,14 +55,16 @@ impl ToPublicKey for FuzzPk { 0xfc, 0x07, 0x00, 0xca, 0x10, 0x0e, 0x59, 0xdd, 0xf3, ]) .unwrap(); - PublicKey { inner: secp_pk, compressed: self.compressed } + if self.compressed { + miniscript::bitcoin::PublicKey::from_secp(secp_pk) + } else { + miniscript::bitcoin::PublicKey::from_secp_uncompressed(secp_pk) + } } fn to_sha256(hash: &Self::Sha256) -> sha256::Hash { sha256::Hash::from_byte_array([*hash; 32]) } - fn to_hash256(hash: &Self::Hash256) -> hash256::Hash { - hash256::Hash::from_byte_array([*hash; 32]) - } + fn to_hash256(hash: &Self::Hash256) -> hash256::Hash { hash256::Hash::hash(&[*hash; 32]) } fn to_ripemd160(hash: &Self::Ripemd160) -> ripemd160::Hash { ripemd160::Hash::from_byte_array([*hash; 20]) @@ -81,7 +83,8 @@ impl old_miniscript::MiniscriptKey for FuzzPk { } impl old_miniscript::ToPublicKey for FuzzPk { - fn to_public_key(&self) -> PublicKey { + fn to_public_key(&self) -> old_miniscript::bitcoin::PublicKey { + use old_miniscript::bitcoin::secp256k1; let secp_pk = secp256k1::PublicKey::from_slice(&[ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce, 0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, @@ -90,20 +93,26 @@ impl old_miniscript::ToPublicKey for FuzzPk { 0xfc, 0x07, 0x00, 0xca, 0x10, 0x0e, 0x59, 0xdd, 0xf3, ]) .unwrap(); - PublicKey { inner: secp_pk, compressed: self.compressed } + old_miniscript::bitcoin::PublicKey { inner: secp_pk, compressed: self.compressed } } - fn to_sha256(hash: &Self::Sha256) -> sha256::Hash { sha256::Hash::from_byte_array([*hash; 32]) } + fn to_sha256(hash: &Self::Sha256) -> old_miniscript::bitcoin::hashes::sha256::Hash { + use old_miniscript::bitcoin::hashes::Hash as _; + old_miniscript::bitcoin::hashes::sha256::Hash::from_byte_array([*hash; 32]) + } fn to_hash256(hash: &Self::Hash256) -> old_miniscript::hash256::Hash { + use old_miniscript::bitcoin::hashes::Hash as _; old_miniscript::hash256::Hash::from_byte_array([*hash; 32]) } - fn to_ripemd160(hash: &Self::Ripemd160) -> ripemd160::Hash { - ripemd160::Hash::from_byte_array([*hash; 20]) + fn to_ripemd160(hash: &Self::Ripemd160) -> old_miniscript::bitcoin::hashes::ripemd160::Hash { + use old_miniscript::bitcoin::hashes::Hash as _; + old_miniscript::bitcoin::hashes::ripemd160::Hash::from_byte_array([*hash; 20]) } - fn to_hash160(hash: &Self::Ripemd160) -> hash160::Hash { - hash160::Hash::from_byte_array([*hash; 20]) + fn to_hash160(hash: &Self::Ripemd160) -> old_miniscript::bitcoin::hashes::hash160::Hash { + use old_miniscript::bitcoin::hashes::Hash as _; + old_miniscript::bitcoin::hashes::hash160::Hash::from_byte_array([*hash; 20]) } } From a6880460d8a14881309ca42682354fd62c203dad Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 14:09:38 -0600 Subject: [PATCH 08/23] bitcoin 0.33: fix test expectations and migrate deprecated APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the test expectations that broke after the bitcoin 0.33 migration and migrates remaining deprecated 0.32-era calls: - Opcode display names changed: `OP_PUSHNUM_N` → `OP_N`. Update every expected-string in `src/miniscript/mod.rs` test helpers. - `bitcoin::PublicKey`'s `Debug` impl no longer wraps the inner key as `PublicKey()` — it now prints the hex bytes directly. Update the six expected debug strings in `pk_alias`. - `miniscript::tests::deserialize` relied on `read_scriptint` rejecting non-minimal integers; the migration swapped to `read_scriptint_non_minimal`, which by name does not. Switch the lexer to the `PushBytes::read_scriptint` method which performs the minimal check. - Interpreter's `sat_constraints` test: the interpreter reconstructs `XOnlyPublicKey` from a 32-byte push with default (`Even`) parity, so normalise the expected `x_only_pks` produced by `from_keypair` to `Even` parity before comparison. - Drop `LockTime::from_time` (deprecated) in favour of `from_mtp` in `plan.rs` and `policy/semantic.rs`. - Drop `Script::to_bytes` (deprecated) in favour of `to_vec` in `interpreter/inner.rs`. - Migrate `secp.sign_ecdsa` / `verify_ecdsa` / `sign_schnorr_with_aux_rand` / `verify_schnorr` to the new `secp256k1::ecdsa::{sign, verify}` / `secp256k1::schnorr::{ sign_with_aux_rand, verify}` free functions (interpreter tests, `plan.rs`, `descriptor/mod.rs`, `policy/compiler.rs`). `bitcoin::ecdsa::Signature::verify(msg, pk)` is used for the inherent method style in the `verify_tx` example. - `Message::from_digest_slice` → `Message::from_digest(arr32)` in `plan.rs`. - Clean up residual unused variables (`secp_ctx` in `descriptor/mod.rs`, `secp` in `plan.rs`, example secp params) and unused `Hash` imports in iter/mod tests. - Fix the two doctests that still passed `&secp` to `DescriptorXKey::matches` and `Descriptor::derived_descriptor(index)`. - Drop secp argument from three example helpers in `examples/xpub_descriptors.rs` now that the underlying API no longer needs it. Final state: `cargo check --all-targets` is clean (0 errors, 0 warnings); `cargo test --all-targets` passes all 151 lib tests and all 9 doctests. Co-Authored-By: Claude Opus 4.7 (1M context) --- examples/psbt_sign_finalize.rs | 7 ++- examples/taproot.rs | 6 ++- .../taptree_of_horror/taptree_of_horror.rs | 4 +- examples/verify_tx.rs | 6 +-- examples/xpub_descriptors.rs | 16 +++--- src/descriptor/key.rs | 8 ++- src/descriptor/mod.rs | 42 ++++++++++----- src/interpreter/inner.rs | 25 ++++----- src/interpreter/mod.rs | 23 ++++---- src/miniscript/iter.rs | 2 +- src/miniscript/lex.rs | 2 +- src/miniscript/mod.rs | 53 +++++++++---------- src/plan.rs | 15 +++--- src/policy/compiler.rs | 6 +-- src/policy/semantic.rs | 10 ++-- src/test_utils.rs | 2 +- 16 files changed, 117 insertions(+), 110 deletions(-) diff --git a/examples/psbt_sign_finalize.rs b/examples/psbt_sign_finalize.rs index 82f23c123..105e506c2 100644 --- a/examples/psbt_sign_finalize.rs +++ b/examples/psbt_sign_finalize.rs @@ -3,16 +3,15 @@ use std::collections::BTreeMap; use std::str::FromStr; +use miniscript::bitcoin::blockdata::witness::Witness; use miniscript::bitcoin::consensus::encode::deserialize_hex; use miniscript::bitcoin::psbt::{self, Psbt}; use miniscript::bitcoin::sighash::SighashCache; +use miniscript::bitcoin::ScriptPubKey; //use miniscript::bitcoin::secp256k1; // https://github.com/rust-lang/rust/issues/121684 use miniscript::bitcoin::{ - transaction, Address, Amount, Network, OutPoint, PrivateKey, Sequence, Transaction, - TxIn, TxOut, + transaction, Address, Amount, Network, OutPoint, PrivateKey, Sequence, Transaction, TxIn, TxOut, }; -use miniscript::bitcoin::ScriptPubKey; -use miniscript::bitcoin::blockdata::witness::Witness; use miniscript::psbt::{PsbtExt, PsbtInputExt}; use miniscript::Descriptor; diff --git a/examples/taproot.rs b/examples/taproot.rs index 534413ab5..08cd78930 100644 --- a/examples/taproot.rs +++ b/examples/taproot.rs @@ -142,7 +142,11 @@ fn hardcoded_xonlypubkeys() -> Vec { ]; let mut keys: Vec = vec![]; for key in serialized_keys { - keys.push(secp256k1::XOnlyPublicKey::from_byte_array(key).unwrap().into()); + keys.push( + secp256k1::XOnlyPublicKey::from_byte_array(key) + .unwrap() + .into(), + ); } keys } diff --git a/examples/taptree_of_horror/taptree_of_horror.rs b/examples/taptree_of_horror/taptree_of_horror.rs index fa7bc70cb..d2cf8116b 100644 --- a/examples/taptree_of_horror/taptree_of_horror.rs +++ b/examples/taptree_of_horror/taptree_of_horror.rs @@ -1,12 +1,12 @@ use std::str::FromStr; use bitcoin::absolute::LockTime; +use bitcoin::blockdata::witness::Witness; use bitcoin::consensus::encode::serialize; -use bitcoin::hashes::Hash; use bitcoin::hashes::hex::prelude::DisplayHex; +use bitcoin::hashes::Hash; use bitcoin::transaction::Version; use bitcoin::{Address, Amount, Network, Psbt, PublicKey, Sequence, TxIn, TxOut}; -use bitcoin::blockdata::witness::Witness; use helper_fns::{produce_grim_hash, produce_kelly_hash, produce_key_pairs}; use miniscript::descriptor::DescriptorSecretKey; use miniscript::policy::Concrete; diff --git a/examples/verify_tx.rs b/examples/verify_tx.rs index 8ebff73d2..d6aeab2fa 100644 --- a/examples/verify_tx.rs +++ b/examples/verify_tx.rs @@ -85,15 +85,13 @@ fn main() { // // Same, but with the wrong signature hash, to demonstrate what happens // given an apparently invalid script. - let secp = Secp256k1::new(); + let _secp = Secp256k1::new(); let message = secp256k1::Message::from_digest([0x01; 32]); let iter = interpreter.iter_custom(Box::new(|key_sig: &KeySigPair| { let (pk, ecdsa_sig) = key_sig.as_ecdsa().expect("Ecdsa Sig"); ecdsa_sig.sighash_type == bitcoin::sighash::EcdsaSighashType::All - && secp - .verify_ecdsa(message, &ecdsa_sig.signature, &pk.to_inner()) - .is_ok() + && ecdsa_sig.signature.verify(message, &pk.to_inner()).is_ok() })); println!("\n\nExample three:\n"); diff --git a/examples/xpub_descriptors.rs b/examples/xpub_descriptors.rs index 2afec2819..d0b7d8109 100644 --- a/examples/xpub_descriptors.rs +++ b/examples/xpub_descriptors.rs @@ -4,7 +4,6 @@ use std::str::FromStr; -use miniscript::bitcoin::secp256k1::{Secp256k1, Verification}; use miniscript::bitcoin::{Address, Network}; use miniscript::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey}; @@ -12,21 +11,18 @@ const XPUB_1: &str = "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapS const XPUB_2: &str = "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"; fn main() { - // For deriving from descriptors, we need to provide a secp context. - let secp = Secp256k1::verification_only(); - // P2WSH and single xpubs. - let _ = p2wsh(&secp); + let _ = p2wsh(); // P2WSH-P2SH and ranged xpubs. - let _ = p2sh_p2wsh(&secp); + let _ = p2sh_p2wsh(); // P2TR with xpubs in sortedmulti_a - let _ = p2tr_sortedmulti_a(&secp); + let _ = p2tr_sortedmulti_a(); } /// Parses a P2WSH descriptor, returns the associated address. -fn p2wsh(secp: &Secp256k1) -> Address { +fn p2wsh() -> Address { // It does not matter what order the two xpubs go in, the same address will be generated. let s = format!("wsh(sortedmulti(1,{},{}))", XPUB_1, XPUB_2); // let s = format!("wsh(sortedmulti(1,{},{}))", XPUB_2, XPUB_1); @@ -48,7 +44,7 @@ fn p2wsh(secp: &Secp256k1) -> Address { } /// Parses a P2SH-P2WSH descriptor, returns the associated address. -fn p2sh_p2wsh(secp: &Secp256k1) -> Address { +fn p2sh_p2wsh() -> Address { // It does not matter what order the two xpubs go in, the same address will be generated. let s = format!("sh(wsh(sortedmulti(1,{}/1/0/*,{}/0/0/*)))", XPUB_1, XPUB_2); // let s = format!("sh(wsh(sortedmulti(1,{}/1/0/*,{}/0/0/*)))", XPUB_2, XPUB_1); @@ -69,7 +65,7 @@ fn p2sh_p2wsh(secp: &Secp256k1) -> Address { } /// Parses a P2TR sortedmulti_a descriptor, returns the associated address. -fn p2tr_sortedmulti_a(secp: &Secp256k1) -> Address { +fn p2tr_sortedmulti_a() -> Address { let internal = "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"; // It does not matter what order the two xpubs go in, the same address will be generated. let s1 = format!("tr({},sortedmulti_a(2,{}/1/0/*,{}/0/0/*))", internal, XPUB_1, XPUB_2); diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index 58e636996..7ffd094e4 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -1209,8 +1209,6 @@ impl DescriptorXKey { /// use miniscript::bitcoin::bip32; /// use miniscript::descriptor::DescriptorPublicKey; /// - /// let ctx = miniscript::bitcoin::secp256k1::Secp256k1::signing_only(); - /// /// let key = DescriptorPublicKey::from_str("[d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*").or(Err(()))?; /// let xpub = match key { /// DescriptorPublicKey::XPub(xpub) => xpub, @@ -1221,21 +1219,21 @@ impl DescriptorXKey { /// xpub.matches(&( /// bip32::Fingerprint::from_str("d34db33f").or(Err(()))?, /// bip32::DerivationPath::from_str("m/44'/0'/0'/1/42").or(Err(()))? - /// ), &ctx), + /// )), /// Some(bip32::DerivationPath::from_str("m/44'/0'/0'/1").or(Err(()))?) /// ); /// assert_eq!( /// xpub.matches(&( /// bip32::Fingerprint::from_str("ffffffff").or(Err(()))?, /// bip32::DerivationPath::from_str("m/44'/0'/0'/1/42").or(Err(()))? - /// ), &ctx), + /// )), /// None /// ); /// assert_eq!( /// xpub.matches(&( /// bip32::Fingerprint::from_str("d34db33f").or(Err(()))?, /// bip32::DerivationPath::from_str("m/44'/0'/0'/100/0").or(Err(()))? - /// ), &ctx), + /// )), /// None /// ); /// # Ok(()) diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 582e37255..17cb6177c 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -728,14 +728,13 @@ impl Descriptor { /// This is a shorthand for: /// /// ``` - /// # use miniscript::{Descriptor, DescriptorPublicKey, bitcoin::secp256k1::Secp256k1}; + /// # use miniscript::{Descriptor, DescriptorPublicKey}; /// # use core::str::FromStr; /// # let descriptor = Descriptor::::from_str("tr(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)") /// .expect("Valid ranged descriptor"); /// # let index = 42; - /// # let secp = Secp256k1::verification_only(); - /// let derived_descriptor = descriptor.derive_at_index(index).unwrap().derived_descriptor(&secp); - /// # assert_eq!(descriptor.derived_descriptor(&secp, index).unwrap(), derived_descriptor); + /// let derived_descriptor = descriptor.derive_at_index(index).unwrap().derived_descriptor(); + /// # assert_eq!(descriptor.derived_descriptor(index).unwrap(), derived_descriptor); /// ``` /// /// and is only here really here for backwards compatibility. @@ -1166,10 +1165,9 @@ pub(crate) use write_descriptor; mod tests { use core::convert::TryFrom; + use bitcoin::blockdata::opcodes; use bitcoin::blockdata::opcodes::all::{OP_CLTV, OP_CSV}; use bitcoin::blockdata::script::Instruction; - use bitcoin::blockdata::{opcodes, script}; - use bitcoin::hashes::Hash; use bitcoin::script::{PushBytes, ScriptExt as _, WitnessScriptExt as _}; use bitcoin::sighash::EcdsaSighashType; use bitcoin::{bip32, PublicKey, Sequence, XOnlyPublicKey}; @@ -1433,7 +1431,8 @@ mod tests { let mut msg_bytes = [0u8; 32]; msg_bytes.copy_from_slice(&b"michael was a message, amusingly"[..]); let msg = secp256k1::Message::from_digest(msg_bytes); - let sig = secp.sign_ecdsa(msg, &sk); + let _ = &secp; + let sig = secp256k1::ecdsa::sign(msg, &sk); let mut sigser = sig.serialize_der().to_vec(); sigser.push(0x01); // sighash_all @@ -1579,7 +1578,15 @@ mod tests { bitcoin::TxIn { previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, script_sig: bitcoin::script::Builder::::new() - .push_slice(<&PushBytes>::try_from(bitcoin::WitnessScriptBuf::from(ms.encode().into_bytes()).to_p2wsh().unwrap().as_bytes()).unwrap()) + .push_slice( + <&PushBytes>::try_from( + bitcoin::WitnessScriptBuf::from(ms.encode().into_bytes()) + .to_p2wsh() + .unwrap() + .as_bytes() + ) + .unwrap() + ) .into_script(), sequence: Sequence::from_height(100), witness: Witness::from_slice(&[sigser.clone(), ms.encode().into_bytes()]), @@ -1588,7 +1595,15 @@ mod tests { assert_eq!( shwsh.unsigned_script_sig(), crate::ScriptBuilder::new() - .push_slice(<&PushBytes>::try_from(bitcoin::WitnessScriptBuf::from(ms.encode().into_bytes()).to_p2wsh().unwrap().as_bytes()).unwrap()) + .push_slice( + <&PushBytes>::try_from( + bitcoin::WitnessScriptBuf::from(ms.encode().into_bytes()) + .to_p2wsh() + .unwrap() + .as_bytes() + ) + .unwrap() + ) .into_script() ); } @@ -1915,7 +1930,6 @@ mod tests { #[test] fn test_sortedmulti() { fn _test_sortedmulti(raw_desc_one: &str, raw_desc_two: &str, raw_addr_expected: &str) { - let secp_ctx = secp256k1::Secp256k1::verification_only(); let index = 5; // Parse descriptor @@ -1948,8 +1962,6 @@ mod tests { assert_eq!(addr_two, addr_expected); } - let secp_ctx = secp256k1::Secp256k1::verification_only(); - // P2SH and pubkeys (no wildcard — descriptors are fully defined) { let desc_strs = [ @@ -2105,8 +2117,10 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))"; fn test_find_derivation_index_for_spk() { let descriptor = Descriptor::from_str("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)").unwrap(); let script_at_0_1 = ScriptBuf::from_bytes( - hex::decode_to_vec("5120a82f29944d65b86ae6b5e5cc75e294ead6c59391a1edc5e016e3498c67fc7bbb") - .unwrap(), + hex::decode_to_vec( + "5120a82f29944d65b86ae6b5e5cc75e294ead6c59391a1edc5e016e3498c67fc7bbb", + ) + .unwrap(), ); let expected_concrete = Descriptor::from_str( "tr(0283dfe85a3151d2517290da461fe2815591ef69f2b18a2ce63f01697a8b313145)", diff --git a/src/interpreter/inner.rs b/src/interpreter/inner.rs index 256fb2b96..9485d37b4 100644 --- a/src/interpreter/inner.rs +++ b/src/interpreter/inner.rs @@ -510,14 +510,14 @@ mod tests { .into_script(), pkh_sig_justkey: ScriptBuilderLocal::new().push_key(key).into_script(), wpkh_spk: wpkh_spk.clone(), - wpkh_stack: Witness::from_slice(&[dummy_sig_vec.clone(), key.to_bytes()]), - wpkh_stack_justkey: Witness::from_slice(&[key.to_bytes()]), + wpkh_stack: Witness::from_slice(&[dummy_sig_vec.clone(), key.to_vec()]), + wpkh_stack_justkey: Witness::from_slice(&[key.to_vec()]), sh_wpkh_spk: ScriptBuf::new_p2sh(wpkh_scripthash), sh_wpkh_sig: ScriptBuilderLocal::new() .push_slice(<&PushBytes>::try_from(wpkh_spk[..].as_bytes()).unwrap()) .into_script(), - sh_wpkh_stack: Witness::from_slice(&[dummy_sig_vec, key.to_bytes()]), - sh_wpkh_stack_justkey: Witness::from_slice(&[key.to_bytes()]), + sh_wpkh_stack: Witness::from_slice(&[dummy_sig_vec, key.to_vec()]), + sh_wpkh_stack_justkey: Witness::from_slice(&[key.to_vec()]), } } } @@ -582,14 +582,14 @@ mod tests { assert_eq!(script_code, Some(uncomp.pk_spk)); // Scriptpubkey has invalid key - let mut spk = comp.pk_spk.to_bytes(); + let mut spk = comp.pk_spk.to_vec(); spk[1] = 5; let spk = ScriptBuf::from(spk); let err = from_txdata(&spk, &ScriptBuf::new(), &empty_wit).unwrap_err(); assert_eq!(err.to_string(), "could not parse pubkey"); // Scriptpubkey has invalid script - let mut spk = comp.pk_spk.to_bytes(); + let mut spk = comp.pk_spk.to_vec(); spk[0] = 100; let spk = ScriptBuf::from(spk); let err = from_txdata(&spk, &ScriptBuf::new(), &empty_wit).unwrap_err(); @@ -737,10 +737,7 @@ mod tests { from_txdata(&comp.sh_wpkh_spk, &comp.sh_wpkh_sig, &comp.sh_wpkh_stack) .expect("parse txdata"); assert_eq!(inner, Inner::PublicKey(fixed.pk_comp.into(), PubkeyType::ShWpkh)); - assert_eq!( - stack, - Stack::from(vec![comp.sh_wpkh_stack.get_back(1).unwrap().into()]) - ); + assert_eq!(stack, Stack::from(vec![comp.sh_wpkh_stack.get_back(1).unwrap().into()])); assert_eq!(script_code, Some(comp.pkh_spk.clone())); } @@ -821,7 +818,7 @@ mod tests { let wit_hash = bitcoin::script::WScriptHash::from_byte_array( sha256::Hash::hash(witness_script.as_bytes()).to_byte_array(), ); - let wit_stack = Witness::from_slice(&[witness_script.to_bytes()]); + let wit_stack = Witness::from_slice(&[witness_script.to_vec()]); let spk = ScriptBuf::new_p2wsh(wit_hash); let blank_script = ScriptBuf::new(); @@ -831,7 +828,7 @@ mod tests { assert_eq!(&err.to_string(), "unexpected end of stack"); // with incorrect witness - let wit = Witness::from_slice(&[spk.to_bytes()]); + let wit = Witness::from_slice(&[spk.to_vec()]); let err = from_txdata(&spk, &blank_script, &wit).unwrap_err(); assert_eq!(&err.to_string()[0..12], "parse error:"); @@ -858,7 +855,7 @@ mod tests { let wit_hash = bitcoin::script::WScriptHash::from_byte_array( sha256::Hash::hash(witness_script.as_bytes()).to_byte_array(), ); - let wit_stack = Witness::from_slice(&[witness_script.to_bytes()]); + let wit_stack = Witness::from_slice(&[witness_script.to_vec()]); let redeem_script = ScriptBuf::new_p2wsh(wit_hash); let script_sig = ScriptBuilderLocal::new() @@ -880,7 +877,7 @@ mod tests { assert_eq!(&err.to_string(), "unexpected end of stack"); // with incorrect witness - let wit = Witness::from_slice(&[spk.to_bytes()]); + let wit = Witness::from_slice(&[spk.to_vec()]); let err = from_txdata(&spk, &script_sig, &wit).unwrap_err(); assert_eq!(&err.to_string()[0..12], "parse error:"); diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index f44d57c85..c7a820b1f 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -1094,7 +1094,7 @@ mod tests { let sk = secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"); let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key(&sk)); - let signature = secp.sign_ecdsa(msg, &sk); + let signature = secp256k1::ecdsa::sign(msg, &sk); ecdsa_sigs.push(bitcoin::ecdsa::Signature { signature, sighash_type: bitcoin::sighash::EcdsaSighashType::All, @@ -1106,10 +1106,13 @@ mod tests { let secp_keypair = secp256k1::Keypair::from_secret_key(&sk); let keypair = bitcoin::key::Keypair::from_secp(secp_keypair); - let x_only_pk = bitcoin::key::XOnlyPublicKey::from_keypair(&keypair); + // The interpreter reconstructs XOnlyPublicKey from a 32-byte push with default (Even) + // parity; normalise the test's expected keys the same way so assertions line up. + let x_only_pk = bitcoin::key::XOnlyPublicKey::from_keypair(&keypair) + .with_parity(bitcoin::secp256k1::Parity::Even); x_only_pks.push(x_only_pk); let schnorr_sig = - secp.sign_schnorr_with_aux_rand(msg.as_ref(), &secp_keypair, &[0u8; 32]); + secp256k1::schnorr::sign_with_aux_rand(msg.as_ref(), &secp_keypair, &[0u8; 32]); let schnorr_sig = bitcoin::taproot::Signature { signature: schnorr_sig, sighash_type: bitcoin::sighash::TapSighashType::Default, @@ -1125,13 +1128,15 @@ mod tests { let (pks, der_sigs, ecdsa_sigs, sighash, secp, xpks, schnorr_sigs, ser_schnorr_sigs) = setup_keys_sigs(10); let secp_ref = &secp; + let _ = secp_ref; let vfyfn = |pksig: &KeySigPair| match pksig { - KeySigPair::Ecdsa(pk, ecdsa_sig) => secp_ref - .verify_ecdsa(sighash, &ecdsa_sig.signature, &pk.to_inner()) - .is_ok(), - KeySigPair::Schnorr(xpk, schnorr_sig) => secp_ref - .verify_schnorr(&schnorr_sig.signature, sighash.as_ref(), xpk.as_inner()) - .is_ok(), + KeySigPair::Ecdsa(pk, ecdsa_sig) => { + ecdsa_sig.signature.verify(sighash, &pk.to_inner()).is_ok() + } + KeySigPair::Schnorr(xpk, schnorr_sig) => { + secp256k1::schnorr::verify(&schnorr_sig.signature, sighash.as_ref(), xpk.as_inner()) + .is_ok() + } }; fn from_stack<'txin, 'elem>( diff --git a/src/miniscript/iter.rs b/src/miniscript/iter.rs index fe8f4ace2..f108466f7 100644 --- a/src/miniscript/iter.rs +++ b/src/miniscript/iter.rs @@ -211,7 +211,7 @@ impl Iterator for PkIter<'_, Pk, Ctx> { /// dependent libraries for their own tasts based on Miniscript AST #[cfg(test)] pub mod test { - use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; + use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d}; use super::Miniscript; use crate::miniscript::context::Segwitv0; diff --git a/src/miniscript/lex.rs b/src/miniscript/lex.rs index 3c0964afd..2ad5e448b 100644 --- a/src/miniscript/lex.rs +++ b/src/miniscript/lex.rs @@ -223,7 +223,7 @@ pub fn lex(script: &'_ Script) -> Result, Error> { ret.push(Token::Bytes65(bytes)); } else { // check minimality of the number - match script::read_scriptint_non_minimal(bytes.as_bytes()) { + match bytes.read_scriptint() { Ok(v) if v >= 0 => { ret.push(Token::Num(v as u32)); } diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 91e235b57..b644b2f6b 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -1104,7 +1104,7 @@ mod tests { use core::str; use core::str::FromStr; - use bitcoin::hashes::{hash160, sha256, Hash}; + use bitcoin::hashes::{hash160, sha256}; use bitcoin::secp256k1::XOnlyPublicKey; use bitcoin::taproot::TapLeafHash; use sync::Arc; @@ -1337,10 +1337,10 @@ mod tests { #[test] fn true_false() { - roundtrip(&ms_str!("1"), "OP_PUSHNUM_1"); - roundtrip(&ms_str!("tv:1"), "OP_PUSHNUM_1 OP_VERIFY OP_PUSHNUM_1"); + roundtrip(&ms_str!("1"), "OP_1"); + roundtrip(&ms_str!("tv:1"), "OP_1 OP_VERIFY OP_1"); roundtrip(&ms_str!("0"), "OP_0"); - roundtrip(&ms_str!("andor(0,1,0)"), "OP_0 OP_NOTIF OP_0 OP_ELSE OP_PUSHNUM_1 OP_ENDIF"); + roundtrip(&ms_str!("andor(0,1,0)"), "OP_0 OP_NOTIF OP_0 OP_ELSE OP_1 OP_ENDIF"); assert!(Segwitv0Script::from_str("1()").is_err()); assert!(Segwitv0Script::from_str("tv:1()").is_err()); @@ -1373,7 +1373,7 @@ mod tests { string_rtt( script, - "[B/onduesm]pk(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "[B/onduesm]pk(PublicKey { compressed: true, inner: 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa })", "pk(028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa)" ); @@ -1381,7 +1381,7 @@ mod tests { string_rtt( script, - "[B/onduesm]pk(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "[B/onduesm]pk(PublicKey { compressed: true, inner: 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa })", "pk(028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa)" ); @@ -1389,7 +1389,7 @@ mod tests { string_rtt( script, - "[B/onufsm]t[V/onfsm]v:[B/onduesm]pk(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "[B/onufsm]t[V/onfsm]v:[B/onduesm]pk(PublicKey { compressed: true, inner: 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa })", "tv:pk(028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa)" ); @@ -1397,7 +1397,7 @@ mod tests { string_display_debug_test( script, - "[B/nduesm]pkh(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "[B/nduesm]pkh(PublicKey { compressed: true, inner: 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa })", "pkh(028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa)", ); @@ -1405,7 +1405,7 @@ mod tests { string_display_debug_test( script, - "[B/nduesm]pkh(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "[B/nduesm]pkh(PublicKey { compressed: true, inner: 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa })", "pkh(028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa)", ); @@ -1413,7 +1413,7 @@ mod tests { string_display_debug_test( script, - "[B/nufsm]t[V/nfsm]v:[B/nduesm]pkh(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "[B/nufsm]t[V/nfsm]v:[B/nduesm]pkh(PublicKey { compressed: true, inner: 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa })", "tv:pkh(028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa)", ); } @@ -1439,7 +1439,7 @@ mod tests { ); roundtrip( &ms_str!("multi(3,{},{},{},{},{})", keys[0], keys[1], keys[2], keys[3], keys[4]), - "OP_PUSHNUM_3 OP_PUSHBYTES_33 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa OP_PUSHBYTES_33 03ab1ac1872a38a2f196bed5a6047f0da2c8130fe8de49fc4d5dfb201f7611d8e2 OP_PUSHBYTES_33 039729247032c0dfcf45b4841fcd72f6e9a2422631fc3466cf863e87154754dd40 OP_PUSHBYTES_33 032564fe9b5beef82d3703a607253f31ef8ea1b365772df434226aee642651b3fa OP_PUSHBYTES_33 0289637f97580a796e050791ad5a2f27af1803645d95df021a3c2d82eb8c2ca7ff OP_PUSHNUM_5 OP_CHECKMULTISIG" + "OP_3 OP_PUSHBYTES_33 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa OP_PUSHBYTES_33 03ab1ac1872a38a2f196bed5a6047f0da2c8130fe8de49fc4d5dfb201f7611d8e2 OP_PUSHBYTES_33 039729247032c0dfcf45b4841fcd72f6e9a2422631fc3466cf863e87154754dd40 OP_PUSHBYTES_33 032564fe9b5beef82d3703a607253f31ef8ea1b365772df434226aee642651b3fa OP_PUSHBYTES_33 0289637f97580a796e050791ad5a2f27af1803645d95df021a3c2d82eb8c2ca7ff OP_5 OP_CHECKMULTISIG" ); // Liquid policy @@ -1449,13 +1449,13 @@ mod tests { keys[1].to_string(), keys[3].to_string(), keys[4].to_string()), - "OP_PUSHNUM_2 OP_PUSHBYTES_33 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa \ + "OP_2 OP_PUSHBYTES_33 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa \ OP_PUSHBYTES_33 03ab1ac1872a38a2f196bed5a6047f0da2c8130fe8de49fc4d5dfb201f7611d8e2 \ - OP_PUSHNUM_2 OP_CHECKMULTISIG \ + OP_2 OP_CHECKMULTISIG \ OP_IFDUP OP_NOTIF \ - OP_PUSHNUM_2 OP_PUSHBYTES_33 032564fe9b5beef82d3703a607253f31ef8ea1b365772df434226aee642651b3fa \ + OP_2 OP_PUSHBYTES_33 032564fe9b5beef82d3703a607253f31ef8ea1b365772df434226aee642651b3fa \ OP_PUSHBYTES_33 0289637f97580a796e050791ad5a2f27af1803645d95df021a3c2d82eb8c2ca7ff \ - OP_PUSHNUM_2 OP_CHECKMULTISIGVERIFY \ + OP_2 OP_CHECKMULTISIGVERIFY \ OP_PUSHBYTES_2 1027 OP_CSV \ OP_ENDIF" ); @@ -1491,13 +1491,13 @@ mod tests { roundtrip( &ms_str!("multi(3,{},{},{},{},{})", keys[0], keys[1], keys[2], keys[3], keys[4]), - "OP_PUSHNUM_3 \ + "OP_3 \ OP_PUSHBYTES_33 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa \ OP_PUSHBYTES_33 03ab1ac1872a38a2f196bed5a6047f0da2c8130fe8de49fc4d5dfb201f7611d8e2 \ OP_PUSHBYTES_33 039729247032c0dfcf45b4841fcd72f6e9a2422631fc3466cf863e87154754dd40 \ OP_PUSHBYTES_33 032564fe9b5beef82d3703a607253f31ef8ea1b365772df434226aee642651b3fa \ OP_PUSHBYTES_33 0289637f97580a796e050791ad5a2f27af1803645d95df021a3c2d82eb8c2ca7ff \ - OP_PUSHNUM_5 OP_CHECKMULTISIG", + OP_5 OP_CHECKMULTISIG", ); roundtrip( @@ -1506,11 +1506,11 @@ mod tests { vu:hash256(131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b),\ v:sha256(ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5)\ )"), - "OP_IF OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_HASH256 OP_PUSHBYTES_32 131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b OP_EQUAL OP_ELSE OP_0 OP_ENDIF OP_VERIFY OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_SHA256 OP_PUSHBYTES_32 ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5 OP_EQUALVERIFY OP_PUSHNUM_1" + "OP_IF OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_HASH256 OP_PUSHBYTES_32 131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b OP_EQUAL OP_ELSE OP_0 OP_ENDIF OP_VERIFY OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_SHA256 OP_PUSHBYTES_32 ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5 OP_EQUALVERIFY OP_1" ); roundtrip( &ms_str!("and_n(pk(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729),and_b(l:older(4252898),a:older(16)))"), - "OP_PUSHBYTES_33 03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729 OP_CHECKSIG OP_NOTIF OP_0 OP_ELSE OP_IF OP_0 OP_ELSE OP_PUSHBYTES_3 e2e440 OP_CSV OP_ENDIF OP_TOALTSTACK OP_PUSHNUM_16 OP_CSV OP_FROMALTSTACK OP_BOOLAND OP_ENDIF" + "OP_PUSHBYTES_33 03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729 OP_CHECKSIG OP_NOTIF OP_0 OP_ELSE OP_IF OP_0 OP_ELSE OP_PUSHBYTES_3 e2e440 OP_CSV OP_ENDIF OP_TOALTSTACK OP_16 OP_CSV OP_FROMALTSTACK OP_BOOLAND OP_ENDIF" ); roundtrip( &ms_str!( @@ -1523,12 +1523,12 @@ mod tests { v:older(4194305),\ v:sha256(9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2)\ )"), - "OP_PUSHNUM_3 OP_PUSHBYTES_33 02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e \ + "OP_3 OP_PUSHBYTES_33 02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e \ OP_PUSHBYTES_33 03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556 \ OP_PUSHBYTES_33 02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13 \ - OP_PUSHNUM_3 OP_CHECKMULTISIG OP_NOTIF OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_SHA256 \ + OP_3 OP_CHECKMULTISIG OP_NOTIF OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_SHA256 \ OP_PUSHBYTES_32 9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2 OP_EQUALVERIFY \ - OP_ELSE OP_PUSHBYTES_3 010040 OP_CSV OP_VERIFY OP_ENDIF OP_PUSHNUM_1" + OP_ELSE OP_PUSHBYTES_3 010040 OP_CSV OP_VERIFY OP_ENDIF OP_1" ); roundtrip( &ms_str!( @@ -1539,14 +1539,14 @@ mod tests { "\ OP_IF OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_HASH256 OP_PUSHBYTES_32 131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b OP_EQUAL \ OP_ELSE OP_0 OP_ENDIF OP_VERIFY OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_SHA256 OP_PUSHBYTES_32 ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5 OP_EQUALVERIFY \ - OP_PUSHNUM_1\ + OP_1\ " ); // Thresh bug with equal verify roundtrip roundtrip( &ms_str!("tv:thresh(1,pk(02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e))", ), - "OP_PUSHBYTES_33 02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e OP_CHECKSIG OP_PUSHNUM_1 OP_EQUALVERIFY OP_PUSHNUM_1", + "OP_PUSHBYTES_33 02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e OP_CHECKSIG OP_1 OP_EQUALVERIFY OP_1", ); } @@ -1733,9 +1733,8 @@ mod tests { "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c", ) .unwrap(); - let hash160 = bitcoin::hashes::hash160::Hash::from_byte_array( - pk.pubkey_hash().to_byte_array(), - ); + let hash160 = + bitcoin::hashes::hash160::Hash::from_byte_array(pk.pubkey_hash().to_byte_array()); let ms_str = &format!("c:expr_raw_pkh({})", hash160); type SegwitMs = Miniscript; diff --git a/src/plan.rs b/src/plan.rs index 413a050f3..e31e56112 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -747,7 +747,6 @@ mod test { use std::str::FromStr; use bitcoin::bip32::Xpub; - use secp256k1::Secp256k1; use super::*; use crate::*; @@ -953,7 +952,7 @@ mod test { vec![0, 1], vec![], None, - Some(absolute::LockTime::from_time(500_001_000).unwrap()), + Some(absolute::LockTime::from_mtp(500_001_000).unwrap()), Some(153), ), // incompatible timelock ]; @@ -1055,7 +1054,7 @@ mod test { vec![4], vec![], None, - Some(absolute::LockTime::from_time(1296000000).unwrap()), + Some(absolute::LockTime::from_mtp(1296000000).unwrap()), None, ), // Spend with third leaf (key + timelock), @@ -1178,8 +1177,6 @@ mod test { desc_str_fn: fn(&[bitcoin::PublicKey]) -> String, exp_witness_len: usize, ) -> Vec> { - let secp = Secp256k1::new(); - let (sks, pks): (Vec<_>, Vec<_>) = [ b"sally was a secret key, she said", b"polly was a secret key, she said", @@ -1198,11 +1195,11 @@ mod test { let sigs = sks .iter() .map(|sk| { - let sighash = - secp256k1::Message::from_digest_slice(&b"michael was a message, amusingly"[..]) - .expect("32 bytes"); + let mut msg_bytes = [0u8; 32]; + msg_bytes.copy_from_slice(&b"michael was a message, amusingly"[..]); + let sighash = secp256k1::Message::from_digest(msg_bytes); bitcoin::ecdsa::Signature { - signature: secp.sign_ecdsa(sighash, sk), + signature: secp256k1::ecdsa::sign(sighash, sk), sighash_type: bitcoin::sighash::EcdsaSighashType::All, } }) diff --git a/src/policy/compiler.rs b/src/policy/compiler.rs index 2d7519d21..840cc773a 100644 --- a/src/policy/compiler.rs +++ b/src/policy/compiler.rs @@ -1276,13 +1276,13 @@ mod tests { sk[2] = (i >> 16) as u8; let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key( - &secp, &secp256k1::SecretKey::from_secret_bytes(sk).expect("sk"), )); ret.push(pk); } - let sig = secp.sign_ecdsa( - &secp256k1::Message::from_digest(sk), // Not a digest but 32 bytes nonetheless. + let _ = &secp; + let sig = secp256k1::ecdsa::sign( + secp256k1::Message::from_digest(sk), // Not a digest but 32 bytes nonetheless. &secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"), ); (ret, sig) diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs index 15ba83618..0c944d441 100644 --- a/src/policy/semantic.rs +++ b/src/policy/semantic.rs @@ -896,7 +896,7 @@ mod tests { assert_eq!( policy .clone() - .at_lock_time(absolute::LockTime::from_time(500_000_001).expect("valid timestamp")), + .at_lock_time(absolute::LockTime::from_mtp(500_000_001).expect("valid timestamp")), Policy::Unsatisfiable ); assert_eq!(policy.n_keys(), 0); @@ -931,25 +931,25 @@ mod tests { assert_eq!( policy .clone() - .at_lock_time(absolute::LockTime::from_time(500_000_000).expect("valid timestamp")), + .at_lock_time(absolute::LockTime::from_mtp(500_000_000).expect("valid timestamp")), Policy::Unsatisfiable ); assert_eq!( policy .clone() - .at_lock_time(absolute::LockTime::from_time(500_000_001).expect("valid timestamp")), + .at_lock_time(absolute::LockTime::from_mtp(500_000_001).expect("valid timestamp")), Policy::Unsatisfiable ); assert_eq!( policy .clone() - .at_lock_time(absolute::LockTime::from_time(500_000_010).expect("valid timestamp")), + .at_lock_time(absolute::LockTime::from_mtp(500_000_010).expect("valid timestamp")), policy ); assert_eq!( policy .clone() - .at_lock_time(absolute::LockTime::from_time(500_000_012).expect("valid timestamp")), + .at_lock_time(absolute::LockTime::from_mtp(500_000_012).expect("valid timestamp")), policy ); assert_eq!(policy.n_keys(), 0); diff --git a/src/test_utils.rs b/src/test_utils.rs index ac922195f..81e2b204a 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -7,9 +7,9 @@ use std::collections::HashMap; use std::str::FromStr; use bitcoin::hashes::{hash160, ripemd160, sha256}; -use bitcoin::secp256k1::XOnlyPublicKey; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 use bitcoin::secp256k1; +use bitcoin::secp256k1::XOnlyPublicKey; use crate::miniscript::context::SigType; use crate::{hash256, ToPublicKey, Translator}; From 3f63efc24455bcc54e0c29160c2ebcf711695931 Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 14:27:52 -0600 Subject: [PATCH 09/23] bitcoin 0.33: restore MasterFingerprint error source Introduces MasterFingerprintHexError, a small wrapper that captures the displayed form of the upstream `hex-conservative` parse error and implements `std::error::Error`, so the `source()` chain for DescriptorKeyParseError::MasterFingerprint points at the underlying hex-parse error again. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/descriptor/key.rs | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index 7ffd094e4..c7f9889fc 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -374,6 +374,26 @@ impl fmt::Display for NonDefiniteKeyError { #[cfg(feature = "std")] impl error::Error for NonDefiniteKeyError {} +/// Error parsing the hex string of a master key fingerprint. +/// +/// The underlying `Fingerprint::from_hex` surfaces its error from an unstable +/// `hex-conservative` version that is not re-exported from `bitcoin`, so we +/// capture its textual representation and expose it as a proper [`error::Error`]. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct MasterFingerprintHexError(String); + +impl MasterFingerprintHexError { + /// Construct from any displayable source error. + pub fn from_display(err: E) -> Self { Self(err.to_string()) } +} + +impl fmt::Display for MasterFingerprintHexError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.0) } +} + +#[cfg(feature = "std")] +impl error::Error for MasterFingerprintHexError {} + /// Kinds of malformed key data #[derive(Debug, PartialEq, Eq, Clone)] #[non_exhaustive] @@ -439,8 +459,8 @@ pub enum DescriptorKeyParseError { MasterFingerprint { /// The invalid fingerprint fingerprint: String, - /// The underlying parse error (displayed as a string) - err: String, + /// The underlying hex parse error. + err: MasterFingerprintHexError, }, /// Attempt to construct a [`DefiniteDescriptorKey`] from an ambiguous key. NonDefiniteKey(NonDefiniteKeyError), @@ -482,7 +502,7 @@ impl error::Error for DescriptorKeyParseError { Self::DerivationIndexError { err, .. } => Some(err), Self::DeriveHardenedKey(err) => Some(err), Self::MasterDerivationPath(err) => Some(err), - Self::MasterFingerprint { .. } => None, + Self::MasterFingerprint { err, .. } => Some(err), Self::NonDefiniteKey(err) => Some(err), Self::FullPublicKey(err) => Some(err), Self::WifPrivateKey(err) => Some(err), @@ -1053,7 +1073,7 @@ fn parse_key_origin(s: &str) -> Result<(&str, Option), Descrip let parent_fingerprint = bip32::Fingerprint::from_hex(origin_id_hex).map_err(|err| { DescriptorKeyParseError::MasterFingerprint { fingerprint: origin_id_hex.to_owned(), - err: err.to_string(), + err: MasterFingerprintHexError::from_display(err), } })?; let origin_path = raw_origin From 1a654a3975ddde4ce360bca5df70fd0a10205b29 Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 14:36:23 -0600 Subject: [PATCH 10/23] bitcoin 0.33: drop secp parameter from parse_descriptor and friends bitcoin 0.33 exposes `PrivateKey::public_key`, `Xpriv::derive_priv`, `Xpub::from_priv`, and `Fingerprint` without requiring a `Secp256k1` context (the crate uses a global verification-only context internally), so the public API can shed the unused parameter. - DescriptorSecretKey::to_public, DescriptorXKey::to_public, and DescriptorMultiXKey::to_public no longer take a Secp256k1 reference. - KeyMap::insert drops its secp parameter and generic. - Descriptor::parse_descriptor drops secp, simplifying both the user entry point and the internal `KeyMapWrapper` translator. - Propagate the signature change through every test, example, and fuzz target that previously constructed a context just to hand to one of these calls. This matches the direction taken by upstream PR #874 and removes the last trace of the pre-0.33 "pass a context everywhere" pattern from the public API. Co-Authored-By: Claude Opus 4.7 (1M context) --- fuzz/fuzz_targets/parse_descriptor_priv.rs | 4 +- src/descriptor/key.rs | 44 +++++++--------------- src/descriptor/key_map.rs | 38 +++++-------------- src/descriptor/mod.rs | 36 ++++++++---------- 4 files changed, 40 insertions(+), 82 deletions(-) diff --git a/fuzz/fuzz_targets/parse_descriptor_priv.rs b/fuzz/fuzz_targets/parse_descriptor_priv.rs index 98bfb992c..41c22720d 100644 --- a/fuzz/fuzz_targets/parse_descriptor_priv.rs +++ b/fuzz/fuzz_targets/parse_descriptor_priv.rs @@ -1,14 +1,12 @@ #![allow(unexpected_cfgs)] use honggfuzz::fuzz; -use miniscript::bitcoin::secp256k1; use miniscript::Descriptor; fn do_test(data: &[u8]) { let data_str = String::from_utf8_lossy(data); - let secp = &secp256k1::Secp256k1::signing_only(); - if let Ok((desc, _)) = Descriptor::parse_descriptor(secp, &data_str) { + if let Ok((desc, _)) = Descriptor::parse_descriptor(&data_str) { let _output = desc.to_string(); let _sanity_check = desc.sanity_check(); } diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index c7f9889fc..7170a8327 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -8,7 +8,6 @@ use std::error; use bitcoin::hashes::{hash160, ripemd160, sha256, HashEngine}; use bitcoin::key::{PublicKey, XOnlyPublicKey}; -use bitcoin::secp256k1::{Secp256k1, Signing}; use bitcoin::{bip32, NetworkKind}; use super::WalletPolicyError; @@ -223,10 +222,7 @@ impl DescriptorXKey { /// If the key already has an origin, the derivation steps applied will be appended to the path /// already present, otherwise this key will be treated as a master key and an origin will be /// added with this key's fingerprint and the derivation steps applied. - fn to_public( - &self, - _secp: &Secp256k1, - ) -> Result, DescriptorKeyParseError> { + fn to_public(&self) -> Result, DescriptorKeyParseError> { let unhardened = self .derivation_path .into_iter() @@ -269,10 +265,7 @@ impl DescriptorMultiXKey { /// are shared among all derivation paths before turning it into a public key. /// /// Errors if there are hardened derivation steps that are not shared among all paths. - fn to_public( - &self, - _secp: &Secp256k1, - ) -> Result, DescriptorKeyParseError> { + fn to_public(&self) -> Result, DescriptorKeyParseError> { let deriv_paths = self.derivation_paths.paths(); let shared_prefix: Vec<_> = deriv_paths[0] @@ -580,15 +573,12 @@ impl DescriptorSecretKey { /// /// It will return an error if the key is a "multi-xpriv" that includes /// hardened derivation steps not shared for all paths. - pub fn to_public( - &self, - secp: &Secp256k1, - ) -> Result { + pub fn to_public(&self) -> Result { let pk = match self { DescriptorSecretKey::Single(prv) => DescriptorPublicKey::Single(prv.to_public()), - DescriptorSecretKey::XPrv(xprv) => DescriptorPublicKey::XPub(xprv.to_public(secp)?), + DescriptorSecretKey::XPrv(xprv) => DescriptorPublicKey::XPub(xprv.to_public()?), DescriptorSecretKey::MultiXPrv(xprv) => { - DescriptorPublicKey::MultiXPub(xprv.to_public(secp)?) + DescriptorPublicKey::MultiXPub(xprv.to_public()?) } }; @@ -1568,35 +1558,33 @@ mod test { #[test] fn test_deriv_on_xprv() { - let secp = secp256k1::Secp256k1::signing_only(); - let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2").unwrap(); - let public_key = secret_key.to_public(&secp).unwrap(); + let public_key = secret_key.to_public().unwrap(); assert_eq!(public_key.to_string(), "[2cbe2a6d/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2"); assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d"); assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'/2"); assert!(!public_key.has_wildcard()); let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2'").unwrap(); - let public_key = secret_key.to_public(&secp).unwrap(); + let public_key = secret_key.to_public().unwrap(); assert_eq!(public_key.to_string(), "[2cbe2a6d/0'/1'/2']tpubDDPuH46rv4dbFtmF6FrEtJEy1CvLZonyBoVxF6xsesHdYDdTBrq2mHhm8AbsPh39sUwL2nZyxd6vo4uWNTU9v4t893CwxjqPnwMoUACLvMV"); assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d"); assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'/2'"); let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0/1/2").unwrap(); - let public_key = secret_key.to_public(&secp).unwrap(); + let public_key = secret_key.to_public().unwrap(); assert_eq!(public_key.to_string(), "tpubD6NzVbkrYhZ4WQdzxL7NmJN7b85ePo4p6RSj9QQHF7te2RR9iUeVSGgnGkoUsB9LBRosgvNbjRv9bcsJgzgBd7QKuxDm23ZewkTRzNSLEDr/0/1/2"); assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d"); assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0/1/2"); let secret_key = DescriptorSecretKey::from_str("[aabbccdd]tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0/1/2").unwrap(); - let public_key = secret_key.to_public(&secp).unwrap(); + let public_key = secret_key.to_public().unwrap(); assert_eq!(public_key.to_string(), "[aabbccdd]tpubD6NzVbkrYhZ4WQdzxL7NmJN7b85ePo4p6RSj9QQHF7te2RR9iUeVSGgnGkoUsB9LBRosgvNbjRv9bcsJgzgBd7QKuxDm23ZewkTRzNSLEDr/0/1/2"); assert_eq!(public_key.master_fingerprint().to_string(), "aabbccdd"); assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0/1/2"); let secret_key = DescriptorSecretKey::from_str("[aabbccdd/90']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2").unwrap(); - let public_key = secret_key.to_public(&secp).unwrap(); + let public_key = secret_key.to_public().unwrap(); assert_eq!(public_key.to_string(), "[aabbccdd/90'/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2"); assert_eq!(public_key.master_fingerprint().to_string(), "aabbccdd"); assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "90'/0'/1'/2"); @@ -1634,8 +1622,6 @@ mod test { #[test] fn multipath_extended_keys() { - let secp = secp256k1::Secp256k1::signing_only(); - // We can have a key in a descriptor that has multiple paths let xpub = get_multipath_xpub("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/<0;1;42;9854>", 4); assert_eq!( @@ -1792,7 +1778,7 @@ mod test { get_multipath_xprv(&DescriptorSecretKey::MultiXPrv(xprv.clone()).to_string()) ); let desc_key = DescriptorSecretKey::from_str("[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/<0';1>/8h/*'").unwrap(); - assert!(desc_key.to_public(&secp).is_err()); + assert!(desc_key.to_public().is_err()); assert!(desc_key.is_multipath()); assert_eq!(desc_key.into_single_keys(), vec![DescriptorSecretKey::from_str("[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/0'/8h/*'").unwrap(), DescriptorSecretKey::from_str("[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/1/8h/*'").unwrap()]); @@ -1811,16 +1797,14 @@ mod test { #[test] fn test_multixprv_to_public() { - let secp = secp256k1::Secp256k1::signing_only(); - // Works if all hardended derivation steps are part of the shared path let xprv = get_multipath_xprv("[01020304/5]tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1'/2'/3/<4;5>/6"); - let xpub = DescriptorPublicKey::MultiXPub(xprv.to_public(&secp).unwrap()); // wrap in a DescriptorPublicKey to have Display + let xpub = DescriptorPublicKey::MultiXPub(xprv.to_public().unwrap()); // wrap in a DescriptorPublicKey to have Display assert_eq!(xpub.to_string(), "[01020304/5/1'/2']tpubDBTRkEMEFkUbk3WTz6CFSULyswkTPpPr38AWibf5TVkB5GxuBxbSbmdFGr3jmswwemknyYxAGoX7BJnKfyPy4WXaHmcrxZhfzFwoUFvFtm5/3/<4;5>/6"); // Fails if they're part of the multi-path specifier or following it - get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/2/<3';4'>/5").to_public(&secp).unwrap_err(); - get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/2/<3;4>/5/6'").to_public(&secp).unwrap_err(); + get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/2/<3';4'>/5").to_public().unwrap_err(); + get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/2/<3;4>/5/6'").to_public().unwrap_err(); } #[test] diff --git a/src/descriptor/key_map.rs b/src/descriptor/key_map.rs index 60e14396b..6f5bfbf3e 100644 --- a/src/descriptor/key_map.rs +++ b/src/descriptor/key_map.rs @@ -5,7 +5,6 @@ use core::iter; use bitcoin::psbt::{GetKey, GetKeyError, KeyRequest}; -use bitcoin::secp256k1::{Secp256k1, Signing}; use bitcoin::PrivateKey; #[cfg(doc)] @@ -31,12 +30,11 @@ impl KeyMap { /// Inserts secret key into key map returning the associated public key. #[inline] - pub fn insert( + pub fn insert( &mut self, - secp: &Secp256k1, sk: DescriptorSecretKey, ) -> Result { - let pk = sk.to_public(secp)?; + let pk = sk.to_public()?; if !self.map.contains_key(&pk) { self.map.insert(pk.clone(), sk); } @@ -175,8 +173,6 @@ mod tests { #[test] fn get_key_single_key() { - let secp = Secp256k1::new(); - let descriptor_sk_s = "[90b6a706/44'/0'/0'/0/0]cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij"; @@ -187,7 +183,7 @@ mod tests { let want_sk = single.key; let descriptor_s = format!("wpkh({})", descriptor_sk_s); - let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap(); + let (_, keymap) = Descriptor::parse_descriptor(&descriptor_s).unwrap(); let pk = want_sk.public_key(); let request = KeyRequest::Pubkey(pk); @@ -200,8 +196,6 @@ mod tests { #[test] fn get_key_xpriv_single_key_xpriv() { - let secp = Secp256k1::new(); - let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"; let xpriv = s.parse::().unwrap(); @@ -220,7 +214,7 @@ mod tests { let want_sk = xpriv.to_priv(); let descriptor_s = format!("wpkh([{}]{})", xpriv_fingerprint, xpriv); - let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap(); + let (_, keymap) = Descriptor::parse_descriptor(&descriptor_s).unwrap(); let pk = want_sk.public_key(); let request = KeyRequest::Pubkey(pk); @@ -233,8 +227,6 @@ mod tests { #[test] fn get_key_xpriv_child_depth_one() { - let secp = Secp256k1::new(); - let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"; let master = s.parse::().unwrap(); let master_fingerprint = master.fingerprint(); @@ -255,7 +247,7 @@ mod tests { let want_sk = child.to_priv(); let descriptor_s = format!("wpkh({}/44')", s); - let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap(); + let (_, keymap) = Descriptor::parse_descriptor(&descriptor_s).unwrap(); let pk = want_sk.public_key(); let request = KeyRequest::Pubkey(pk); @@ -268,8 +260,6 @@ mod tests { #[test] fn get_key_xpriv_with_path() { - let secp = Secp256k1::new(); - let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"; let master = s.parse::().unwrap(); let master_fingerprint = master.fingerprint(); @@ -293,7 +283,7 @@ mod tests { let want_sk = child.to_priv(); let descriptor_s = format!("wpkh({}/44'/0'/0'/0/*)", s); - let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap(); + let (_, keymap) = Descriptor::parse_descriptor(&descriptor_s).unwrap(); let key_source = (master_fingerprint, derivation_path); let request = KeyRequest::Bip32(key_source); @@ -307,10 +297,8 @@ mod tests { #[test] fn get_key_xpriv_with_key_origin() { - let secp = Secp256k1::new(); - let descriptor_str = "wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"; - let (_descriptor_pk, keymap) = Descriptor::parse_descriptor(&secp, descriptor_str).unwrap(); + let (_descriptor_pk, keymap) = Descriptor::parse_descriptor(descriptor_str).unwrap(); let descriptor_sk = DescriptorSecretKey::from_str("[d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*").unwrap(); let xpriv = match descriptor_sk { @@ -339,11 +327,9 @@ mod tests { #[test] fn get_key_keymap_no_match() { - let secp = Secp256k1::new(); - // Create a keymap with one key let descriptor_s = "wpkh(cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij)"; - let (_, keymap) = Descriptor::parse_descriptor(&secp, descriptor_s).unwrap(); + let (_, keymap) = Descriptor::parse_descriptor(descriptor_s).unwrap(); // Request a different public key that doesn't exist in the keymap let different_sk = @@ -357,8 +343,6 @@ mod tests { #[test] fn get_key_descriptor_secret_key_xonly_not_supported() { - let secp = Secp256k1::new(); - let descriptor_sk = DescriptorSecretKey::from_str("xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi").unwrap(); // Create an x-only public key request @@ -372,7 +356,7 @@ mod tests { // Also test with KeyMap let descriptor_s = "wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi)"; - let (_, keymap) = Descriptor::parse_descriptor(&secp, descriptor_s).unwrap(); + let (_, keymap) = Descriptor::parse_descriptor(descriptor_s).unwrap(); // While requesting an x-only key from an individual xpriv, that's an error. // But from a keymap, which might have both x-only keys and regular xprivs, @@ -383,8 +367,6 @@ mod tests { #[test] fn get_key_descriptor_secret_key_xonly_multipath() { - let secp = Secp256k1::new(); - let descriptor_sk = DescriptorSecretKey::from_str("[d34db33f/84h/0h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/<0;1>").unwrap(); // Request with a different fingerprint @@ -406,7 +388,7 @@ mod tests { // Also test with KeyMap; as in the previous test, the error turns to None. let descriptor_s = "wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/<0;1>/*)"; - let (_, keymap) = Descriptor::parse_descriptor(&secp, descriptor_s).unwrap(); + let (_, keymap) = Descriptor::parse_descriptor(descriptor_s).unwrap(); let result = keymap.get_key(&request).unwrap(); assert!(result.is_none(), "Should return None when fingerprint doesn't match"); diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 17cb6177c..b0b306f3b 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -16,7 +16,7 @@ use core::ops::Range; use core::str::{self, FromStr}; use bitcoin::hashes::{hash160, ripemd160, sha256}; -use bitcoin::{secp256k1, Address, Network, TxIn, Weight, Witness, WitnessVersion}; +use bitcoin::{Address, Network, TxIn, Weight, Witness, WitnessVersion}; use sync::Arc; use crate::expression::FromTree as _; @@ -759,19 +759,17 @@ impl Descriptor { /// /// Internally turns every secret key found into the corresponding public key and then returns a /// a descriptor that only contains public keys and a map to lookup the secret key given a public key. - pub fn parse_descriptor( - secp: &secp256k1::Secp256k1, + pub fn parse_descriptor( s: &str, ) -> Result<(Descriptor, KeyMap), Error> { - fn parse_key( + fn parse_key( s: &str, key_map: &mut KeyMap, - secp: &secp256k1::Secp256k1, ) -> Result { match DescriptorSecretKey::from_str(s) { Ok(sk) => { let pk = key_map - .insert(secp, sk) + .insert(sk) .map_err(|e| Error::Unexpected(e.to_string()))?; Ok(pk) } @@ -785,16 +783,16 @@ impl Descriptor { } } - let mut keymap_pk = KeyMapWrapper(KeyMap::new(), secp); + let mut keymap_pk = KeyMapWrapper(KeyMap::new()); - struct KeyMapWrapper<'a, C: secp256k1::Signing>(KeyMap, &'a secp256k1::Secp256k1); + struct KeyMapWrapper(KeyMap); - impl Translator for KeyMapWrapper<'_, C> { + impl Translator for KeyMapWrapper { type TargetPk = DescriptorPublicKey; type Error = Error; fn pk(&mut self, pk: &String) -> Result { - parse_key(pk, &mut self.0, self.1) + parse_key(pk, &mut self.0) } fn sha256(&mut self, sha256: &String) -> Result { @@ -2014,17 +2012,16 @@ mod tests { #[test] fn test_parse_descriptor() { - let secp = &secp256k1::Secp256k1::signing_only(); - let (descriptor, key_map) = Descriptor::parse_descriptor(secp, "wpkh(tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/44'/0'/0'/0/*)").unwrap(); + let (descriptor, key_map) = Descriptor::parse_descriptor("wpkh(tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/44'/0'/0'/0/*)").unwrap(); assert_eq!(descriptor.to_string(), "wpkh([2cbe2a6d/44'/0'/0']tpubDCvNhURocXGZsLNqWcqD3syHTqPXrMSTwi8feKVwAcpi29oYKsDD3Vex7x2TDneKMVN23RbLprfxB69v94iYqdaYHsVz3kPR37NQXeqouVz/0/*)#nhdxg96s"); assert_eq!(key_map.len(), 1); // https://github.com/bitcoin/bitcoin/blob/7ae86b3c6845873ca96650fc69beb4ae5285c801/src/test/descriptor_tests.cpp#L355-L360 macro_rules! check_invalid_checksum { - ($secp: ident,$($desc: expr),*) => { + ($($desc: expr),*) => { use crate::{ParseError, ParseTreeError}; $( - match Descriptor::parse_descriptor($secp, $desc) { + match Descriptor::parse_descriptor($desc) { Err(Error::Parse(ParseError::Tree(ParseTreeError::Checksum(_)))) => {}, Err(e) => panic!("Expected bad checksum for {}, got '{}'", $desc, e), _ => panic!("Invalid checksum treated as valid: {}", $desc), @@ -2032,7 +2029,7 @@ mod tests { )* }; } - check_invalid_checksum!(secp, + check_invalid_checksum!( "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#", "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfyq", @@ -2046,8 +2043,8 @@ mod tests { "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))##tjq09x4t" ); - Descriptor::parse_descriptor(secp, "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy").expect("Valid descriptor with checksum"); - Descriptor::parse_descriptor(secp, "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t").expect("Valid descriptor with checksum"); + Descriptor::parse_descriptor("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy").expect("Valid descriptor with checksum"); + Descriptor::parse_descriptor("sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t").expect("Valid descriptor with checksum"); } #[test] @@ -2074,10 +2071,9 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))"; #[test] fn parse_with_secrets() { - let secp = &secp256k1::Secp256k1::signing_only(); let descriptor_str = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)#v20xlvm9"; let (descriptor, keymap) = - Descriptor::::parse_descriptor(secp, descriptor_str).unwrap(); + Descriptor::::parse_descriptor(descriptor_str).unwrap(); let expected = "wpkh([a12b02f4/44'/0'/0']xpub6BzhLAQUDcBUfHRQHZxDF2AbcJqp4Kaeq6bzJpXrjrWuK26ymTFwkEFbxPra2bJ7yeZKbDjfDeFwxe93JMqpo5SsPJH6dZdvV9kMzJkAZ69/0/*)#u37l7u8u"; assert_eq!(expected, descriptor.to_string()); @@ -2341,14 +2337,12 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))"; #[test] fn regression_806() { - let secp = secp256k1::Secp256k1::signing_only(); type Desc = Descriptor; // OK Desc::from_str("pkh(111111111111111111111111111111110000008375319363688624584A111111)") .unwrap_err(); // ERR: crashes in translate_pk Desc::parse_descriptor( - &secp, "pkh(111111111111111111111111111111110000008375319363688624584A111111)", ) .unwrap_err(); From 2e1bb8cc96f0dc883d17eaad508614d447f0526d Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 14:51:53 -0600 Subject: [PATCH 11/23] bitcoin 0.33: make Miniscript/Terminal encode generic over script tag `Miniscript::encode` and `Terminal::encode` now take a type parameter `T` so callers can produce a tagged `script::ScriptBuf` of whatever role fits the call-site (ScriptPubKey, RedeemScript, WitnessScript, TapScript) instead of always producing a `ScriptPubKeyBuf` and then copying the bytes into another tagged newtype. Follow-on changes: - `PushAstElem` is generic over `T`, as is the `impl MsKeyBuilder for Builder` in `util.rs`, so script construction works for every tag. - Segwit (`Wsh`, `Wpkh`) surfaces `WitnessScriptBuf` directly from `inner_script` / `ecdsa_sighash_script_code`; P2SH surfaces `RedeemScriptBuf`; every `get_satisfaction` return type now distinguishes `ScriptSigBuf` from `ScriptPubKeyBuf`. - `Plan::satisfy`, `Descriptor::{unsigned_script_sig, get_satisfaction, get_satisfaction_mall}`, and the PSBT finalizer propagate `ScriptSigBuf` through their signatures. The finalizer's interpreter-check helper takes a borrowed `ScriptSig` and internally converts to the untagged `Script` view that the interpreter expects. - `witness_to_scriptsig` now actually returns a `ScriptSigBuf`. - Tests update their expectations to the new tagged types and annotate `encode::()` where inference cannot pick a tag on its own. The one semantic subtlety: `Sh::inner_script` for `Sh(Wsh)` still returns the inner witness script (not the P2WSH scriptPubKey), matching the pre-0.33 behavior; `address_fallible` hashes the correct nested segwit scriptPubKey for `Sh(Wsh)` / `Sh(Wpkh)` so p2sh addresses match the previous implementation. `cargo test --all-targets` passes 151 lib tests and 9 doctests; the fuzz crate and every example still builds. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/descriptor/bare.rs | 24 +++++++++--- src/descriptor/mod.rs | 68 ++++++++++++++++++++------------ src/descriptor/segwitv0.rs | 38 +++++++++++------- src/descriptor/sh.rs | 79 +++++++++++++++++++++++++------------- src/descriptor/tr/mod.rs | 11 ++++-- src/miniscript/astelem.rs | 13 +++++-- src/miniscript/mod.rs | 39 ++++++++++++------- src/plan.rs | 22 ++++++----- src/psbt/finalizer.rs | 22 ++++++----- src/psbt/mod.rs | 2 +- src/util.rs | 8 ++-- 11 files changed, 211 insertions(+), 115 deletions(-) diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index 32f86b894..d626b2b14 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -22,7 +22,7 @@ use crate::prelude::*; use crate::util::{varint_len, witness_to_scriptsig}; use crate::{ BareCtx, Error, ForEachKey, FromStrKey, Miniscript, MiniscriptKey, Satisfier, ScriptBuf, - ScriptBuilder, ToPublicKey, TranslateErr, Translator, + ToPublicKey, TranslateErr, Translator, }; /// Create a Bare Descriptor. That is descriptor that is @@ -114,7 +114,10 @@ impl Bare { /// Returns satisfying non-malleable witness and scriptSig with minimum /// weight to spend an output controlled by the given descriptor if it is /// possible to construct one using the `satisfier`. - pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction( + &self, + satisfier: S, + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -127,7 +130,10 @@ impl Bare { /// Returns satisfying, possibly malleable, witness and scriptSig with /// minimum weight to spend an output controlled by the given descriptor if /// it is possible to construct one using the `satisfier`. - pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction_mall( + &self, + satisfier: S, + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -288,12 +294,15 @@ impl Pkh { /// Returns satisfying non-malleable witness and scriptSig with minimum /// weight to spend an output controlled by the given descriptor if it is /// possible to construct one using the `satisfier`. - pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction( + &self, + satisfier: S, + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { if let Some(sig) = satisfier.lookup_ecdsa_sig(&self.pk) { - let script_sig = ScriptBuilder::new() + let script_sig = bitcoin::script::Builder::::new() .push_slice::<&PushBytes>( // serialize() does not allocate here sig.serialize().as_ref(), @@ -310,7 +319,10 @@ impl Pkh { /// Returns satisfying, possibly malleable, witness and scriptSig with /// minimum weight to spend an output controlled by the given descriptor if /// it is possible to construct one using the `satisfier`. - pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction_mall( + &self, + satisfier: S, + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index b0b306f3b..661d8e53d 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -456,14 +456,14 @@ impl Descriptor { /// This is used in Segwit transactions to produce an unsigned transaction /// whose txid will not change during signing (since only the witness data /// will change). - pub fn unsigned_script_sig(&self) -> ScriptBuf { + pub fn unsigned_script_sig(&self) -> bitcoin::script::ScriptSigBuf { match *self { - Descriptor::Bare(_) => ScriptBuf::new(), - Descriptor::Pkh(_) => ScriptBuf::new(), - Descriptor::Wpkh(_) => ScriptBuf::new(), - Descriptor::Wsh(_) => ScriptBuf::new(), + Descriptor::Bare(_) => bitcoin::script::ScriptSigBuf::new(), + Descriptor::Pkh(_) => bitcoin::script::ScriptSigBuf::new(), + Descriptor::Wpkh(_) => bitcoin::script::ScriptSigBuf::new(), + Descriptor::Wsh(_) => bitcoin::script::ScriptSigBuf::new(), Descriptor::Sh(ref sh) => sh.unsigned_script_sig(), - Descriptor::Tr(_) => ScriptBuf::new(), + Descriptor::Tr(_) => bitcoin::script::ScriptSigBuf::new(), } } @@ -478,8 +478,12 @@ impl Descriptor { Descriptor::Bare(ref bare) => Ok(bare.script_pubkey()), Descriptor::Pkh(ref pkh) => Ok(pkh.script_pubkey()), Descriptor::Wpkh(ref wpkh) => Ok(wpkh.script_pubkey()), - Descriptor::Wsh(ref wsh) => Ok(wsh.inner_script()), - Descriptor::Sh(ref sh) => Ok(sh.inner_script()), + Descriptor::Wsh(ref wsh) => { + Ok(ScriptBuf::from_bytes(wsh.inner_script().into_bytes())) + } + Descriptor::Sh(ref sh) => { + Ok(ScriptBuf::from_bytes(sh.inner_script().into_bytes())) + } Descriptor::Tr(_) => Err(Error::TrNoScriptCode), } } @@ -496,8 +500,12 @@ impl Descriptor { Descriptor::Bare(ref bare) => Ok(bare.ecdsa_sighash_script_code()), Descriptor::Pkh(ref pkh) => Ok(pkh.ecdsa_sighash_script_code()), Descriptor::Wpkh(ref wpkh) => Ok(wpkh.ecdsa_sighash_script_code()), - Descriptor::Wsh(ref wsh) => Ok(wsh.ecdsa_sighash_script_code()), - Descriptor::Sh(ref sh) => Ok(sh.ecdsa_sighash_script_code()), + Descriptor::Wsh(ref wsh) => { + Ok(ScriptBuf::from_bytes(wsh.ecdsa_sighash_script_code().into_bytes())) + } + Descriptor::Sh(ref sh) => { + Ok(ScriptBuf::from_bytes(sh.ecdsa_sighash_script_code().into_bytes())) + } Descriptor::Tr(_) => Err(Error::TrNoScriptCode), } } @@ -505,7 +513,10 @@ impl Descriptor { /// Returns satisfying non-malleable witness and scriptSig to spend an /// output controlled by the given descriptor if it possible to /// construct one using the satisfier S. - pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction( + &self, + satisfier: S, + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -522,7 +533,10 @@ impl Descriptor { /// Returns a possilbly mallable satisfying non-malleable witness and scriptSig to spend an /// output controlled by the given descriptor if it possible to /// construct one using the satisfier S. - pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction_mall( + &self, + satisfier: S, + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -545,7 +559,7 @@ impl Descriptor { { let (witness, script_sig) = self.get_satisfaction(satisfier)?; txin.witness = Witness::from_slice(&witness); - txin.script_sig = bitcoin::script::ScriptSigBuf::from(script_sig.into_bytes()); + txin.script_sig = script_sig; Ok(()) } } @@ -1478,7 +1492,7 @@ mod tests { witness: Witness::default(), } ); - assert_eq!(bare.unsigned_script_sig(), ScriptBuf::new()); + assert_eq!(bare.unsigned_script_sig(), bitcoin::script::ScriptSigBuf::new()); let pkh = Descriptor::new_pkh(pk).unwrap(); pkh.satisfy(&mut txin, &satisfier).expect("satisfaction"); @@ -1494,7 +1508,7 @@ mod tests { witness: Witness::default(), } ); - assert_eq!(pkh.unsigned_script_sig(), ScriptBuf::new()); + assert_eq!(pkh.unsigned_script_sig(), bitcoin::script::ScriptSigBuf::new()); let wpkh = Descriptor::new_wpkh(pk).unwrap(); wpkh.satisfy(&mut txin, &satisfier).expect("satisfaction"); @@ -1507,7 +1521,7 @@ mod tests { witness: Witness::from_slice(&[sigser.clone(), pk.to_bytes()]), } ); - assert_eq!(wpkh.unsigned_script_sig(), ScriptBuf::new()); + assert_eq!(wpkh.unsigned_script_sig(), bitcoin::script::ScriptSigBuf::new()); let shwpkh = Descriptor::new_sh_wpkh(pk).unwrap(); shwpkh.satisfy(&mut txin, &satisfier).expect("satisfaction"); @@ -1532,7 +1546,7 @@ mod tests { ); assert_eq!( shwpkh.unsigned_script_sig(), - crate::ScriptBuilder::new() + bitcoin::script::Builder::::new() .push_slice(<&PushBytes>::try_from(redeem_script.as_bytes()).unwrap()) .into_script() ); @@ -1540,37 +1554,40 @@ mod tests { let ms = ms_str!("c:pk_k({})", pk); let sh = Descriptor::new_sh(ms.clone()).unwrap(); sh.satisfy(&mut txin, &satisfier).expect("satisfaction"); + let ms_redeem: bitcoin::script::RedeemScriptBuf = ms.encode(); assert_eq!( txin, bitcoin::TxIn { previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, script_sig: bitcoin::script::Builder::::new() .push_slice(<&PushBytes>::try_from(sigser.as_slice()).unwrap()) - .push_slice(<&PushBytes>::try_from(ms.encode().as_bytes()).unwrap()) + .push_slice(<&PushBytes>::try_from(ms_redeem.as_bytes()).unwrap()) .into_script(), sequence: Sequence::from_height(100), witness: Witness::default(), } ); - assert_eq!(sh.unsigned_script_sig(), ScriptBuf::new()); + assert_eq!(sh.unsigned_script_sig(), bitcoin::script::ScriptSigBuf::new()); let ms = ms_str!("c:pk_k({})", pk); let wsh = Descriptor::new_wsh(ms.clone()).unwrap(); wsh.satisfy(&mut txin, &satisfier).expect("satisfaction"); + let ms_wit: bitcoin::WitnessScriptBuf = ms.encode(); assert_eq!( txin, bitcoin::TxIn { previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, script_sig: bitcoin::ScriptSigBuf::new(), sequence: Sequence::from_height(100), - witness: Witness::from_slice(&[sigser.clone(), ms.encode().into_bytes()]), + witness: Witness::from_slice(&[sigser.clone(), ms_wit.into_bytes()]), } ); - assert_eq!(wsh.unsigned_script_sig(), ScriptBuf::new()); + assert_eq!(wsh.unsigned_script_sig(), bitcoin::script::ScriptSigBuf::new()); let shwsh = Descriptor::new_sh_wsh(ms.clone()).unwrap(); shwsh.satisfy(&mut txin, &satisfier).expect("satisfaction"); + let ms_wit2: bitcoin::WitnessScriptBuf = ms.encode(); assert_eq!( txin, bitcoin::TxIn { @@ -1578,7 +1595,7 @@ mod tests { script_sig: bitcoin::script::Builder::::new() .push_slice( <&PushBytes>::try_from( - bitcoin::WitnessScriptBuf::from(ms.encode().into_bytes()) + ms_wit2 .to_p2wsh() .unwrap() .as_bytes() @@ -1587,15 +1604,16 @@ mod tests { ) .into_script(), sequence: Sequence::from_height(100), - witness: Witness::from_slice(&[sigser.clone(), ms.encode().into_bytes()]), + witness: Witness::from_slice(&[sigser.clone(), ms_wit2.clone().into_bytes()]), } ); + let ms_encoded: bitcoin::WitnessScriptBuf = ms.encode(); assert_eq!( shwsh.unsigned_script_sig(), - crate::ScriptBuilder::new() + bitcoin::script::Builder::::new() .push_slice( <&PushBytes>::try_from( - bitcoin::WitnessScriptBuf::from(ms.encode().into_bytes()) + ms_encoded .to_p2wsh() .unwrap() .as_bytes() diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index 80533e1ae..f95e5a4a6 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -122,48 +122,54 @@ impl Wsh { impl Wsh { /// Obtains the corresponding script pubkey for this descriptor. pub fn script_pubkey(&self) -> ScriptBuf { - let witness_script = WitnessScriptBuf::from(self.inner_script().into_bytes()); - witness_script + self.inner_script() .to_p2wsh() .expect("witness script size within bounds") } /// Obtains the corresponding script pubkey for this descriptor. pub fn address(&self, network: Network) -> Address { - let witness_script = WitnessScriptBuf::from(self.ms.encode().into_bytes()); + let witness_script = self.inner_script(); Address::p2wsh(&witness_script, network).expect("witness script size within bounds") } - /// Obtains the underlying miniscript for this descriptor. - pub fn inner_script(&self) -> ScriptBuf { self.ms.encode() } + /// Obtains the underlying miniscript for this descriptor, tagged as a + /// witness script. + pub fn inner_script(&self) -> WitnessScriptBuf { self.ms.encode() } /// Obtains the pre bip-340 signature script code for this descriptor. - pub fn ecdsa_sighash_script_code(&self) -> ScriptBuf { self.inner_script() } + pub fn ecdsa_sighash_script_code(&self) -> WitnessScriptBuf { self.inner_script() } /// Returns satisfying non-malleable witness and scriptSig with minimum /// weight to spend an output controlled by the given descriptor if it is /// possible to construct one using the `satisfier`. - pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction( + &self, + satisfier: S, + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { let mut witness = self.ms.satisfy(satisfier)?; let witness_script = self.inner_script(); witness.push(witness_script.into_bytes()); - let script_sig = ScriptBuf::new(); + let script_sig = bitcoin::script::ScriptSigBuf::new(); Ok((witness, script_sig)) } /// Returns satisfying, possibly malleable, witness and scriptSig with /// minimum weight to spend an output controlled by the given descriptor if /// it is possible to construct one using the `satisfier`. - pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction_mall( + &self, + satisfier: S, + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { let mut witness = self.ms.satisfy_malleable(satisfier)?; witness.push(self.inner_script().into_bytes()); - let script_sig = ScriptBuf::new(); + let script_sig = bitcoin::script::ScriptSigBuf::new(); Ok((witness, script_sig)) } } @@ -347,13 +353,16 @@ impl Wpkh { /// Returns satisfying non-malleable witness and scriptSig with minimum /// weight to spend an output controlled by the given descriptor if it is /// possible to construct one using the `satisfier`. - pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction( + &self, + satisfier: S, + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { if let Some(sig) = satisfier.lookup_ecdsa_sig(&self.pk) { let sig_vec = sig.to_vec(); - let script_sig = ScriptBuf::new(); + let script_sig = bitcoin::script::ScriptSigBuf::new(); let witness = vec![sig_vec, self.pk.to_public_key().to_bytes()]; Ok((witness, script_sig)) } else { @@ -364,7 +373,10 @@ impl Wpkh { /// Returns satisfying, possibly malleable, witness and scriptSig with /// minimum weight to spend an output controlled by the given descriptor if /// it is possible to construct one using the `satisfier`. - pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction_mall( + &self, + satisfier: S, + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index dec366723..eb099b8df 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -25,7 +25,7 @@ use crate::prelude::*; use crate::util::{varint_len, witness_to_scriptsig}; use crate::{ push_opcode_size, Error, ForEachKey, FromStrKey, Legacy, Miniscript, MiniscriptKey, Satisfier, - ScriptBuf, ScriptBuilder, Segwitv0, Threshold, ToPublicKey, TranslateErr, Translator, + ScriptBuf, Segwitv0, Threshold, ToPublicKey, TranslateErr, Translator, }; /// A Legacy p2sh Descriptor @@ -262,10 +262,10 @@ impl Sh { .script_pubkey() .to_p2sh() .expect("redeem script within size bounds"), - ShInner::Ms(ref ms) => ms - .encode() - .to_p2sh() - .expect("redeem script within size bounds"), + ShInner::Ms(ref ms) => { + let redeem: bitcoin::script::RedeemScriptBuf = ms.encode(); + redeem.to_p2sh().expect("redeem script within size bounds") + } } } @@ -279,32 +279,47 @@ impl Sh { } fn address_fallible(&self, network: Network) -> Result { - let script = match self.inner { - ShInner::Wsh(ref wsh) => wsh.script_pubkey(), - ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey(), - ShInner::Ms(ref ms) => ms.encode(), + // The redeem script for a P2SH-wrapped segwit descriptor is the wrapped + // segwit output's scriptPubKey, not the inner witness/redeem script. + let address = match self.inner { + ShInner::Wsh(ref wsh) => Address::p2sh(&wsh.script_pubkey(), network)?, + ShInner::Wpkh(ref wpkh) => Address::p2sh(&wpkh.script_pubkey(), network)?, + ShInner::Ms(ref ms) => { + let redeem: bitcoin::script::RedeemScriptBuf = ms.encode(); + Address::p2sh(&redeem, network)? + } }; - let address = Address::p2sh(&script, network)?; - Ok(address) } - /// Obtain the underlying miniscript for this descriptor - pub fn inner_script(&self) -> ScriptBuf { + /// Obtain the underlying miniscript for this descriptor, tagged as a + /// redeem script. + /// + /// For `Sh(Wsh)` this returns the inner witness script; for `Sh(Wpkh)` + /// and `Sh(Ms)` it returns the redeem script itself. + pub fn inner_script(&self) -> bitcoin::script::RedeemScriptBuf { match self.inner { - ShInner::Wsh(ref wsh) => wsh.inner_script(), - ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey(), + ShInner::Wsh(ref wsh) => { + bitcoin::script::RedeemScriptBuf::from_bytes(wsh.inner_script().into_bytes()) + } + ShInner::Wpkh(ref wpkh) => { + bitcoin::script::RedeemScriptBuf::from_bytes(wpkh.script_pubkey().into_bytes()) + } ShInner::Ms(ref ms) => ms.encode(), } } /// Obtains the pre bip-340 signature script code for this descriptor. - pub fn ecdsa_sighash_script_code(&self) -> ScriptBuf { + pub fn ecdsa_sighash_script_code(&self) -> bitcoin::script::RedeemScriptBuf { match self.inner { // - For P2WSH witness program, if the witnessScript does not contain any `OP_CODESEPARATOR`, // the `scriptCode` is the `witnessScript` serialized as scripts inside CTxOut. - ShInner::Wsh(ref wsh) => wsh.ecdsa_sighash_script_code(), - ShInner::Wpkh(ref wpkh) => wpkh.ecdsa_sighash_script_code(), + ShInner::Wsh(ref wsh) => bitcoin::script::RedeemScriptBuf::from_bytes( + wsh.ecdsa_sighash_script_code().into_bytes(), + ), + ShInner::Wpkh(ref wpkh) => bitcoin::script::RedeemScriptBuf::from_bytes( + wpkh.ecdsa_sighash_script_code().into_bytes(), + ), // For "legacy" P2SH outputs, it is defined as the txo's redeemScript. ShInner::Ms(ref ms) => ms.encode(), } @@ -317,7 +332,7 @@ impl Sh { /// This is used in Segwit transactions to produce an unsigned transaction /// whose txid will not change during signing (since only the witness data /// will change). - pub fn unsigned_script_sig(&self) -> ScriptBuf { + pub fn unsigned_script_sig(&self) -> bitcoin::script::ScriptSigBuf { match self.inner { ShInner::Wsh(ref wsh) => { // wsh explicit must contain exactly 1 element @@ -326,22 +341,29 @@ impl Sh { .expect("Witness script is not too large"); let push_bytes = <&PushBytes>::try_from(witness_script.as_bytes()) .expect("Witness script is not too large"); - ScriptBuilder::new().push_slice(push_bytes).into_script() + bitcoin::script::Builder::::new() + .push_slice(push_bytes) + .into_script() } ShInner::Wpkh(ref wpkh) => { let redeem_script = wpkh.script_pubkey(); let push_bytes: &PushBytes = <&PushBytes>::try_from(redeem_script.as_bytes()).expect("Script not too large"); - ScriptBuilder::new().push_slice(push_bytes).into_script() + bitcoin::script::Builder::::new() + .push_slice(push_bytes) + .into_script() } - ShInner::Ms(..) => ScriptBuf::new(), + ShInner::Ms(..) => bitcoin::script::ScriptSigBuf::new(), } } /// Returns satisfying non-malleable witness and scriptSig with minimum /// weight to spend an output controlled by the given descriptor if it is /// possible to construct one using the `satisfier`. - pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction( + &self, + satisfier: S, + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -357,7 +379,8 @@ impl Sh { } ShInner::Ms(ref ms) => { let mut script_witness = ms.satisfy(satisfier)?; - script_witness.push(ms.encode().into_bytes()); + let encoded: bitcoin::script::RedeemScriptBuf = ms.encode(); + script_witness.push(encoded.into_bytes()); let script_sig = witness_to_scriptsig(&script_witness); let witness = vec![]; Ok((witness, script_sig)) @@ -368,7 +391,10 @@ impl Sh { /// Returns satisfying, possibly malleable, witness and scriptSig with /// minimum weight to spend an output controlled by the given descriptor if /// it is possible to construct one using the `satisfier`. - pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction_mall( + &self, + satisfier: S, + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -380,7 +406,8 @@ impl Sh { } ShInner::Ms(ref ms) => { let mut script_witness = ms.satisfy_malleable(satisfier)?; - script_witness.push(ms.encode().into_bytes()); + let encoded: bitcoin::script::RedeemScriptBuf = ms.encode(); + script_witness.push(encoded.into_bytes()); let script_sig = witness_to_scriptsig(&script_witness); let witness = vec![]; Ok((witness, script_sig)) diff --git a/src/descriptor/tr/mod.rs b/src/descriptor/tr/mod.rs index fcb222ad7..2e9448c7b 100644 --- a/src/descriptor/tr/mod.rs +++ b/src/descriptor/tr/mod.rs @@ -285,7 +285,10 @@ impl Tr { /// Returns satisfying non-malleable witness and scriptSig with minimum /// weight to spend an output controlled by the given descriptor if it is /// possible to construct one using the `satisfier`. - pub fn get_satisfaction(&self, satisfier: &S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction( + &self, + satisfier: &S, + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -293,7 +296,7 @@ impl Tr { .try_completing(satisfier) .expect("the same satisfier should manage to complete the template"); if let Witness::Stack(stack) = satisfaction.stack { - Ok((stack, ScriptBuf::new())) + Ok((stack, bitcoin::script::ScriptSigBuf::new())) } else { Err(Error::CouldNotSatisfy) } @@ -305,7 +308,7 @@ impl Tr { pub fn get_satisfaction_mall( &self, satisfier: &S, - ) -> Result<(Vec>, ScriptBuf), Error> + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -313,7 +316,7 @@ impl Tr { .try_completing(satisfier) .expect("the same satisfier should manage to complete the template"); if let Witness::Stack(stack) = satisfaction.stack { - Ok((stack, ScriptBuf::new())) + Ok((stack, bitcoin::script::ScriptSigBuf::new())) } else { Err(Error::CouldNotSatisfy) } diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs index 04e05a3b7..63154ebd0 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -12,16 +12,18 @@ use bitcoin::{absolute, opcodes}; use crate::miniscript::context::SigType; use crate::miniscript::ScriptContext; use crate::util::MsKeyBuilder; -use crate::{Miniscript, MiniscriptKey, ScriptBuilder, Terminal, ToPublicKey}; +use crate::{Miniscript, MiniscriptKey, Terminal, ToPublicKey}; -/// Helper trait to add a `push_astelem` method to `ScriptBuilder` +/// Helper trait to add a `push_astelem` method to `bitcoin::script::Builder`. trait PushAstElem { fn push_astelem(self, ast: &Miniscript) -> Self where Pk: ToPublicKey; } -impl PushAstElem for ScriptBuilder { +impl PushAstElem + for bitcoin::script::Builder +{ fn push_astelem(self, ast: &Miniscript) -> Self where Pk: ToPublicKey, @@ -34,7 +36,10 @@ impl Terminal { /// Encode the element as a fragment of Bitcoin Script. The inverse /// function, from Script to an AST element, is implemented in the /// `parse` module. - pub fn encode(&self, mut builder: ScriptBuilder) -> ScriptBuilder + pub fn encode( + &self, + mut builder: bitcoin::script::Builder, + ) -> bitcoin::script::Builder where Pk: ToPublicKey, { diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index b644b2f6b..4578eddd3 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -21,7 +21,7 @@ use self::analyzable::ExtParams; pub use self::context::{BareCtx, Legacy, Segwitv0, Tap}; use crate::iter::TreeLike; use crate::prelude::*; -use crate::{script_num_size, Script, ScriptBuf, ScriptBuilder, TranslateErr}; +use crate::{script_num_size, Script, TranslateErr}; pub mod analyzable; pub mod astelem; @@ -360,12 +360,18 @@ impl Miniscript { /// Get a reference to the inner `AstElem` representing the root of miniscript pub fn as_inner(&self) -> &Terminal { &self.node } - /// Encode as a Bitcoin script - pub fn encode(&self) -> ScriptBuf + /// Encode as a Bitcoin script, tagged at the call site. + /// + /// The caller chooses the script tag `T`, so this works for + /// `ScriptPubKeyBuf`, `RedeemScriptBuf`, `WitnessScriptBuf`, + /// `TapScriptBuf`, etc. without any byte-level conversion. + pub fn encode(&self) -> bitcoin::script::ScriptBuf where Pk: ToPublicKey, { - self.node.encode(ScriptBuilder::new()).into_script() + self.node + .encode(bitcoin::script::Builder::::new()) + .into_script() } /// Size, in bytes of the script-pubkey. If this Miniscript is used outside @@ -452,9 +458,8 @@ impl Miniscript { where Pk: ToPublicKey, { - let encoded = self.encode(); - let tap_script = bitcoin::script::TapScript::from_bytes(encoded.as_bytes()); - TapLeafHash::from_script(tap_script, LeafVersion::TapScript) + let encoded: bitcoin::script::TapScriptBuf = self.encode(); + TapLeafHash::from_script(&encoded, LeafVersion::TapScript) } /// Attempt to produce non-malleable satisfying witness for the @@ -1205,7 +1210,7 @@ mod tests { fn roundtrip(tree: &Segwitv0Script, s: &str) { assert_eq!(tree.ty.corr.base, types::Base::B); - let ser = tree.encode(); + let ser: crate::ScriptBuf = tree.encode(); assert_eq!(ser.len(), tree.script_size()); assert_eq!(ser.to_string(), s); let deser = @@ -1225,7 +1230,8 @@ mod tests { let ms: Result = Miniscript::from_str_insane(ms); match (ms, valid) { (Ok(ms), true) => { - assert_eq!(format!("{:x}", ms.encode()), expected_hex); + let encoded: crate::ScriptBuf = ms.encode(); + assert_eq!(format!("{:x}", encoded), expected_hex); assert_eq!(ms.ty.mall.non_malleable, non_mal); assert_eq!(ms.ty.mall.safe, need_sig); assert_eq!(ms.ext.static_ops + ms.ext.sat_data.unwrap().max_exec_op_count, ops); @@ -1424,7 +1430,7 @@ mod tests { let tree: &Segwitv0Script = &ms_str!("c:pk_h({})", keys[5]); assert_eq!(tree.ty.corr.base, types::Base::B); - let ser = tree.encode(); + let ser: crate::ScriptBuf = tree.encode(); let s = "\ OP_DUP OP_HASH160 OP_PUSHBYTES_20 \ 7e5a2a6a7610ca4ea78bd65a087bd75b1870e319 \ @@ -1679,8 +1685,11 @@ mod tests { // ); assert_eq!(tap_ms.script_size(), 104); assert_eq!(tap_ms_sorted.script_size(), 104); - assert_eq!(tap_ms.encode().len(), tap_ms.script_size()); - assert_eq!(tap_ms_sorted.encode().len(), tap_ms_sorted.script_size()); + assert_eq!(tap_ms.encode::().len(), tap_ms.script_size()); + assert_eq!( + tap_ms_sorted.encode::().len(), + tap_ms_sorted.script_size() + ); // Test satisfaction code struct SimpleSatisfier(secp256k1::schnorr::Signature); @@ -1721,9 +1730,11 @@ mod tests { ) .unwrap(); let ms_trans = ms.translate_pk(&mut StrKeyTranslator::new()).unwrap(); - let enc = ms_trans.encode(); + let enc: crate::ScriptBuf = ms_trans.encode(); let ms = Miniscript::::decode_consensus(&enc).unwrap(); - assert_eq!(ms_trans.encode(), ms.encode()); + let trans_enc: crate::ScriptBuf = ms_trans.encode(); + let re_enc: crate::ScriptBuf = ms.encode(); + assert_eq!(trans_enc, re_enc); } #[test] diff --git a/src/plan.rs b/src/plan.rs index e31e56112..4a79ef772 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -271,9 +271,7 @@ impl Plan { pub fn satisfy>( &self, stfr: &Sat, - ) -> Result<(Vec>, ScriptBuf), Error> { - use bitcoin::blockdata::script::Builder; - + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> { let stack = self .template .iter() @@ -286,14 +284,20 @@ impl Plan { vec![], stack .into_iter() - .fold(Builder::new(), |builder, item| { - let bytes = PushBytesBuf::try_from(item) - .expect("All the possible placeholders can be made into PushBytesBuf"); - builder.push_slice(bytes) - }) + .fold( + bitcoin::script::Builder::::new(), + |builder, item| { + let bytes = PushBytesBuf::try_from(item).expect( + "All the possible placeholders can be made into PushBytesBuf", + ); + builder.push_slice(bytes) + }, + ) .into_script(), ), - DescriptorType::Wpkh | DescriptorType::Tr => (stack, ScriptBuf::new()), + DescriptorType::Wpkh | DescriptorType::Tr => { + (stack, bitcoin::script::ScriptSigBuf::new()) + } DescriptorType::ShWpkh => (stack, self.descriptor.unsigned_script_sig()), DescriptorType::Wsh | DescriptorType::ShWsh => { let mut stack = stack; diff --git a/src/psbt/finalizer.rs b/src/psbt/finalizer.rs index 235e0eefd..26805d02b 100644 --- a/src/psbt/finalizer.rs +++ b/src/psbt/finalizer.rs @@ -89,7 +89,8 @@ fn construct_tap_witness( Err(..) => continue, } }; - wit.push(ms.encode().into_bytes()); + let encoded: bitcoin::TapScriptBuf = ms.encode(); + wit.push(encoded.into_bytes()); wit.push(control_block.serialize()); let wit_len = Some(witness_size(&wit)); if min_wit_len.is_some() && wit_len > min_wit_len { @@ -326,9 +327,9 @@ pub fn interpreter_check( let utxos = prevouts(psbt)?; let utxos = &Prevouts::All(&utxos); for (index, input) in psbt.inputs.iter().enumerate() { - let empty_script_sig = ScriptBuf::new(); - let script_sig_spk = match input.final_script_sig.as_ref() { - Some(sig) => ScriptBuf::from_bytes(sig.to_vec()), + let empty_script_sig = bitcoin::script::ScriptSigBuf::new(); + let script_sig = match input.final_script_sig.as_ref() { + Some(sig) => sig.clone(), None => empty_script_sig, }; let empty_witness = Witness::default(); @@ -338,7 +339,7 @@ pub fn interpreter_check( .map(|wit_slice| Witness::from_slice(&wit_slice.to_vec())) // TODO: Update rust-bitcoin psbt API to use witness .unwrap_or(empty_witness); - interpreter_inp_check(psbt, secp, index, utxos, &witness, &script_sig_spk)?; + interpreter_inp_check(psbt, secp, index, utxos, &witness, &script_sig)?; } Ok(()) } @@ -350,7 +351,7 @@ fn interpreter_inp_check>( index: usize, utxos: &Prevouts, witness: &Witness, - script_sig: &Script, + script_sig: &bitcoin::script::ScriptSig, ) -> Result<(), Error> { let spk = get_scriptpubkey(psbt, index).map_err(|e| Error::InputError(e, index))?; @@ -360,8 +361,11 @@ fn interpreter_inp_check>( { let cltv = psbt.unsigned_tx.lock_time; let csv = psbt.unsigned_tx.inputs[index].sequence; + // The miniscript interpreter takes an untagged ScriptPubKey for both spk and sig; + // cast the tagged scriptSig bytes accordingly. + let script_sig_spk = Script::from_bytes(script_sig.as_bytes()); let interpreter = - interpreter::Interpreter::from_txdata(&spk, script_sig, witness, csv, cltv) + interpreter::Interpreter::from_txdata(&spk, script_sig_spk, witness, csv, cltv) .map_err(|e| Error::InputError(InputError::Interpreter(e), index))?; let iter = interpreter.iter(secp, &psbt.unsigned_tx, index, utxos); if let Some(error) = iter.filter_map(Result::err).next() { @@ -420,7 +424,7 @@ fn finalize_input_helper( index: usize, secp: &Secp256k1, allow_mall: bool, -) -> Result<(Witness, ScriptBuf), super::Error> { +) -> Result<(Witness, bitcoin::script::ScriptSigBuf), super::Error> { let (witness, script_sig) = { let spk = get_scriptpubkey(psbt, index).map_err(|e| Error::InputError(e, index))?; let sat = PsbtInputSatisfier::new(psbt, index); @@ -429,7 +433,7 @@ fn finalize_input_helper( // Deal with tr case separately, unfortunately we cannot infer the full descriptor for Tr let wit = construct_tap_witness(&spk, &sat, allow_mall) .map_err(|e| Error::InputError(e, index))?; - (wit, ScriptBuf::new()) + (wit, bitcoin::script::ScriptSigBuf::new()) } else { // Get a descriptor for this input. let desc = get_descriptor(psbt, index).map_err(|e| Error::InputError(e, index))?; diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index 6125879e0..41056ea39 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -1481,7 +1481,7 @@ mod tests { let first_leaf_hash = { let ms = Miniscript::::from_str(&format!("pkh({})", &key_0_1)).unwrap(); - let first_script = TapScriptBuf::from_bytes(ms.encode().into_bytes()); + let first_script: TapScriptBuf = ms.encode(); assert!(psbt_input .tap_scripts .values() diff --git a/src/util.rs b/src/util.rs index 06d4f07f0..e7eb2bba7 100644 --- a/src/util.rs +++ b/src/util.rs @@ -9,7 +9,7 @@ use crate::miniscript::context; use crate::miniscript::limits::MAX_SCRIPT_ELEMENT_SIZE; use crate::miniscript::satisfy::Placeholder; use crate::prelude::*; -use crate::{MiniscriptKey, ScriptBuf, ScriptBuilder, ScriptContext, ToPublicKey}; +use crate::{MiniscriptKey, ScriptContext, ToPublicKey}; pub(crate) fn varint_len(n: usize) -> usize { // Equivalent to the CompactSize / VarInt length used by Bitcoin consensus encoding. @@ -62,8 +62,8 @@ pub(crate) fn witness_size(wit: &[T]) -> usize { wit.iter().map(T::size).sum::() + varint_len(wit.len()) } -pub(crate) fn witness_to_scriptsig(witness: &[Vec]) -> ScriptBuf { - let mut b = ScriptBuilder::new(); +pub(crate) fn witness_to_scriptsig(witness: &[Vec]) -> bitcoin::script::ScriptSigBuf { + let mut b = bitcoin::script::Builder::::new(); for (i, wit) in witness.iter().enumerate() { if let Ok(n) = bitcoin::script::read_scriptint_non_minimal(wit) { b = b.push_int(n).expect("not i32::MIN"); @@ -95,7 +95,7 @@ pub(crate) trait MsKeyBuilder { Ctx: ScriptContext; } -impl MsKeyBuilder for ScriptBuilder { +impl MsKeyBuilder for bitcoin::script::Builder { fn push_ms_key(self, key: &Pk) -> Self where Pk: ToPublicKey, From 0762bd09bf428974d8f5a0c1a1c18c79f493cbe8 Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 14:59:58 -0600 Subject: [PATCH 12/23] bitcoin 0.33: use tagged bitcoin::XOnlyPublicKey in Tap context Switches the Tap `ScriptContext::Key` from `bitcoin::secp256k1::XOnlyPublicKey` (raw secp type) to the tagged `bitcoin::XOnlyPublicKey` introduced in bitcoin 0.33. This lines up with upstream PR #874 and lets the taproot miniscript layer benefit from the same type-safety distinction the rest of bitcoin 0.33 uses. - `context::Tap::Key = bitcoin::XOnlyPublicKey`. - Seal and implement `ParseableKey` for `bitcoin::XOnlyPublicKey` (it delegates to the secp impl and wraps the result via `from_secp`). The secp variant stays sealed and implementable for callers who want to parse into the raw type. - PSBT finalizer's tap-script hash lookup map is now keyed on `bitcoin::XOnlyPublicKey`; no conversion needed because `tap_key_origins` already yields the tagged type. - `Tapscript` alias in the tests and the decode doctest import the tagged type. - `StrXOnlyKeyTranslator` in `test_utils` produces `bitcoin::XOnlyPublicKey` (via `from_secp`) so Tap miniscripts constructed through it drive through the new context. - Drop the now-unreachable `ToNoChecks` impl for the raw secp type; the existing impl for `bitcoin::key::XOnlyPublicKey` (the same tagged type) already covers the new context. - Fuzz target for tap roundtripping parses into the tagged type. The raw secp type is still the canonical key in non-Tap contexts and still implements `MiniscriptKey`/`ToPublicKey` unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../roundtrip_miniscript_script_tap.rs | 8 +++---- src/interpreter/inner.rs | 21 ------------------- src/miniscript/context.rs | 2 +- src/miniscript/decode.rs | 9 ++++++++ src/miniscript/mod.rs | 6 +++--- src/psbt/finalizer.rs | 6 +++--- src/test_utils.rs | 6 +++--- 7 files changed, 22 insertions(+), 36 deletions(-) diff --git a/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs b/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs index 4a0fc3a49..b180f886a 100644 --- a/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs +++ b/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs @@ -7,12 +7,10 @@ fn do_test(data: &[u8]) { // Try round-tripping as a script let script = miniscript::Script::from_bytes(data); - if let Ok(pt) = - Miniscript::::decode(script) - { - let output = pt.encode(); + if let Ok(pt) = Miniscript::::decode(script) { + let output: miniscript::bitcoin::script::ScriptPubKeyBuf = pt.encode(); assert_eq!(pt.script_size(), output.len()); - assert_eq!(&output, script); + assert_eq!(output.as_bytes(), script.as_bytes()); } } diff --git a/src/interpreter/inner.rs b/src/interpreter/inner.rs index 9485d37b4..fb0a111fe 100644 --- a/src/interpreter/inner.rs +++ b/src/interpreter/inner.rs @@ -426,27 +426,6 @@ impl ToNoChecks for Miniscript ToNoChecks for Miniscript { - fn to_no_checks_ms(&self) -> Miniscript { - struct TranslateSecpXOnlyPk; - - impl Translator for TranslateSecpXOnlyPk { - type TargetPk = BitcoinKey; - type Error = core::convert::Infallible; - - fn pk( - &mut self, - pk: &bitcoin::secp256k1::XOnlyPublicKey, - ) -> Result { - Ok(BitcoinKey::XOnlyPublicKey(bitcoin::key::XOnlyPublicKey::from(*pk))) - } - - translate_hash_clone!(bitcoin::secp256k1::XOnlyPublicKey); - } - self.translate_pk_ctx(&mut TranslateSecpXOnlyPk) - .expect("Translation should succeed") - } -} #[cfg(test)] mod tests { diff --git a/src/miniscript/context.rs b/src/miniscript/context.rs index bd3f0a929..a7fd7f471 100644 --- a/src/miniscript/context.rs +++ b/src/miniscript/context.rs @@ -579,7 +579,7 @@ impl ScriptContext for Segwitv0 { pub enum Tap {} impl ScriptContext for Tap { - type Key = bitcoin::secp256k1::XOnlyPublicKey; + type Key = bitcoin::XOnlyPublicKey; fn check_terminal_non_malleable( _frag: &Terminal, ) -> Result<(), ScriptContextError> { diff --git a/src/miniscript/decode.rs b/src/miniscript/decode.rs index 52213d123..9b6170443 100644 --- a/src/miniscript/decode.rs +++ b/src/miniscript/decode.rs @@ -45,6 +45,14 @@ impl ParseableKey for bitcoin::secp256k1::XOnlyPublicKey { } } +impl ParseableKey for bitcoin::XOnlyPublicKey { + fn from_slice(sl: &[u8]) -> Result { + let secp: bitcoin::secp256k1::XOnlyPublicKey = + ::from_slice(sl)?; + Ok(bitcoin::XOnlyPublicKey::from_secp(secp)) + } +} + /// Private Mod to prevent downstream from implementing this public trait mod private { @@ -53,6 +61,7 @@ mod private { // Implement for those same types, but no others. impl Sealed for bitcoin::PublicKey {} impl Sealed for bitcoin::secp256k1::XOnlyPublicKey {} + impl Sealed for bitcoin::XOnlyPublicKey {} } #[derive(Copy, Clone, Debug)] diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 4578eddd3..b2f0d9f49 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -592,7 +592,7 @@ impl Miniscript { /// ```rust /// use miniscript::{Miniscript, Segwitv0, Tap}; /// use miniscript::bitcoin::script::ScriptBufExt as _; - /// use miniscript::bitcoin::secp256k1::XOnlyPublicKey; + /// use miniscript::bitcoin::XOnlyPublicKey; /// /// type Segwitv0Script = Miniscript; /// type TapScript = Miniscript; @@ -1110,7 +1110,7 @@ mod tests { use core::str::FromStr; use bitcoin::hashes::{hash160, sha256}; - use bitcoin::secp256k1::XOnlyPublicKey; + use bitcoin::XOnlyPublicKey; use bitcoin::taproot::TapLeafHash; use sync::Arc; @@ -1124,7 +1124,7 @@ mod tests { }; type Segwitv0Script = Miniscript; - type Tapscript = Miniscript; + type Tapscript = Miniscript; fn pubkeys(n: usize) -> Vec { let mut ret = Vec::with_capacity(n); diff --git a/src/psbt/finalizer.rs b/src/psbt/finalizer.rs index 26805d02b..47fd8cfe2 100644 --- a/src/psbt/finalizer.rs +++ b/src/psbt/finalizer.rs @@ -40,14 +40,14 @@ fn construct_tap_witness( ) -> Result>, InputError> { // When miniscript tries to finalize the PSBT, it doesn't have the full descriptor (which contained a pkh() fragment) // and instead resorts to parsing the raw script sig, which is translated into a "expr_raw_pkh" internally. - let mut map: BTreeMap = BTreeMap::new(); + let mut map: BTreeMap = BTreeMap::new(); let psbt_inputs = &sat.psbt.inputs; for psbt_input in psbt_inputs { // We need to satisfy or dissatisfy any given key. `tap_key_origin` is the only field of PSBT Input which consist of // all the keys added on a descriptor and thus we get keys from it. let public_keys = psbt_input.tap_key_origins.keys(); for key in public_keys { - let bitcoin_key: bitcoin::secp256k1::XOnlyPublicKey = *key.as_inner(); + let bitcoin_key: bitcoin::XOnlyPublicKey = *key; let hash = bitcoin_key.to_pubkeyhash(SigType::Schnorr); map.insert(hash, bitcoin_key); } @@ -72,7 +72,7 @@ fn construct_tap_witness( continue; } let script_spk = Script::from_bytes(script.as_bytes()); - let ms = match Miniscript::::decode_consensus( + let ms = match Miniscript::::decode_consensus( script_spk, ) { Ok(ms) => ms.substitute_raw_pkh(&map), diff --git a/src/test_utils.rs b/src/test_utils.rs index 81e2b204a..f0f2720d5 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -9,7 +9,7 @@ use std::str::FromStr; use bitcoin::hashes::{hash160, ripemd160, sha256}; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 use bitcoin::secp256k1; -use bitcoin::secp256k1::XOnlyPublicKey; +use bitcoin::XOnlyPublicKey; use crate::miniscript::context::SigType; use crate::{hash256, ToPublicKey, Translator}; @@ -164,12 +164,12 @@ impl StrKeyTranslator { impl StrXOnlyKeyTranslator { pub fn new() -> Self { let sks = random_sks(26); - let pks: Vec<_> = sks + let pks: Vec = sks .iter() .map(|sk| { let keypair = secp256k1::Keypair::from_secret_key(sk); let (pk, _parity) = secp256k1::XOnlyPublicKey::from_keypair(&keypair); - pk + XOnlyPublicKey::from_secp(pk) }) .collect(); let mut pk_map = HashMap::new(); From 11b8c866e433014b7964be8b9b0b07c897f1e260 Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 15:01:41 -0600 Subject: [PATCH 13/23] style: cargo +nightly fmt Co-Authored-By: Claude Opus 4.7 (1M context) --- src/descriptor/mod.rs | 33 ++++++--------------------------- src/interpreter/inner.rs | 1 - src/miniscript/astelem.rs | 5 +---- src/miniscript/mod.rs | 2 +- src/psbt/finalizer.rs | 5 ++--- 5 files changed, 10 insertions(+), 36 deletions(-) diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 661d8e53d..e42fc10e2 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -478,12 +478,8 @@ impl Descriptor { Descriptor::Bare(ref bare) => Ok(bare.script_pubkey()), Descriptor::Pkh(ref pkh) => Ok(pkh.script_pubkey()), Descriptor::Wpkh(ref wpkh) => Ok(wpkh.script_pubkey()), - Descriptor::Wsh(ref wsh) => { - Ok(ScriptBuf::from_bytes(wsh.inner_script().into_bytes())) - } - Descriptor::Sh(ref sh) => { - Ok(ScriptBuf::from_bytes(sh.inner_script().into_bytes())) - } + Descriptor::Wsh(ref wsh) => Ok(ScriptBuf::from_bytes(wsh.inner_script().into_bytes())), + Descriptor::Sh(ref sh) => Ok(ScriptBuf::from_bytes(sh.inner_script().into_bytes())), Descriptor::Tr(_) => Err(Error::TrNoScriptCode), } } @@ -773,13 +769,8 @@ impl Descriptor { /// /// Internally turns every secret key found into the corresponding public key and then returns a /// a descriptor that only contains public keys and a map to lookup the secret key given a public key. - pub fn parse_descriptor( - s: &str, - ) -> Result<(Descriptor, KeyMap), Error> { - fn parse_key( - s: &str, - key_map: &mut KeyMap, - ) -> Result { + pub fn parse_descriptor(s: &str) -> Result<(Descriptor, KeyMap), Error> { + fn parse_key(s: &str, key_map: &mut KeyMap) -> Result { match DescriptorSecretKey::from_str(s) { Ok(sk) => { let pk = key_map @@ -1594,13 +1585,7 @@ mod tests { previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, script_sig: bitcoin::script::Builder::::new() .push_slice( - <&PushBytes>::try_from( - ms_wit2 - .to_p2wsh() - .unwrap() - .as_bytes() - ) - .unwrap() + <&PushBytes>::try_from(ms_wit2.to_p2wsh().unwrap().as_bytes()).unwrap() ) .into_script(), sequence: Sequence::from_height(100), @@ -1612,13 +1597,7 @@ mod tests { shwsh.unsigned_script_sig(), bitcoin::script::Builder::::new() .push_slice( - <&PushBytes>::try_from( - ms_encoded - .to_p2wsh() - .unwrap() - .as_bytes() - ) - .unwrap() + <&PushBytes>::try_from(ms_encoded.to_p2wsh().unwrap().as_bytes()).unwrap() ) .into_script() ); diff --git a/src/interpreter/inner.rs b/src/interpreter/inner.rs index fb0a111fe..48a0d5f6f 100644 --- a/src/interpreter/inner.rs +++ b/src/interpreter/inner.rs @@ -426,7 +426,6 @@ impl ToNoChecks for Miniscript Terminal { /// Encode the element as a fragment of Bitcoin Script. The inverse /// function, from Script to an AST element, is implemented in the /// `parse` module. - pub fn encode( - &self, - mut builder: bitcoin::script::Builder, - ) -> bitcoin::script::Builder + pub fn encode(&self, mut builder: bitcoin::script::Builder) -> bitcoin::script::Builder where Pk: ToPublicKey, { diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index b2f0d9f49..f082b2f63 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -1110,8 +1110,8 @@ mod tests { use core::str::FromStr; use bitcoin::hashes::{hash160, sha256}; - use bitcoin::XOnlyPublicKey; use bitcoin::taproot::TapLeafHash; + use bitcoin::XOnlyPublicKey; use sync::Arc; use super::{Miniscript, ScriptContext, Segwitv0, Tap}; diff --git a/src/psbt/finalizer.rs b/src/psbt/finalizer.rs index 47fd8cfe2..8cc20203b 100644 --- a/src/psbt/finalizer.rs +++ b/src/psbt/finalizer.rs @@ -72,9 +72,8 @@ fn construct_tap_witness( continue; } let script_spk = Script::from_bytes(script.as_bytes()); - let ms = match Miniscript::::decode_consensus( - script_spk, - ) { + let ms = match Miniscript::::decode_consensus(script_spk) + { Ok(ms) => ms.substitute_raw_pkh(&map), Err(..) => continue, // try another script }; From 898fd5e7377892f4b8c39fb02dc59fa70058648e Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 15:25:31 -0600 Subject: [PATCH 14/23] bitcoin 0.33: drop ScriptBuf/Script/ScriptBuilder re-exports The `miniscript::ScriptBuf`, `miniscript::Script` and `miniscript::ScriptBuilder` type aliases in `src/lib.rs` flattened bitcoin 0.33's role-tagged script types back to a single `ScriptPubKeyTag`-specialized alias, hiding the distinction between scriptPubKey / scriptSig / redeemScript / witnessScript / tapScript from every downstream caller. That was always a compromise to keep internal migration mechanical. This commit removes the re-exports and migrates every call site to the tagged types it actually needs: - `scriptPubKey` values (`script_pubkey`, `explicit_script`, `script_code`, the script-pubkey comparisons in the interpreter) become `bitcoin::script::ScriptPubKey` / `ScriptPubKeyBuf`. - `scriptSig` values (every `unsigned_script_sig`, every empty `ScriptBuf::new()` that represented a scriptSig, `witness_to_scriptsig`) become `ScriptSig` / `ScriptSigBuf`. - `witnessScript` returns from `Wsh::inner_script` / `ecdsa_sighash_script_code` stay as `WitnessScriptBuf`. - `redeemScript` returns from `Sh::inner_script` / `ecdsa_sighash_script_code` / `unsigned_script_sig` stay as `RedeemScriptBuf` / `ScriptSigBuf`. - `TapScriptBuf` is threaded through `Placeholder::TapScript`, the tap satisfier helpers, `TrSpendInfo`, the fuzz tap roundtripper, and the PSBT-finalizer tap witness construction. Side effects of dropping the aliases: - `push_astelem` no longer picks the scriptPubKey-tagged builder; every builder construction now spells out `Builder::::new()` (or `ScriptSigTag` / `ScriptPubKeyTag`) so the tag is visible at the construction site. - The PSBT-finalizer module keeps a pair of local aliases (`Script = ScriptPubKey`, `ScriptBuf = ScriptPubKeyBuf`) because a large block of code there is tightly coupled to the "compare against txout scriptPubKey" notion; the aliases are now scoped to that file instead of crate-wide. - The interpreter's lex/decode path uses a file-local alias `ScriptPubKey as Script` so `Miniscript::decode(&Script)` keeps its previous spelling while being explicit about the tag at the use site. Breaking change for downstream: anything that spelled `miniscript::ScriptBuf`, `miniscript::Script`, or `miniscript::ScriptBuilder` must now spell the bitcoin 0.33 tagged type it actually wants. `cargo test --all-targets` passes 151 lib tests and 9 doctests; examples and the fuzz crate both build; `cargo clippy --all-targets -- -D warnings` is clean. Co-Authored-By: Claude Opus 4.7 (1M context) --- examples/sign_multisig.rs | 2 +- examples/verify_tx.rs | 2 +- .../roundtrip_miniscript_script_tap.rs | 2 +- src/descriptor/bare.rs | 18 ++++---- src/descriptor/mod.rs | 41 ++++++++++-------- src/descriptor/segwitv0.rs | 14 +++---- src/descriptor/sh.rs | 4 +- src/descriptor/tr/mod.rs | 10 ++--- src/descriptor/tr/spend_info.rs | 8 ++-- src/descriptor/tr/taptree.rs | 2 +- src/interpreter/inner.rs | 42 +++++++++---------- src/interpreter/mod.rs | 6 +-- src/lib.rs | 17 +------- src/miniscript/lex.rs | 3 +- src/miniscript/mod.rs | 27 ++++++------ src/miniscript/satisfy.rs | 15 +++---- src/plan.rs | 6 +-- src/psbt/finalizer.rs | 9 ++-- src/psbt/mod.rs | 19 +++++---- 19 files changed, 121 insertions(+), 126 deletions(-) diff --git a/examples/sign_multisig.rs b/examples/sign_multisig.rs index e10cd3e1c..86ec9f9dd 100644 --- a/examples/sign_multisig.rs +++ b/examples/sign_multisig.rs @@ -7,7 +7,7 @@ use std::str::FromStr; use bitcoin::blockdata::witness::Witness; use bitcoin::{absolute, ecdsa, transaction, Amount, OutPoint, Sequence}; -use miniscript::ScriptBuf; +use miniscript::bitcoin::script::ScriptPubKeyBuf as ScriptBuf; fn main() { let mut tx = spending_transaction(); diff --git a/examples/verify_tx.rs b/examples/verify_tx.rs index d6aeab2fa..e5891a804 100644 --- a/examples/verify_tx.rs +++ b/examples/verify_tx.rs @@ -5,10 +5,10 @@ use std::str::FromStr; use miniscript::bitcoin::consensus::Decodable; +use miniscript::bitcoin::script::ScriptPubKeyBuf as ScriptBuf; use miniscript::bitcoin::secp256k1::Secp256k1; use miniscript::bitcoin::{absolute, sighash, Sequence}; use miniscript::interpreter::KeySigPair; -use miniscript::ScriptBuf; fn main() { // diff --git a/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs b/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs index b180f886a..8e010051e 100644 --- a/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs +++ b/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs @@ -5,7 +5,7 @@ use miniscript::{Miniscript, Tap}; fn do_test(data: &[u8]) { // Try round-tripping as a script - let script = miniscript::Script::from_bytes(data); + let script = miniscript::bitcoin::script::ScriptPubKey::from_bytes(data); if let Ok(pt) = Miniscript::::decode(script) { let output: miniscript::bitcoin::script::ScriptPubKeyBuf = pt.encode(); diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index d626b2b14..8dacd8896 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -9,7 +9,7 @@ use core::fmt; -use bitcoin::script::PushBytes; +use bitcoin::script::{PushBytes, ScriptPubKeyBuf}; use bitcoin::{Address, Network, Weight}; use crate::descriptor::{write_descriptor, DefiniteDescriptorKey}; @@ -21,8 +21,8 @@ use crate::policy::{semantic, Liftable}; use crate::prelude::*; use crate::util::{varint_len, witness_to_scriptsig}; use crate::{ - BareCtx, Error, ForEachKey, FromStrKey, Miniscript, MiniscriptKey, Satisfier, ScriptBuf, - ToPublicKey, TranslateErr, Translator, + BareCtx, Error, ForEachKey, FromStrKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey, + TranslateErr, Translator, }; /// Create a Bare Descriptor. That is descriptor that is @@ -103,13 +103,13 @@ impl Bare { impl Bare { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { self.ms.encode() } + pub fn script_pubkey(&self) -> ScriptPubKeyBuf { self.ms.encode() } /// Obtains the underlying miniscript for this descriptor. - pub fn inner_script(&self) -> ScriptBuf { self.script_pubkey() } + pub fn inner_script(&self) -> ScriptPubKeyBuf { self.script_pubkey() } /// Obtains the pre bip-340 signature script code for this descriptor. - pub fn ecdsa_sighash_script_code(&self) -> ScriptBuf { self.script_pubkey() } + pub fn ecdsa_sighash_script_code(&self) -> ScriptPubKeyBuf { self.script_pubkey() } /// Returns satisfying non-malleable witness and scriptSig with minimum /// weight to spend an output controlled by the given descriptor if it is @@ -273,7 +273,7 @@ impl Pkh { impl Pkh { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { + pub fn script_pubkey(&self) -> ScriptPubKeyBuf { // Fine to hard code the `Network` here because we immediately call // `script_pubkey` which does not use the `network` field of `Address`. let addr = self.address(Network::Bitcoin); @@ -286,10 +286,10 @@ impl Pkh { } /// Obtains the underlying miniscript for this descriptor. - pub fn inner_script(&self) -> ScriptBuf { self.script_pubkey() } + pub fn inner_script(&self) -> ScriptPubKeyBuf { self.script_pubkey() } /// Obtains the pre bip-340 signature script code for this descriptor. - pub fn ecdsa_sighash_script_code(&self) -> ScriptBuf { self.script_pubkey() } + pub fn ecdsa_sighash_script_code(&self) -> ScriptPubKeyBuf { self.script_pubkey() } /// Returns satisfying non-malleable witness and scriptSig with minimum /// weight to spend an output controlled by the given descriptor if it is diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index e42fc10e2..2b61e9841 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -16,6 +16,7 @@ use core::ops::Range; use core::str::{self, FromStr}; use bitcoin::hashes::{hash160, ripemd160, sha256}; +use bitcoin::script::{ScriptPubKey, ScriptPubKeyBuf}; use bitcoin::{Address, Network, TxIn, Weight, Witness, WitnessVersion}; use sync::Arc; @@ -27,7 +28,7 @@ use crate::plan::{AssetProvider, Plan}; use crate::prelude::*; use crate::{ expression, hash256, BareCtx, Error, ForEachKey, FromStrKey, MiniscriptKey, ParseError, - Satisfier, Script, ScriptBuf, Threshold, ToPublicKey, TranslateErr, Translator, + Satisfier, Threshold, ToPublicKey, TranslateErr, Translator, }; mod bare; @@ -438,7 +439,7 @@ impl Descriptor { } /// Computes the scriptpubkey of the descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { + pub fn script_pubkey(&self) -> ScriptPubKeyBuf { match *self { Descriptor::Bare(ref bare) => bare.script_pubkey(), Descriptor::Pkh(ref pkh) => pkh.script_pubkey(), @@ -473,13 +474,17 @@ impl Descriptor { /// /// # Errors /// If the descriptor is a taproot descriptor. - pub fn explicit_script(&self) -> Result { + pub fn explicit_script(&self) -> Result { match *self { Descriptor::Bare(ref bare) => Ok(bare.script_pubkey()), Descriptor::Pkh(ref pkh) => Ok(pkh.script_pubkey()), Descriptor::Wpkh(ref wpkh) => Ok(wpkh.script_pubkey()), - Descriptor::Wsh(ref wsh) => Ok(ScriptBuf::from_bytes(wsh.inner_script().into_bytes())), - Descriptor::Sh(ref sh) => Ok(ScriptBuf::from_bytes(sh.inner_script().into_bytes())), + Descriptor::Wsh(ref wsh) => { + Ok(ScriptPubKeyBuf::from_bytes(wsh.inner_script().into_bytes())) + } + Descriptor::Sh(ref sh) => { + Ok(ScriptPubKeyBuf::from_bytes(sh.inner_script().into_bytes())) + } Descriptor::Tr(_) => Err(Error::TrNoScriptCode), } } @@ -491,16 +496,16 @@ impl Descriptor { /// /// # Errors /// If the descriptor is a taproot descriptor. - pub fn script_code(&self) -> Result { + pub fn script_code(&self) -> Result { match *self { Descriptor::Bare(ref bare) => Ok(bare.ecdsa_sighash_script_code()), Descriptor::Pkh(ref pkh) => Ok(pkh.ecdsa_sighash_script_code()), Descriptor::Wpkh(ref wpkh) => Ok(wpkh.ecdsa_sighash_script_code()), Descriptor::Wsh(ref wsh) => { - Ok(ScriptBuf::from_bytes(wsh.ecdsa_sighash_script_code().into_bytes())) + Ok(ScriptPubKeyBuf::from_bytes(wsh.ecdsa_sighash_script_code().into_bytes())) } Descriptor::Sh(ref sh) => { - Ok(ScriptBuf::from_bytes(sh.ecdsa_sighash_script_code().into_bytes())) + Ok(ScriptPubKeyBuf::from_bytes(sh.ecdsa_sighash_script_code().into_bytes())) } Descriptor::Tr(_) => Err(Error::TrNoScriptCode), } @@ -888,7 +893,7 @@ impl Descriptor { /// returned will be meaningless). pub fn find_derivation_index_for_spk( &self, - script_pubkey: &Script, + script_pubkey: &ScriptPubKey, range: Range, ) -> Result)>, NonDefiniteKeyError> { if !self.has_wildcard() { @@ -1273,7 +1278,7 @@ mod tests { let pk = StdDescriptor::from_str(TEST_PK).unwrap(); assert_eq!( pk.script_pubkey(), - ScriptBuf::from(vec![ + ScriptPubKeyBuf::from(vec![ 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xac, @@ -1288,7 +1293,7 @@ mod tests { .unwrap(); assert_eq!( pkh.script_pubkey(), - crate::ScriptBuilder::new() + bitcoin::script::Builder::::new() .push_opcode(opcodes::all::OP_DUP) .push_opcode(opcodes::all::OP_HASH160) .push_slice( @@ -1313,7 +1318,7 @@ mod tests { .unwrap(); assert_eq!( wpkh.script_pubkey(), - crate::ScriptBuilder::new() + bitcoin::script::Builder::::new() .push_opcode(opcodes::all::OP_PUSHBYTES_0) .push_slice( hash160::Hash::from_str("84e9ed95a38613f0527ff685a9928abe2d4754d4",) @@ -1335,7 +1340,7 @@ mod tests { .unwrap(); assert_eq!( shwpkh.script_pubkey(), - crate::ScriptBuilder::new() + bitcoin::script::Builder::::new() .push_opcode(opcodes::all::OP_HASH160) .push_slice( hash160::Hash::from_str("f1c3b9a431134cb90a500ec06e0067cfa9b8bba7",) @@ -1358,7 +1363,7 @@ mod tests { .unwrap(); assert_eq!( sh.script_pubkey(), - crate::ScriptBuilder::new() + bitcoin::script::Builder::::new() .push_opcode(opcodes::all::OP_HASH160) .push_slice( hash160::Hash::from_str("aa5282151694d3f2f32ace7d00ad38f927a33ac8",) @@ -1381,7 +1386,7 @@ mod tests { .unwrap(); assert_eq!( wsh.script_pubkey(), - crate::ScriptBuilder::new() + bitcoin::script::Builder::::new() .push_opcode(opcodes::all::OP_PUSHBYTES_0) .push_slice( sha256::Hash::from_str( @@ -1408,7 +1413,7 @@ mod tests { .unwrap(); assert_eq!( shwsh.script_pubkey(), - crate::ScriptBuilder::new() + bitcoin::script::Builder::::new() .push_opcode(opcodes::all::OP_HASH160) .push_slice( hash160::Hash::from_str("4bec5d7feeed99e1d0a23fe32a4afe126a7ff07e",) @@ -1516,7 +1521,7 @@ mod tests { let shwpkh = Descriptor::new_sh_wpkh(pk).unwrap(); shwpkh.satisfy(&mut txin, &satisfier).expect("satisfaction"); - let redeem_script = crate::ScriptBuilder::new() + let redeem_script = bitcoin::script::Builder::::new() .push_opcode(opcodes::all::OP_PUSHBYTES_0) .push_slice( hash160::Hash::from_str("d1b2a1faf62e73460af885c687dee3b7189cd8ab") @@ -2109,7 +2114,7 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))"; #[test] fn test_find_derivation_index_for_spk() { let descriptor = Descriptor::from_str("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)").unwrap(); - let script_at_0_1 = ScriptBuf::from_bytes( + let script_at_0_1 = ScriptPubKeyBuf::from_bytes( hex::decode_to_vec( "5120a82f29944d65b86ae6b5e5cc75e294ead6c59391a1edc5e016e3498c67fc7bbb", ) diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index f95e5a4a6..7873d93c3 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -8,7 +8,7 @@ use core::convert::TryFrom; use core::fmt; -use bitcoin::script::{WitnessScriptBuf, WitnessScriptExt as _}; +use bitcoin::script::{ScriptPubKeyBuf, WitnessScriptBuf, WitnessScriptExt as _}; use bitcoin::{Address, Network, Weight}; use crate::descriptor::{write_descriptor, DefiniteDescriptorKey}; @@ -21,8 +21,8 @@ use crate::policy::{semantic, Liftable}; use crate::prelude::*; use crate::util::varint_len; use crate::{ - Error, ForEachKey, FromStrKey, Miniscript, MiniscriptKey, Satisfier, ScriptBuf, Segwitv0, - Terminal, Threshold, ToPublicKey, TranslateErr, Translator, + Error, ForEachKey, FromStrKey, Miniscript, MiniscriptKey, Satisfier, Segwitv0, Terminal, + Threshold, ToPublicKey, TranslateErr, Translator, }; /// A Segwitv0 wsh descriptor #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] @@ -121,7 +121,7 @@ impl Wsh { impl Wsh { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { + pub fn script_pubkey(&self) -> ScriptPubKeyBuf { self.inner_script() .to_p2wsh() .expect("witness script size within bounds") @@ -319,7 +319,7 @@ impl Wpkh { impl Wpkh { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { + pub fn script_pubkey(&self) -> ScriptPubKeyBuf { let pk = self.pk.to_public_key(); let compressed = bitcoin::key::CompressedPublicKey::try_from(pk) .expect("wpkh descriptors have compressed keys"); @@ -338,10 +338,10 @@ impl Wpkh { } /// Obtains the underlying miniscript for this descriptor. - pub fn inner_script(&self) -> ScriptBuf { self.script_pubkey() } + pub fn inner_script(&self) -> ScriptPubKeyBuf { self.script_pubkey() } /// Obtains the pre bip-340 signature script code for this descriptor. - pub fn ecdsa_sighash_script_code(&self) -> ScriptBuf { + pub fn ecdsa_sighash_script_code(&self) -> ScriptPubKeyBuf { // For SegWit outputs, it is defined by bip-0143 (quoted below) and is different from // the previous txo's scriptPubKey. // The item 5: diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index eb099b8df..03aad2946 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -25,7 +25,7 @@ use crate::prelude::*; use crate::util::{varint_len, witness_to_scriptsig}; use crate::{ push_opcode_size, Error, ForEachKey, FromStrKey, Legacy, Miniscript, MiniscriptKey, Satisfier, - ScriptBuf, Segwitv0, Threshold, ToPublicKey, TranslateErr, Translator, + Segwitv0, Threshold, ToPublicKey, TranslateErr, Translator, }; /// A Legacy p2sh Descriptor @@ -252,7 +252,7 @@ impl Sh { impl Sh { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { + pub fn script_pubkey(&self) -> bitcoin::script::ScriptPubKeyBuf { match self.inner { ShInner::Wsh(ref wsh) => wsh .script_pubkey() diff --git a/src/descriptor/tr/mod.rs b/src/descriptor/tr/mod.rs index 2e9448c7b..6e83a39c1 100644 --- a/src/descriptor/tr/mod.rs +++ b/src/descriptor/tr/mod.rs @@ -17,8 +17,8 @@ use crate::policy::Liftable; use crate::prelude::*; use crate::util::{varint_len, witness_size}; use crate::{ - Error, ForEachKey, FromStrKey, MiniscriptKey, ParseError, Satisfier, ScriptBuf, ScriptBuilder, - ScriptContext, Tap, Threshold, ToPublicKey, TranslateErr, Translator, + Error, ForEachKey, FromStrKey, MiniscriptKey, ParseError, Satisfier, ScriptContext, Tap, + Threshold, ToPublicKey, TranslateErr, Translator, }; mod spend_info; @@ -267,9 +267,9 @@ impl Tr { impl Tr { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { + pub fn script_pubkey(&self) -> bitcoin::script::ScriptPubKeyBuf { let output_key = self.spend_info().output_key(); - let builder = ScriptBuilder::new(); + let builder = bitcoin::script::Builder::::new(); builder .push_opcode(opcodes::all::OP_PUSHNUM_1) .push_slice(output_key.serialize()) @@ -506,7 +506,7 @@ where _ => unreachable!(), }; - let script = ScriptBuf::from(leaf.script()); + let script = bitcoin::script::TapScriptBuf::from(leaf.script()); let control_block = leaf.control_block().clone(); wit.push(Placeholder::TapScript(script)); diff --git a/src/descriptor/tr/spend_info.rs b/src/descriptor/tr/spend_info.rs index 16030ab6e..4f0d236dd 100644 --- a/src/descriptor/tr/spend_info.rs +++ b/src/descriptor/tr/spend_info.rs @@ -15,7 +15,7 @@ use bitcoin::taproot::{ use crate::miniscript::context::Tap; use crate::prelude::Vec; use crate::sync::Arc; -use crate::{Miniscript, MiniscriptKey, Script, ScriptBuf, ToPublicKey}; +use crate::{Miniscript, MiniscriptKey, ToPublicKey}; /// Utility structure which maintains a stack of bits (at most 128) using a u128. /// @@ -226,7 +226,7 @@ struct TrSpendInfoNode { #[derive(Debug)] struct LeafData { - script: ScriptBuf, + script: TapScriptBuf, miniscript: Arc>, leaf_hash: TapLeafHash, } @@ -300,7 +300,7 @@ impl<'sp, Pk: MiniscriptKey> Iterator for TrSpendInfoIter<'sp, Pk> { /// Item yielded from a [`TrSpendInfoIter`]. #[derive(Clone, PartialEq, Eq, Debug)] pub struct TrSpendInfoIterItem<'tr, Pk: MiniscriptKey> { - script: &'tr Script, + script: &'tr TapScript, miniscript: &'tr Arc>, leaf_hash: TapLeafHash, control_block: ControlBlock, @@ -309,7 +309,7 @@ pub struct TrSpendInfoIterItem<'tr, Pk: MiniscriptKey> { impl<'sp, Pk: MiniscriptKey> TrSpendInfoIterItem<'sp, Pk> { /// The Tapscript of this leaf. #[inline] - pub fn script(&self) -> &'sp Script { self.script } + pub fn script(&self) -> &'sp TapScript { self.script } /// The Tapscript of this leaf, in Miniscript form. #[inline] diff --git a/src/descriptor/tr/taptree.rs b/src/descriptor/tr/taptree.rs index 0b0a4034d..d133c3ae9 100644 --- a/src/descriptor/tr/taptree.rs +++ b/src/descriptor/tr/taptree.rs @@ -216,7 +216,7 @@ impl TapTreeIterItem<'_, Pk> { /// all (or many) of the leaves of the tree, you may instead want to call /// [`super::Tr::spend_info`] and use the [`super::TrSpendInfo::leaves`] iterator instead. #[inline] - pub fn compute_script(&self) -> crate::ScriptBuf { self.node.encode() } + pub fn compute_script(&self) -> bitcoin::script::TapScriptBuf { self.node.encode() } /// Computes the [`TapLeafHash`] of the leaf. /// diff --git a/src/interpreter/inner.rs b/src/interpreter/inner.rs index 48a0d5f6f..0fe6f9074 100644 --- a/src/interpreter/inner.rs +++ b/src/interpreter/inner.rs @@ -48,7 +48,8 @@ fn script_from_stack_elem( ) -> Result, Error> { match *elem { stack::Element::Push(sl) => { - Miniscript::decode_consensus(crate::Script::from_bytes(sl)).map_err(Error::from) + Miniscript::decode_consensus(bitcoin::script::ScriptPubKey::from_bytes(sl)) + .map_err(Error::from) } stack::Element::Satisfied => Ok(Miniscript::TRUE), stack::Element::Dissatisfied => Ok(Miniscript::FALSE), @@ -96,10 +97,10 @@ pub(super) enum Inner { /// Tr outputs don't have script code and return None. #[allow(clippy::collapsible_else_if)] pub(super) fn from_txdata<'txin>( - spk: &crate::Script, - script_sig: &'txin crate::Script, + spk: &bitcoin::script::ScriptPubKey, + script_sig: &'txin bitcoin::script::ScriptPubKey, witness: &'txin Witness, -) -> Result<(Inner, Stack<'txin>, Option), Error> { +) -> Result<(Inner, Stack<'txin>, Option), Error> { let mut ssig_stack: Stack = script_sig .instructions_minimal() .map(stack::Element::from_instruction) @@ -134,7 +135,7 @@ pub(super) fn from_txdata<'txin>( Some(elem) => { let pk = pk_from_stack_elem(&elem, false)?; if *spk - == crate::ScriptBuf::new_p2pkh(PubkeyHash::from_byte_array( + == bitcoin::script::ScriptPubKeyBuf::new_p2pkh(PubkeyHash::from_byte_array( pk.to_pubkeyhash(SigType::Ecdsa).to_byte_array(), )) { @@ -160,16 +161,16 @@ pub(super) fn from_txdata<'txin>( let pk = pk_from_stack_elem(&elem, true)?; let hash160 = pk.to_pubkeyhash(SigType::Ecdsa); if *spk - == crate::ScriptBuf::new_p2wpkh(WPubkeyHash::from_byte_array( - hash160.to_byte_array(), - )) + == bitcoin::script::ScriptPubKeyBuf::new_p2wpkh( + WPubkeyHash::from_byte_array(hash160.to_byte_array()), + ) { Ok(( Inner::PublicKey(pk.into(), PubkeyType::Wpkh), wit_stack, - Some(crate::ScriptBuf::new_p2pkh(PubkeyHash::from_byte_array( - hash160.to_byte_array(), - ))), // bip143, why.. + Some(bitcoin::script::ScriptPubKeyBuf::new_p2pkh( + PubkeyHash::from_byte_array(hash160.to_byte_array()), + )), // bip143, why.. )) } else { Err(Error::IncorrectWPubkeyHash) @@ -190,9 +191,9 @@ pub(super) fn from_txdata<'txin>( let miniscript = miniscript.to_no_checks_ms(); let scripthash = sha256::Hash::hash(script.as_bytes()); if *spk - == crate::ScriptBuf::new_p2wsh(WScriptHash::from_byte_array( - scripthash.to_byte_array(), - )) + == bitcoin::script::ScriptPubKeyBuf::new_p2wsh( + WScriptHash::from_byte_array(scripthash.to_byte_array()), + ) { Ok((Inner::Script(miniscript, ScriptType::Wsh), wit_stack, Some(script))) } else { @@ -269,7 +270,7 @@ pub(super) fn from_txdata<'txin>( if let stack::Element::Push(slice) = elem { let scripthash = hash160::Hash::hash(slice); if *spk - != crate::ScriptBuf::new_p2sh(ScriptHash::from_byte_array( + != bitcoin::script::ScriptPubKeyBuf::new_p2sh(ScriptHash::from_byte_array( scripthash.to_byte_array(), )) { @@ -285,7 +286,7 @@ pub(super) fn from_txdata<'txin>( let pk = pk_from_stack_elem(&elem, true)?; let hash160 = pk.to_pubkeyhash(SigType::Ecdsa); if slice - == crate::ScriptBuf::new_p2wpkh( + == bitcoin::script::ScriptPubKeyBuf::new_p2wpkh( WPubkeyHash::from_byte_array(hash160.to_byte_array()), ) .as_bytes() @@ -293,7 +294,7 @@ pub(super) fn from_txdata<'txin>( Ok(( Inner::PublicKey(pk.into(), PubkeyType::ShWpkh), wit_stack, - Some(crate::ScriptBuf::new_p2pkh( + Some(bitcoin::script::ScriptPubKeyBuf::new_p2pkh( PubkeyHash::from_byte_array( hash160.to_byte_array(), ), @@ -319,7 +320,7 @@ pub(super) fn from_txdata<'txin>( let miniscript = miniscript.to_no_checks_ms(); let scripthash = sha256::Hash::hash(script.as_bytes()); if slice - == crate::ScriptBuf::new_p2wsh( + == bitcoin::script::ScriptPubKeyBuf::new_p2wsh( WScriptHash::from_byte_array( scripthash.to_byte_array(), ), @@ -347,7 +348,7 @@ pub(super) fn from_txdata<'txin>( if wit_stack.is_empty() { let scripthash = hash160::Hash::hash(script.as_bytes()); if *spk - == crate::ScriptBuf::new_p2sh(ScriptHash::from_byte_array( + == bitcoin::script::ScriptPubKeyBuf::new_p2sh(ScriptHash::from_byte_array( scripthash.to_byte_array(), )) { @@ -432,11 +433,10 @@ mod tests { use core::convert::TryFrom; use core::str::FromStr; - use bitcoin::script::PushBytes; + use bitcoin::script::{Builder as ScriptBuilderLocal, PushBytes, ScriptPubKeyBuf as ScriptBuf}; use hex; use super::*; - use crate::{ScriptBuf, ScriptBuilder as ScriptBuilderLocal}; struct KeyTestData { pk_spk: ScriptBuf, diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index c7a820b1f..64759574f 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -34,7 +34,7 @@ pub struct Interpreter<'txin> { stack: Stack<'txin>, /// For non-Taproot spends, the scriptCode; for Taproot script-spends, this /// is the leaf script; for key-spends it is `None`. - script_code: Option, + script_code: Option, sequence: Sequence, lock_time: absolute::LockTime, } @@ -142,8 +142,8 @@ impl<'txin> Interpreter<'txin> { /// function; otherwise, it should be a closure containing a sighash and /// secp context, which can actually verify a given signature. pub fn from_txdata( - spk: &crate::ScriptBuf, - script_sig: &'txin crate::Script, + spk: &bitcoin::script::ScriptPubKeyBuf, + script_sig: &'txin bitcoin::script::ScriptPubKey, witness: &'txin Witness, sequence: Sequence, // CSV, relative lock time. lock_time: absolute::LockTime, // CLTV, absolute lock time. diff --git a/src/lib.rs b/src/lib.rs index 508ace16d..a8536c86e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -132,19 +132,6 @@ use core::{fmt, hash, str}; use bitcoin::hashes::{hash160, ripemd160, sha256}; -/// Re-export of the tagged `ScriptBuf` used for scriptPubKey values in bitcoin 0.33+. -/// -/// Miniscript emits and consumes scriptPubKeys almost everywhere; this alias keeps -/// the existing `ScriptBuf` spelling working without having to reach into -/// `bitcoin::script` at every call-site. -pub type ScriptBuf = bitcoin::script::ScriptPubKeyBuf; - -/// Re-export of the tagged `Script` corresponding to [`ScriptBuf`]. -pub type Script = bitcoin::script::ScriptPubKey; - -/// Re-export of the tagged `script::Builder` for [`ScriptBuf`]. -pub type ScriptBuilder = bitcoin::script::Builder; - pub use crate::blanket_traits::FromStrKey; pub use crate::descriptor::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey}; pub use crate::error::ParseError; @@ -707,9 +694,9 @@ fn push_opcode_size(script_size: usize) -> usize { /// Helper function used by tests #[cfg(test)] -fn hex_script(s: &str) -> ScriptBuf { +fn hex_script(s: &str) -> bitcoin::script::ScriptPubKeyBuf { use bitcoin::script::ScriptBufExt as _; - ScriptBuf::from_hex(s).unwrap() + bitcoin::script::ScriptPubKeyBuf::from_hex(s).unwrap() } #[cfg(test)] diff --git a/src/miniscript/lex.rs b/src/miniscript/lex.rs index 2ad5e448b..aad38a795 100644 --- a/src/miniscript/lex.rs +++ b/src/miniscript/lex.rs @@ -8,10 +8,9 @@ use core::fmt; use bitcoin::blockdata::{opcodes, script}; -use bitcoin::script::ScriptExt as _; +use bitcoin::script::{ScriptExt as _, ScriptPubKey as Script}; use crate::prelude::*; -use crate::Script; /// Atom of a tokenized version of a script #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index f082b2f63..f77583b3a 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -15,13 +15,14 @@ use core::{hash, str}; use bitcoin::hashes::hash160; +use bitcoin::script::ScriptPubKey as Script; use bitcoin::taproot::{LeafVersion, TapLeafHash}; use self::analyzable::ExtParams; pub use self::context::{BareCtx, Legacy, Segwitv0, Tap}; use crate::iter::TreeLike; use crate::prelude::*; -use crate::{script_num_size, Script, TranslateErr}; +use crate::{script_num_size, TranslateErr}; pub mod analyzable; pub mod astelem; @@ -591,24 +592,24 @@ impl Miniscript { /// /// ```rust /// use miniscript::{Miniscript, Segwitv0, Tap}; - /// use miniscript::bitcoin::script::ScriptBufExt as _; + /// use miniscript::bitcoin::script::{ScriptBufExt as _, ScriptPubKeyBuf}; /// use miniscript::bitcoin::XOnlyPublicKey; /// /// type Segwitv0Script = Miniscript; /// type TapScript = Miniscript; /// /// // parse x-only miniscript in Taproot context - /// let tapscript_ms = TapScript::decode(&miniscript::ScriptBuf::from_hex( + /// let tapscript_ms = TapScript::decode(&ScriptPubKeyBuf::from_hex( /// "202788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac", /// ).expect("Even length hex")) /// .expect("Xonly keys are valid only in taproot context"); /// // tapscript fails decoding when we use them with compressed keys - /// let err = TapScript::decode(&miniscript::ScriptBuf::from_hex( + /// let err = TapScript::decode(&ScriptPubKeyBuf::from_hex( /// "21022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac", /// ).expect("Even length hex")) /// .expect_err("Compressed keys cannot be used in Taproot context"); /// // Segwitv0 succeeds decoding with full keys. - /// Segwitv0Script::decode(&miniscript::ScriptBuf::from_hex( + /// Segwitv0Script::decode(&ScriptPubKeyBuf::from_hex( /// "21022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac", /// ).expect("Even length hex")) /// .expect("Compressed keys are allowed in Segwit context"); @@ -1210,7 +1211,7 @@ mod tests { fn roundtrip(tree: &Segwitv0Script, s: &str) { assert_eq!(tree.ty.corr.base, types::Base::B); - let ser: crate::ScriptBuf = tree.encode(); + let ser: bitcoin::script::ScriptPubKeyBuf = tree.encode(); assert_eq!(ser.len(), tree.script_size()); assert_eq!(ser.to_string(), s); let deser = @@ -1230,7 +1231,7 @@ mod tests { let ms: Result = Miniscript::from_str_insane(ms); match (ms, valid) { (Ok(ms), true) => { - let encoded: crate::ScriptBuf = ms.encode(); + let encoded: bitcoin::script::ScriptPubKeyBuf = ms.encode(); assert_eq!(format!("{:x}", encoded), expected_hex); assert_eq!(ms.ty.mall.non_malleable, non_mal); assert_eq!(ms.ty.mall.safe, need_sig); @@ -1430,7 +1431,7 @@ mod tests { let tree: &Segwitv0Script = &ms_str!("c:pk_h({})", keys[5]); assert_eq!(tree.ty.corr.base, types::Base::B); - let ser: crate::ScriptBuf = tree.encode(); + let ser: bitcoin::script::ScriptPubKeyBuf = tree.encode(); let s = "\ OP_DUP OP_HASH160 OP_PUSHBYTES_20 \ 7e5a2a6a7610ca4ea78bd65a087bd75b1870e319 \ @@ -1730,10 +1731,10 @@ mod tests { ) .unwrap(); let ms_trans = ms.translate_pk(&mut StrKeyTranslator::new()).unwrap(); - let enc: crate::ScriptBuf = ms_trans.encode(); + let enc: bitcoin::script::ScriptPubKeyBuf = ms_trans.encode(); let ms = Miniscript::::decode_consensus(&enc).unwrap(); - let trans_enc: crate::ScriptBuf = ms_trans.encode(); - let re_enc: crate::ScriptBuf = ms.encode(); + let trans_enc: bitcoin::script::ScriptPubKeyBuf = ms_trans.encode(); + let re_enc: bitcoin::script::ScriptPubKeyBuf = ms.encode(); assert_eq!(trans_enc, re_enc); } @@ -1946,8 +1947,8 @@ mod tests { #[test] fn test_script_parse_dos() { - let mut script = - crate::ScriptBuilder::new().push_opcode(bitcoin::opcodes::all::OP_PUSHNUM_1); + let mut script = bitcoin::script::Builder::::new() + .push_opcode(bitcoin::opcodes::all::OP_PUSHNUM_1); for _ in 0..10000 { script = script.push_opcode(bitcoin::opcodes::all::OP_0NOTEQUAL); } diff --git a/src/miniscript/satisfy.rs b/src/miniscript/satisfy.rs index 9e6532506..7e8ede5a0 100644 --- a/src/miniscript/satisfy.rs +++ b/src/miniscript/satisfy.rs @@ -10,6 +10,7 @@ use core::{cmp, fmt, mem}; use bitcoin::hashes::hash160; use bitcoin::key::XOnlyPublicKey; +use bitcoin::script::TapScriptBuf; use bitcoin::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash}; use bitcoin::{absolute, relative, Sequence}; use sync::Arc; @@ -19,8 +20,8 @@ use crate::plan::AssetProvider; use crate::prelude::*; use crate::util::witness_size; use crate::{ - AbsLockTime, Miniscript, MiniscriptKey, RelLockTime, ScriptBuf, ScriptContext, Terminal, - Threshold, ToPublicKey, + AbsLockTime, Miniscript, MiniscriptKey, RelLockTime, ScriptContext, Terminal, Threshold, + ToPublicKey, }; /// Type alias for 32 byte Preimage. @@ -49,7 +50,7 @@ pub trait Satisfier { /// Obtain a reference to the control block for a ver and script fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { None } @@ -303,7 +304,7 @@ impl> Satisfier for &S { fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { (**self).lookup_tap_control_block_map() } @@ -363,7 +364,7 @@ impl> Satisfier for &mut S fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { (**self).lookup_tap_control_block_map() } @@ -473,7 +474,7 @@ macro_rules! impl_tuple_satisfier { fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { let &($(ref $ty,)*) = self; $( if let Some(result) = $ty.lookup_tap_control_block_map() { @@ -602,7 +603,7 @@ pub enum Placeholder { /// \ PushZero, /// Taproot leaf script - TapScript(ScriptBuf), + TapScript(TapScriptBuf), /// Taproot control block TapControlBlock(ControlBlock), } diff --git a/src/plan.rs b/src/plan.rs index 4a79ef772..d2fd3f56f 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -31,9 +31,7 @@ use crate::miniscript::hash256; use crate::miniscript::satisfy::{Placeholder, Satisfier, SchnorrSigType}; use crate::prelude::*; use crate::util::witness_size; -use crate::{ - DefiniteDescriptorKey, DescriptorPublicKey, Error, MiniscriptKey, ScriptBuf, ToPublicKey, -}; +use crate::{DefiniteDescriptorKey, DescriptorPublicKey, Error, MiniscriptKey, ToPublicKey}; /// Trait describing a present/missing lookup table for constructing witness templates /// @@ -325,7 +323,7 @@ impl Plan { #[derive(Default)] struct TrDescriptorData { - tap_script: Option, + tap_script: Option, control_block: Option, spend_type: Option, key_origins: BTreeMap, diff --git a/src/psbt/finalizer.rs b/src/psbt/finalizer.rs index 8cc20203b..b5e41a7e4 100644 --- a/src/psbt/finalizer.rs +++ b/src/psbt/finalizer.rs @@ -13,7 +13,10 @@ use core::mem; use bitcoin::hashes::hash160; use bitcoin::key::XOnlyPublicKey; -use bitcoin::script::{ScriptExt as _, ScriptPubKeyExt as _, WitnessScriptExt as _}; +use bitcoin::script::{ + ScriptExt as _, ScriptPubKey as Script, ScriptPubKeyBuf as ScriptBuf, ScriptPubKeyExt as _, + WitnessScriptExt as _, +}; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 use bitcoin::secp256k1; use bitcoin::secp256k1::Secp256k1; @@ -25,8 +28,8 @@ use super::{sanity_check, Error, InputError, Psbt, PsbtInputSatisfier}; use crate::prelude::*; use crate::util::witness_size; use crate::{ - interpreter, BareCtx, Descriptor, Legacy, Miniscript, Satisfier, Script, ScriptBuf, Segwitv0, - SigType, Tap, ToPublicKey, + interpreter, BareCtx, Descriptor, Legacy, Miniscript, Satisfier, Segwitv0, SigType, Tap, + ToPublicKey, }; // Satisfy the taproot descriptor. It is not possible to infer the complete diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index 41056ea39..0d18e8454 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -30,7 +30,7 @@ use crate::miniscript::context::SigType; use crate::prelude::*; use crate::{ descriptor, interpreter, DefiniteDescriptorKey, Descriptor, DescriptorPublicKey, MiniscriptKey, - Preimage32, Satisfier, Script, ScriptBuf, ToPublicKey, Translator, + Preimage32, Satisfier, ToPublicKey, Translator, }; mod finalizer; @@ -106,14 +106,14 @@ pub enum InputError { /// Redeem script redeem: RedeemScriptBuf, /// Expected p2sh Script - p2sh_expected: ScriptBuf, + p2sh_expected: bitcoin::script::ScriptPubKeyBuf, }, /// Witness script does not match the p2wsh hash InvalidWitnessScript { /// Witness Script witness_script: WitnessScriptBuf, /// Expected p2wsh script - p2wsh_expected: ScriptBuf, + p2wsh_expected: bitcoin::script::ScriptPubKeyBuf, }, /// Invalid sig InvalidSignature { @@ -298,7 +298,7 @@ impl Satisfier for PsbtInputSatisfier<'_> { fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { // The PSBT's `tap_scripts` field uses `TapScriptBuf`, which differs in type // from the `ScriptBuf` (= `ScriptPubKeyBuf`) required by this trait. We do // not attempt the conversion here; callers that need access to PSBT tap @@ -1092,7 +1092,7 @@ impl PsbtFields for psbt::Output { fn update_item_with_descriptor_helper( item: &mut F, descriptor: &Descriptor, - check_script: Option<&Script>, + check_script: Option<&bitcoin::script::ScriptPubKey>, // We return an extra boolean here to indicate an error with `check_script`. We do this // because the error is "morally" a UtxoUpdateError::MismatchedScriptPubkey, but some // callers expect a `descriptor::NonDefiniteKeyError`, which cannot be produced from a @@ -1600,7 +1600,7 @@ mod tests { inputs: vec![], outputs: vec![TxOut { amount: Amount::from_sat(1_000).expect("in range"), - script_pubkey: ScriptBuf::from_hex( + script_pubkey: bitcoin::script::ScriptPubKeyBuf::from_hex( "5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c", ) .unwrap(), @@ -1643,7 +1643,8 @@ mod tests { "non_witness_utxo no longer matches" ); psbt.inputs[0].non_witness_utxo = None; - psbt.inputs[0].witness_utxo.as_mut().unwrap().script_pubkey = ScriptBuf::default(); + psbt.inputs[0].witness_utxo.as_mut().unwrap().script_pubkey = + bitcoin::script::ScriptPubKeyBuf::default(); assert_eq!( psbt.update_input_with_descriptor(0, &desc), Err(UtxoUpdateError::MismatchedScriptPubkey), @@ -1662,7 +1663,7 @@ mod tests { inputs: vec![], outputs: vec![TxOut { amount: Amount::from_sat(1_000).expect("in range"), - script_pubkey: ScriptBuf::from_hex( + script_pubkey: bitcoin::script::ScriptPubKeyBuf::from_hex( "5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c", ) .unwrap(), @@ -1680,7 +1681,7 @@ mod tests { Ok(()), "script_pubkey should match" ); - psbt.unsigned_tx.outputs[0].script_pubkey = ScriptBuf::default(); + psbt.unsigned_tx.outputs[0].script_pubkey = bitcoin::script::ScriptPubKeyBuf::default(); assert_eq!( psbt.update_output_with_descriptor(0, &desc), Err(OutputUpdateError::MismatchedScriptPubkey), From c83397c046edaa72e69711107e1fd21e2cbd8281 Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 16:06:04 -0600 Subject: [PATCH 15/23] bitcoin 0.33: drop secp parameter from PsbtExt and Interpreter APIs `verify_sig`, `iter`, `interpreter_check`, all `PsbtExt::finalize_*`, and `extract` no longer take a secp context. Signature verification now routes through the `secp256k1::ecdsa::verify` and `secp256k1::schnorr::verify` free functions instead of the deprecated `Secp256k1::verify_*` / `sign_*` context methods. Cascades through examples and the in-crate test modules. Co-Authored-By: Claude Opus 4.7 (1M context) --- examples/big.rs | 6 +- examples/psbt_sign_finalize.rs | 12 +- examples/taptree_of_horror/helper_fns.rs | 6 +- .../taptree_of_horror/taptree_of_horror.rs | 35 ++--- examples/verify_tx.rs | 3 +- src/interpreter/mod.rs | 14 +- src/psbt/finalizer.rs | 50 ++----- src/psbt/mod.rs | 137 +++++------------- tests/bip-174.rs | 6 +- 9 files changed, 81 insertions(+), 188 deletions(-) diff --git a/examples/big.rs b/examples/big.rs index 1015d3284..9e5224fa3 100644 --- a/examples/big.rs +++ b/examples/big.rs @@ -20,7 +20,6 @@ use miniscript::{ translate_hash_fail, DefiniteDescriptorKey, Descriptor, DescriptorPublicKey, MiniscriptKey, Translator, }; -use secp256k1::Secp256k1; fn main() { let empty = "".to_string(); let mut args = std::env::args().collect::>(); @@ -39,8 +38,7 @@ fn main() { .unwrap(); println!("{}", a); - let secp = Secp256k1::new(); - let (d, m) = Descriptor::parse_descriptor(&secp, &i).unwrap(); + let (d, m) = Descriptor::parse_descriptor(&i).unwrap(); use_descriptor(d); println!("{:?}", m); @@ -52,7 +50,7 @@ fn main() { println!("{:?}", h.address(bitcoin::Network::Bitcoin)); let psbt: bitcoin::Psbt = i.parse().unwrap(); - let psbt = psbt.finalize(&secp).unwrap(); + let psbt = psbt.finalize().unwrap(); let mut tx = psbt.extract_tx().unwrap(); println!("{:?}", tx); diff --git a/examples/psbt_sign_finalize.rs b/examples/psbt_sign_finalize.rs index 105e506c2..b49664b2a 100644 --- a/examples/psbt_sign_finalize.rs +++ b/examples/psbt_sign_finalize.rs @@ -16,8 +16,6 @@ use miniscript::psbt::{PsbtExt, PsbtInputExt}; use miniscript::Descriptor; fn main() { - let secp256k1 = secp256k1::Secp256k1::new(); - let s = "wsh(t:or_c(pk(027a3565454fe1b749bccaef22aff72843a9c3efefd7b16ac54537a0c23f0ec0de),v:thresh(1,pkh(032d672a1a91cc39d154d366cd231983661b0785c7f27bc338447565844f4a6813),a:pkh(03417129311ed34c242c012cd0a3e0b9bca0065f742d0dfb63c78083ea6a02d4d9),a:pkh(025a687659658baeabdfc415164528065be7bcaade19342241941e556557f01e28))))#7hut9ukn"; let bridge_descriptor = Descriptor::from_str(s).unwrap(); //let bridge_descriptor = Descriptor::::from_str(&s).expect("parse descriptor string"); @@ -124,14 +122,14 @@ fn main() { let sk2 = *backup2_private.as_inner(); // Finally construct the signature and add to psbt - let sig1 = secp256k1.sign_ecdsa(msg, &sk1); + let sig1 = secp256k1::ecdsa::sign(msg, &sk1); let pk1 = backup1_private.public_key(); - assert!(secp256k1.verify_ecdsa(msg, &sig1, &pk1.to_inner()).is_ok()); + assert!(secp256k1::ecdsa::verify(&sig1, msg, &pk1.to_inner()).is_ok()); // Second key just in case - let sig2 = secp256k1.sign_ecdsa(msg, &sk2); + let sig2 = secp256k1::ecdsa::sign(msg, &sk2); let pk2 = backup2_private.public_key(); - assert!(secp256k1.verify_ecdsa(msg, &sig2, &pk2.to_inner()).is_ok()); + assert!(secp256k1::ecdsa::verify(&sig2, msg, &pk2.to_inner()).is_ok()); psbt.inputs[0] .partial_sigs @@ -140,7 +138,7 @@ fn main() { println!("{:#?}", psbt); println!("{}", psbt); - psbt.finalize_mut(&secp256k1).unwrap(); + psbt.finalize_mut().unwrap(); println!("{:#?}", psbt); let tx = psbt.extract_tx().expect("failed to extract tx"); diff --git a/examples/taptree_of_horror/helper_fns.rs b/examples/taptree_of_horror/helper_fns.rs index 9834ea1f0..38ac689f5 100644 --- a/examples/taptree_of_horror/helper_fns.rs +++ b/examples/taptree_of_horror/helper_fns.rs @@ -1,10 +1,9 @@ use std::str::FromStr; use bitcoin::bip32::{DerivationPath, Xpriv}; -use bitcoin::hashes::{ripemd160, sha256, Hash}; +use bitcoin::hashes::{ripemd160, sha256}; use miniscript::descriptor::DescriptorSecretKey; use miniscript::ToPublicKey; -use secp256k1::Secp256k1; use crate::KEYS_PER_PERSONA; @@ -28,7 +27,6 @@ pub fn produce_kelly_hash(secret: &str) -> (sha256::Hash, sha256::Hash) { pub fn produce_key_pairs( desc: DescriptorSecretKey, - secp: &Secp256k1, derivation_without_index: &str, _alias: &str, ) -> (Vec, Vec) { @@ -42,7 +40,7 @@ pub fn produce_key_pairs( for i in 0..KEYS_PER_PERSONA { let pk = desc - .to_public(secp) + .to_public() .unwrap() .at_derivation_index(i.try_into().unwrap()) .unwrap() diff --git a/examples/taptree_of_horror/taptree_of_horror.rs b/examples/taptree_of_horror/taptree_of_horror.rs index d2cf8116b..53e3d95bf 100644 --- a/examples/taptree_of_horror/taptree_of_horror.rs +++ b/examples/taptree_of_horror/taptree_of_horror.rs @@ -4,7 +4,6 @@ use bitcoin::absolute::LockTime; use bitcoin::blockdata::witness::Witness; use bitcoin::consensus::encode::serialize; use bitcoin::hashes::hex::prelude::DisplayHex; -use bitcoin::hashes::Hash; use bitcoin::transaction::Version; use bitcoin::{Address, Amount, Network, Psbt, PublicKey, Sequence, TxIn, TxOut}; use helper_fns::{produce_grim_hash, produce_kelly_hash, produce_key_pairs}; @@ -17,8 +16,6 @@ mod helper_fns; pub const KEYS_PER_PERSONA: usize = 9; fn main() { - let secp: &secp256k1::Secp256k1 = &secp256k1::Secp256k1::new(); - // ====== 1. Setup Hardcoded Values for all of the Personas ====== // Define derivation paths that will be used @@ -61,7 +58,7 @@ fn main() { // ====== 2. Derive Keys, Preimages, Hashes, and Timelocks for Policy and Signing ====== let internal_xpub: miniscript::DescriptorPublicKey = - internal_desc_secret.to_public(secp).unwrap(); + internal_desc_secret.to_public().unwrap(); // example of how defining the internal xpriv that can be used for signing. // let internal_xpriv: DescriptorXKey = match internal_desc_secret { @@ -70,20 +67,18 @@ fn main() { // } // .unwrap(); - let (a_pks, a_prvs) = produce_key_pairs(a_descriptor_desc_secret, secp, normal_path, "alice"); - let (b_pks, b_prvs) = produce_key_pairs(b_descriptor_desc_secret, secp, normal_path, "bob"); - let (c_pks, c_prvs) = produce_key_pairs(c_descriptor_desc_secret, secp, normal_path, "charlie"); - let (d_pks, d_prvs) = produce_key_pairs(d_descriptor_desc_secret, secp, weird_path, "dave"); - let (e_pks, e_prvs) = produce_key_pairs(e_descriptor_desc_secret, secp, normal_path, "eve"); - let (f_pks, f_prvs) = produce_key_pairs(f_descriptor_desc_secret, secp, normal_path, "frank"); - let (h_pks, h_prvs) = produce_key_pairs(h_descriptor_desc_secret, secp, normal_path, "heather"); - let (i_pks, i_prvs) = produce_key_pairs(i_descriptor_desc_secret, secp, unhardened_path, "ian"); - let (j_pks, j_prvs) = produce_key_pairs(j_descriptor_desc_secret, secp, normal_path, "judy"); - let (l_pks, l_prvs) = produce_key_pairs(l_descriptor_desc_secret, secp, normal_path, "liam"); - let (s_pks, _s_prvs) = - produce_key_pairs(s_descriptor_desc_secret, secp, normal_path, "s_backup1"); - let (x_pks, _x_prvs) = - produce_key_pairs(x_descriptor_desc_secret, secp, normal_path, "x_backup2"); + let (a_pks, a_prvs) = produce_key_pairs(a_descriptor_desc_secret, normal_path, "alice"); + let (b_pks, b_prvs) = produce_key_pairs(b_descriptor_desc_secret, normal_path, "bob"); + let (c_pks, c_prvs) = produce_key_pairs(c_descriptor_desc_secret, normal_path, "charlie"); + let (d_pks, d_prvs) = produce_key_pairs(d_descriptor_desc_secret, weird_path, "dave"); + let (e_pks, e_prvs) = produce_key_pairs(e_descriptor_desc_secret, normal_path, "eve"); + let (f_pks, f_prvs) = produce_key_pairs(f_descriptor_desc_secret, normal_path, "frank"); + let (h_pks, h_prvs) = produce_key_pairs(h_descriptor_desc_secret, normal_path, "heather"); + let (i_pks, i_prvs) = produce_key_pairs(i_descriptor_desc_secret, unhardened_path, "ian"); + let (j_pks, j_prvs) = produce_key_pairs(j_descriptor_desc_secret, normal_path, "judy"); + let (l_pks, l_prvs) = produce_key_pairs(l_descriptor_desc_secret, normal_path, "liam"); + let (s_pks, _s_prvs) = produce_key_pairs(s_descriptor_desc_secret, normal_path, "s_backup1"); + let (x_pks, _x_prvs) = produce_key_pairs(x_descriptor_desc_secret, normal_path, "x_backup2"); // For this example we are grabbing the 9 keys for each persona let [a0, a1, a2, a3, a4, a5, a6, a7, a8]: [PublicKey; KEYS_PER_PERSONA] = @@ -203,8 +198,6 @@ fn main() { // ====== 4. Construct an Unsigned Transaction from the Tapscript ====== - let secp: &secp256k1::Secp256k1 = &secp256k1::Secp256k1::new(); - let tx_in = TxIn { previous_output: bitcoin::OutPoint { txid: "8888888899999999aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffff" @@ -274,7 +267,7 @@ fn main() { .insert(grim.1, grim.0.to_byte_array().to_vec()); // Finalize PSBT now that we have all the required signatures and hash preimages. - psbt.finalize_mut(secp).unwrap(); + psbt.finalize_mut().unwrap(); // Now extract the tx let signed_tx = psbt.extract_tx().unwrap(); diff --git a/examples/verify_tx.rs b/examples/verify_tx.rs index e5891a804..7d3807f9d 100644 --- a/examples/verify_tx.rs +++ b/examples/verify_tx.rs @@ -66,13 +66,12 @@ fn main() { // as having participated in the script println!("\n\nExample two:\n"); - let secp = Secp256k1::new(); // We can set prevouts to be empty list because this is a legacy transaction // and this information is not required for sighash computation. let prevouts = sighash::Prevouts::All::(&[]); - for elem in interpreter.iter(&secp, &tx, 0, &prevouts) { + for elem in interpreter.iter(&tx, 0, &prevouts) { if let miniscript::interpreter::SatisfiedConstraint::PublicKey { key_sig } = elem.expect("no evaluation error") { diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 64759574f..a4d44b7b7 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -192,9 +192,8 @@ impl<'txin> Interpreter<'txin> { // TODO: Create a good first issue to change this to error // TODO: Requires refactor to remove the script_code logic in order to use the new sighash API. #[allow(deprecated)] // For segwit_signature_hash - pub fn verify_sig>( + pub fn verify_sig>( &self, - secp: &secp256k1::Secp256k1, tx: &bitcoin::Transaction, input_idx: usize, prevouts: &sighash::Prevouts, @@ -245,9 +244,7 @@ impl<'txin> Interpreter<'txin> { }; let success = msg.map(|msg| { - let inner_pk = key.to_inner(); - secp.verify_ecdsa(msg, &ecdsa_sig.signature, &inner_pk) - .is_ok() + secp256k1::ecdsa::verify(&ecdsa_sig.signature, msg, &key.to_inner()).is_ok() }); success.unwrap_or(false) // unwrap_or checks for errors, while success would have checksig results } @@ -280,7 +277,7 @@ impl<'txin> Interpreter<'txin> { }; let msg = sighash_msg.map(|hash| hash.to_byte_array()); let success = msg.map(|msg| { - secp.verify_schnorr(&schnorr_sig.signature, &msg, xpk.as_inner()) + secp256k1::schnorr::verify(&schnorr_sig.signature, &msg, xpk.as_inner()) .is_ok() }); success.unwrap_or(false) // unwrap_or_default checks for errors, while success would have checksig results @@ -305,14 +302,13 @@ impl<'txin> Interpreter<'txin> { /// - For legacy outputs, no information about prevouts is required /// - For segwitv0 outputs, prevout at corresponding index with correct amount must be provided /// - For taproot outputs, information about all prevouts must be supplied - pub fn iter<'iter, C: secp256k1::Verification, T: Borrow>( + pub fn iter<'iter, T: Borrow>( &'iter self, - secp: &'iter secp256k1::Secp256k1, tx: &'txin bitcoin::Transaction, input_idx: usize, prevouts: &'iter sighash::Prevouts, // actually a 'prevouts, but 'prevouts: 'iter ) -> Iter<'txin, 'iter> { - self.iter_custom(Box::new(move |sig| self.verify_sig(secp, tx, input_idx, prevouts, sig))) + self.iter_custom(Box::new(move |sig| self.verify_sig(tx, input_idx, prevouts, sig))) } /// Creates an iterator over the satisfied spending conditions without checking signatures diff --git a/src/psbt/finalizer.rs b/src/psbt/finalizer.rs index b5e41a7e4..a4822226e 100644 --- a/src/psbt/finalizer.rs +++ b/src/psbt/finalizer.rs @@ -17,9 +17,6 @@ use bitcoin::script::{ ScriptExt as _, ScriptPubKey as Script, ScriptPubKeyBuf as ScriptBuf, ScriptPubKeyExt as _, WitnessScriptExt as _, }; -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 -use bitcoin::secp256k1; -use bitcoin::secp256k1::Secp256k1; use bitcoin::sighash::Prevouts; use bitcoin::taproot::LeafVersion; use bitcoin::{PublicKey, TxOut, Witness}; @@ -322,10 +319,7 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In /// The psbt must have included final script sig and final witness. /// In other words, this checks whether the finalized psbt interprets /// correctly -pub fn interpreter_check( - psbt: &Psbt, - secp: &Secp256k1, -) -> Result<(), Error> { +pub fn interpreter_check(psbt: &Psbt) -> Result<(), Error> { let utxos = prevouts(psbt)?; let utxos = &Prevouts::All(&utxos); for (index, input) in psbt.inputs.iter().enumerate() { @@ -341,15 +335,14 @@ pub fn interpreter_check( .map(|wit_slice| Witness::from_slice(&wit_slice.to_vec())) // TODO: Update rust-bitcoin psbt API to use witness .unwrap_or(empty_witness); - interpreter_inp_check(psbt, secp, index, utxos, &witness, &script_sig)?; + interpreter_inp_check(psbt, index, utxos, &witness, &script_sig)?; } Ok(()) } // Run the miniscript interpreter on a single psbt input -fn interpreter_inp_check>( +fn interpreter_inp_check>( psbt: &Psbt, - secp: &Secp256k1, index: usize, utxos: &Prevouts, witness: &Witness, @@ -369,7 +362,7 @@ fn interpreter_inp_check>( let interpreter = interpreter::Interpreter::from_txdata(&spk, script_sig_spk, witness, csv, cltv) .map_err(|e| Error::InputError(InputError::Interpreter(e), index))?; - let iter = interpreter.iter(secp, &psbt.unsigned_tx, index, utxos); + let iter = interpreter.iter(&psbt.unsigned_tx, index, utxos); if let Some(error) = iter.filter_map(Result::err).next() { return Err(Error::InputError(InputError::Interpreter(error), index)); }; @@ -389,31 +382,17 @@ fn interpreter_inp_check>( /// The functions fails it is not possible to satisfy any of the inputs non-malleably /// See [finalize_mall] if you want to allow malleable satisfactions #[deprecated(since = "7.0.0", note = "Please use PsbtExt::finalize instead")] -pub fn finalize( - psbt: &mut Psbt, - secp: &Secp256k1, -) -> Result<(), super::Error> { - finalize_helper(psbt, secp, false) -} +pub fn finalize(psbt: &mut Psbt) -> Result<(), super::Error> { finalize_helper(psbt, false) } /// Same as [finalize], but allows for malleable satisfactions -pub fn finalize_mall( - psbt: &mut Psbt, - secp: &Secp256k1, -) -> Result<(), super::Error> { - finalize_helper(psbt, secp, true) -} +pub fn finalize_mall(psbt: &mut Psbt) -> Result<(), super::Error> { finalize_helper(psbt, true) } -pub fn finalize_helper( - psbt: &mut Psbt, - secp: &Secp256k1, - allow_mall: bool, -) -> Result<(), super::Error> { +pub fn finalize_helper(psbt: &mut Psbt, allow_mall: bool) -> Result<(), super::Error> { sanity_check(psbt)?; // Actually construct the witnesses for index in 0..psbt.inputs.len() { - finalize_input(psbt, index, secp, allow_mall)?; + finalize_input(psbt, index, allow_mall)?; } // Interpreter is already run inside finalize_input for each input Ok(()) @@ -421,10 +400,9 @@ pub fn finalize_helper( // Helper function to obtain psbt final_witness/final_script_sig. // Does not add fields to the psbt, only returns the values. -fn finalize_input_helper( +fn finalize_input_helper( psbt: &Psbt, index: usize, - secp: &Secp256k1, allow_mall: bool, ) -> Result<(Witness, bitcoin::script::ScriptSigBuf), super::Error> { let (witness, script_sig) = { @@ -454,18 +432,17 @@ fn finalize_input_helper( let witness = bitcoin::Witness::from_slice(&witness); let utxos = prevouts(psbt)?; let utxos = &Prevouts::All(&utxos); - interpreter_inp_check(psbt, secp, index, utxos, &witness, &script_sig)?; + interpreter_inp_check(psbt, index, utxos, &witness, &script_sig)?; Ok((witness, script_sig)) } -pub(super) fn finalize_input( +pub(super) fn finalize_input( psbt: &mut Psbt, index: usize, - secp: &Secp256k1, allow_mall: bool, ) -> Result<(), super::Error> { - let (witness, script_sig) = finalize_input_helper(psbt, index, secp, allow_mall)?; + let (witness, script_sig) = finalize_input_helper(psbt, index, allow_mall)?; // Now mutate the psbt input. Note that we cannot error after this point. // If the input is mutated, it means that the finalization succeeded. @@ -500,8 +477,7 @@ mod tests { fn tests_from_bip174() { let mut psbt = Psbt::deserialize(&hex::decode_to_vec("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f012202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d2010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000").unwrap()).unwrap(); - let secp = Secp256k1::verification_only(); - psbt.finalize_mut(&secp).unwrap(); + psbt.finalize_mut().unwrap(); let expected = Psbt::deserialize(&hex::decode_to_vec("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000").unwrap()).unwrap(); assert_eq!(psbt, expected); diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index 0d18e8454..e29f32d94 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -20,7 +20,6 @@ use bitcoin::script::{ }; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 use bitcoin::secp256k1; -use bitcoin::secp256k1::Secp256k1; use bitcoin::sighash::{self, SighashCache}; use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapLeafHash}; use bitcoin::transaction::TxInExt as _; @@ -268,7 +267,7 @@ impl<'psbt> PsbtInputSatisfier<'psbt> { impl Satisfier for PsbtInputSatisfier<'_> { fn lookup_tap_key_spend_sig(&self, pk: &Pk) -> Option { if let Some(key) = self.psbt_input().tap_internal_key { - let pk_xonly: bitcoin::key::XOnlyPublicKey = pk.to_x_only_pubkey().into(); + let pk_xonly: bitcoin::key::XOnlyPublicKey = pk.to_x_only_pubkey(); if pk_xonly == key { return self.psbt_input().tap_key_sig; } @@ -281,7 +280,7 @@ impl Satisfier for PsbtInputSatisfier<'_> { pk: &Pk, lh: &TapLeafHash, ) -> Option { - let pk_xonly: bitcoin::key::XOnlyPublicKey = pk.to_x_only_pubkey().into(); + let pk_xonly: bitcoin::key::XOnlyPublicKey = pk.to_x_only_pubkey(); self.psbt_input() .tap_script_sigs .get(&(pk_xonly, *lh)) @@ -454,10 +453,7 @@ pub trait PsbtExt { /// # Errors: /// /// - A vector of errors, one of each of failed finalized input - fn finalize_mut( - &mut self, - secp: &secp256k1::Secp256k1, - ) -> Result<(), Vec>; + fn finalize_mut(&mut self) -> Result<(), Vec>; /// Same as [`PsbtExt::finalize_mut`], but does not mutate the input psbt and /// returns a new psbt @@ -467,23 +463,14 @@ pub trait PsbtExt { /// - Returns a mutated psbt with all inputs `finalize_mut` could finalize /// - A vector of input errors, one of each of failed finalized input #[allow(clippy::result_large_err)] - fn finalize( - self, - secp: &secp256k1::Secp256k1, - ) -> Result)>; + fn finalize(self) -> Result)>; /// Same as [PsbtExt::finalize_mut], but allows for malleable satisfactions - fn finalize_mall_mut( - &mut self, - secp: &Secp256k1, - ) -> Result<(), Vec>; + fn finalize_mall_mut(&mut self) -> Result<(), Vec>; /// Same as [PsbtExt::finalize], but allows for malleable satisfactions #[allow(clippy::result_large_err)] - fn finalize_mall( - self, - secp: &Secp256k1, - ) -> Result)>; + fn finalize_mall(self) -> Result)>; /// Same as [`PsbtExt::finalize_mut`], but only tries to finalize a single input leaving other /// inputs as is. Use this when not all of inputs that you are trying to @@ -492,11 +479,7 @@ pub trait PsbtExt { /// # Errors: /// /// - Input error detailing why the finalization failed. The psbt is not mutated when the finalization fails - fn finalize_inp_mut( - &mut self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result<(), Error>; + fn finalize_inp_mut(&mut self, index: usize) -> Result<(), Error>; /// Same as [`PsbtExt::finalize_inp_mut`], but does not mutate the psbt and returns a new one /// @@ -505,26 +488,14 @@ pub trait PsbtExt { /// - Original psbt /// - Input Error detailing why the input finalization failed #[allow(clippy::result_large_err)] // our "error type" includes the original PSBT - fn finalize_inp( - self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result; + fn finalize_inp(self, index: usize) -> Result; /// Same as [`PsbtExt::finalize_inp_mut`], but allows for malleable satisfactions - fn finalize_inp_mall_mut( - &mut self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result<(), Error>; + fn finalize_inp_mall_mut(&mut self, index: usize) -> Result<(), Error>; /// Same as [`PsbtExt::finalize_inp`], but allows for malleable satisfactions #[allow(clippy::result_large_err)] // our "error type" includes the original PSBT - fn finalize_inp_mall( - self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result; + fn finalize_inp_mall(self, index: usize) -> Result; /// Psbt extractor as defined in BIP174 that takes in a psbt reference /// and outputs a extracted [`bitcoin::Transaction`]. @@ -533,10 +504,7 @@ pub trait PsbtExt { /// /// Will error if the final ScriptSig or final Witness are missing /// or the interpreter check fails. - fn extract( - &self, - secp: &Secp256k1, - ) -> Result; + fn extract(&self) -> Result; /// Update PSBT input with a descriptor and check consistency of `*_utxo` fields. /// @@ -607,14 +575,11 @@ pub trait PsbtExt { } impl PsbtExt for Psbt { - fn finalize_mut( - &mut self, - secp: &secp256k1::Secp256k1, - ) -> Result<(), Vec> { + fn finalize_mut(&mut self) -> Result<(), Vec> { // Actually construct the witnesses let mut errors = vec![]; for index in 0..self.inputs.len() { - match finalizer::finalize_input(self, index, secp, /*allow_mall*/ false) { + match finalizer::finalize_input(self, index, /*allow_mall*/ false) { Ok(..) => {} Err(e) => { errors.push(e); @@ -628,23 +593,17 @@ impl PsbtExt for Psbt { } } - fn finalize( - mut self, - secp: &secp256k1::Secp256k1, - ) -> Result)> { - match self.finalize_mut(secp) { + fn finalize(mut self) -> Result)> { + match self.finalize_mut() { Ok(..) => Ok(self), Err(e) => Err((self, e)), } } - fn finalize_mall_mut( - &mut self, - secp: &secp256k1::Secp256k1, - ) -> Result<(), Vec> { + fn finalize_mall_mut(&mut self) -> Result<(), Vec> { let mut errors = vec![]; for index in 0..self.inputs.len() { - match finalizer::finalize_input(self, index, secp, /*allow_mall*/ true) { + match finalizer::finalize_input(self, index, /*allow_mall*/ true) { Ok(..) => {} Err(e) => { errors.push(e); @@ -658,64 +617,42 @@ impl PsbtExt for Psbt { } } - fn finalize_mall( - mut self, - secp: &Secp256k1, - ) -> Result)> { - match self.finalize_mall_mut(secp) { + fn finalize_mall(mut self) -> Result)> { + match self.finalize_mall_mut() { Ok(..) => Ok(self), Err(e) => Err((self, e)), } } - fn finalize_inp_mut( - &mut self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result<(), Error> { + fn finalize_inp_mut(&mut self, index: usize) -> Result<(), Error> { if index >= self.inputs.len() { return Err(Error::InputIdxOutofBounds { psbt_inp: self.inputs.len(), index }); } - finalizer::finalize_input(self, index, secp, /*allow_mall*/ false) + finalizer::finalize_input(self, index, /*allow_mall*/ false) } - fn finalize_inp( - mut self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result { - match self.finalize_inp_mut(secp, index) { + fn finalize_inp(mut self, index: usize) -> Result { + match self.finalize_inp_mut(index) { Ok(..) => Ok(self), Err(e) => Err((self, e)), } } - fn finalize_inp_mall_mut( - &mut self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result<(), Error> { + fn finalize_inp_mall_mut(&mut self, index: usize) -> Result<(), Error> { if index >= self.inputs.len() { return Err(Error::InputIdxOutofBounds { psbt_inp: self.inputs.len(), index }); } - finalizer::finalize_input(self, index, secp, /*allow_mall*/ false) + finalizer::finalize_input(self, index, /*allow_mall*/ false) } - fn finalize_inp_mall( - mut self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result { - match self.finalize_inp_mall_mut(secp, index) { + fn finalize_inp_mall(mut self, index: usize) -> Result { + match self.finalize_inp_mall_mut(index) { Ok(..) => Ok(self), Err(e) => Err((self, e)), } } - fn extract( - &self, - secp: &Secp256k1, - ) -> Result { + fn extract(&self) -> Result { sanity_check(self)?; let mut ret = self.unsigned_tx.clone(); @@ -731,7 +668,7 @@ impl PsbtExt for Psbt { ret.inputs[n].script_sig = script_sig.clone(); } } - interpreter_check(self, secp)?; + interpreter_check(self)?; Ok(ret) } @@ -1121,7 +1058,7 @@ fn update_item_with_descriptor_helper( *item.tap_internal_key() = Some(spend_info.internal_key()); for (derived_key, key_source) in xpub_map { - let xonly: bitcoin::key::XOnlyPublicKey = derived_key.to_x_only_pubkey().into(); + let xonly: bitcoin::key::XOnlyPublicKey = derived_key.to_x_only_pubkey(); item.tap_key_origins().insert(xonly, (vec![], key_source)); } if let Some(merkle_root) = item.tap_merkle_root() { @@ -1140,7 +1077,7 @@ fn update_item_with_descriptor_helper( } for leaf_pk in leaf_derived.miniscript().iter_pk() { - let xonly: bitcoin::key::XOnlyPublicKey = leaf_pk.to_x_only_pubkey().into(); + let xonly: bitcoin::key::XOnlyPublicKey = leaf_pk.to_x_only_pubkey(); let tapleaf_hashes = &mut item .tap_key_origins() .get_mut(&xonly) @@ -1174,10 +1111,11 @@ fn update_item_with_descriptor_helper( descriptor::ShInner::Wsh(wsh) => { let inner = wsh.inner_script(); let witness_script = WitnessScriptBuf::from_bytes(inner.to_vec()); - if let Ok(p2wsh_spk) = witness_script.to_p2wsh() { - *item.redeem_script() = - Some(RedeemScriptBuf::from_bytes(p2wsh_spk.into_bytes())); - } + let p2wsh_spk = witness_script + .to_p2wsh() + .expect("witness script size within bounds"); + *item.redeem_script() = + Some(RedeemScriptBuf::from_bytes(p2wsh_spk.into_bytes())); *item.witness_script() = Some(witness_script); } descriptor::ShInner::Wpkh(..) => { @@ -1407,8 +1345,7 @@ mod tests { #[test] fn test_extract_bip174() { let psbt = bitcoin::Psbt::deserialize(&hex::decode_to_vec("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000").unwrap()).unwrap(); - let secp = Secp256k1::verification_only(); - let tx = psbt.extract(&secp).unwrap(); + let tx = psbt.extract().unwrap(); let expected: bitcoin::Transaction = deserialize(&hex::decode_to_vec("0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000").unwrap()).unwrap(); assert_eq!(tx, expected); } diff --git a/tests/bip-174.rs b/tests/bip-174.rs index 25f8e2d2b..dc955c15a 100644 --- a/tests/bip-174.rs +++ b/tests/bip-174.rs @@ -12,17 +12,15 @@ fn main() { let expected_finalized_psbt = Psbt::deserialize(&hex::decode_to_vec("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000").unwrap()).unwrap(); - // Construct a secp context for transaction signature verification - let secp = bitcoin::secp256k1::Secp256k1::verification_only(); // Assuming all partial sigs are filled in. // Construct a generic finalizer - psbt.finalize_mut(&secp).unwrap(); + psbt.finalize_mut().unwrap(); // println!("{:?}", psbt); assert_eq!(psbt, expected_finalized_psbt); // Extract the transaction from the psbt - let tx = psbt.extract(&secp).unwrap(); + let tx = psbt.extract().unwrap(); let expected: bitcoin::Transaction = deserialize(&hex::decode_to_vec("0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000").unwrap()).unwrap(); // println!("{:?}", tx); From e2cf3917a9645333e74b49816e5206f112aab2b8 Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 16:08:13 -0600 Subject: [PATCH 16/23] bitcoin 0.33: return tagged bitcoin::XOnlyPublicKey from ToPublicKey `ToPublicKey::to_x_only_pubkey` now returns the role-tagged `bitcoin::XOnlyPublicKey` instead of the raw `bitcoin::secp256k1::XOnlyPublicKey`. The untagged secp type is still supported via the `ToPublicKey for bitcoin::secp256k1::XOnlyPublicKey` impl, which upconverts via `bitcoin::XOnlyPublicKey::from_secp`. `.serialize()` on the tagged type returns `([u8; 32], Parity)`; call sites that only want the raw 32 bytes now use `.serialize().0`. Drops redundant `.into()` conversions at call sites in `descriptor/tr/spend_info.rs`, `plan.rs`, and `psbt/mod.rs` now that the return type already matches the expected tagged type. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/descriptor/tr/spend_info.rs | 3 +-- src/lib.rs | 12 +++++++----- src/miniscript/satisfy.rs | 2 +- src/util.rs | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/descriptor/tr/spend_info.rs b/src/descriptor/tr/spend_info.rs index 4f0d236dd..d77d19133 100644 --- a/src/descriptor/tr/spend_info.rs +++ b/src/descriptor/tr/spend_info.rs @@ -142,8 +142,7 @@ impl TrSpendInfo { /// Constructs a [`TrSpendInfo`] for a [`super::Tr`]. pub fn from_tr(tr: &super::Tr) -> Self { - let internal_key: UntweakedPublicKey = - bitcoin::XOnlyPublicKey::from(tr.internal_key().to_x_only_pubkey()); + let internal_key: UntweakedPublicKey = tr.internal_key().to_x_only_pubkey(); let nodes = match tr.tap_tree() { Some(tree) => Self::nodes_from_tap_tree(tree), diff --git a/src/lib.rs b/src/lib.rs index a8536c86e..5ee49af06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -230,9 +230,9 @@ pub trait ToPublicKey: MiniscriptKey { fn to_public_key(&self) -> bitcoin::PublicKey; /// Converts key to an x-only public key. - fn to_x_only_pubkey(&self) -> bitcoin::secp256k1::XOnlyPublicKey { + fn to_x_only_pubkey(&self) -> bitcoin::XOnlyPublicKey { let pk = self.to_public_key(); - bitcoin::secp256k1::XOnlyPublicKey::from(pk.to_inner()) + bitcoin::XOnlyPublicKey::from(pk.to_inner()) } /// Obtains the pubkey hash for this key (as a `MiniscriptKey`). @@ -242,7 +242,7 @@ pub trait ToPublicKey: MiniscriptKey { 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()), + SigType::Schnorr => hash160::Hash::hash(&self.to_x_only_pubkey().serialize().0), } } @@ -287,7 +287,9 @@ impl ToPublicKey for bitcoin::secp256k1::XOnlyPublicKey { .expect("Failed to construct 33 Publickey from 0x02 appended x-only key") } - fn to_x_only_pubkey(&self) -> bitcoin::secp256k1::XOnlyPublicKey { *self } + fn to_x_only_pubkey(&self) -> bitcoin::XOnlyPublicKey { + bitcoin::XOnlyPublicKey::from_secp(*self) + } fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash } fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { *hash } @@ -298,7 +300,7 @@ impl ToPublicKey for bitcoin::secp256k1::XOnlyPublicKey { impl ToPublicKey for bitcoin::XOnlyPublicKey { fn to_public_key(&self) -> bitcoin::PublicKey { bitcoin::XOnlyPublicKey::to_public_key(self) } - fn to_x_only_pubkey(&self) -> bitcoin::secp256k1::XOnlyPublicKey { *self.as_inner() } + fn to_x_only_pubkey(&self) -> bitcoin::XOnlyPublicKey { *self } fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash } fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { *hash } diff --git a/src/miniscript/satisfy.rs b/src/miniscript/satisfy.rs index 7e8ede5a0..de8ffacd3 100644 --- a/src/miniscript/satisfy.rs +++ b/src/miniscript/satisfy.rs @@ -649,7 +649,7 @@ impl Placeholder { match self { Placeholder::Pubkey(pk, size) => { if *size == 33 { - Some(pk.to_x_only_pubkey().serialize().to_vec()) + Some(pk.to_x_only_pubkey().serialize().0.to_vec()) } else { Some(pk.to_public_key().to_bytes()) } diff --git a/src/util.rs b/src/util.rs index e7eb2bba7..3a4793748 100644 --- a/src/util.rs +++ b/src/util.rs @@ -103,7 +103,7 @@ impl MsKeyBuilder for bitcoin::script::Builder { { match Ctx::sig_type() { context::SigType::Ecdsa => self.push_key(key.to_public_key()), - context::SigType::Schnorr => self.push_slice(key.to_x_only_pubkey().serialize()), + context::SigType::Schnorr => self.push_slice(key.to_x_only_pubkey().serialize().0), } } @@ -115,7 +115,7 @@ impl MsKeyBuilder for bitcoin::script::Builder { match Ctx::sig_type() { context::SigType::Ecdsa => self.push_slice(key.to_public_key().pubkey_hash()), context::SigType::Schnorr => self.push_slice( - hash160::Hash::hash(&key.to_x_only_pubkey().serialize()).to_byte_array(), + hash160::Hash::hash(&key.to_x_only_pubkey().serialize().0).to_byte_array(), ), } } From b976b51cfbc3e21421425b5d09a89880bddd9ce8 Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 16:08:37 -0600 Subject: [PATCH 17/23] bitcoin 0.33: remove dead AddrP2shError variant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `Error::AddrP2shError` variant wrapped `bitcoin::script::RedeemScriptSizeError`, which was produced by the fallible `Address::p2sh` in bitcoin 0.33. It was only ever surfaced through `Sh::address_fallible` — an internal helper whose only public caller, `Sh::address`, already panicked with `.expect()` on the error path because the redeem-script-size invariant is enforced at descriptor construction time by `check_global_consensus_validity`. Inline `address_fallible` into `address`, matching the pattern already used by the sibling `script_pubkey` method in the same file. Drop the error variant and its `From` impl. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/descriptor/sh.rs | 22 ++++++++-------------- src/lib.rs | 9 --------- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index 03aad2946..74ff24c22 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -271,25 +271,19 @@ impl Sh { /// Obtains the corresponding address for this descriptor. pub fn address(&self, network: Network) -> Address { - let addr = self.address_fallible(network); - - // Size is checked in `check_global_consensus_validity`. - assert!(addr.is_ok()); - addr.expect("only fails if size > MAX_SCRIPT_ELEMENT_SIZE") - } - - fn address_fallible(&self, network: Network) -> Result { // The redeem script for a P2SH-wrapped segwit descriptor is the wrapped // segwit output's scriptPubKey, not the inner witness/redeem script. - let address = match self.inner { - ShInner::Wsh(ref wsh) => Address::p2sh(&wsh.script_pubkey(), network)?, - ShInner::Wpkh(ref wpkh) => Address::p2sh(&wpkh.script_pubkey(), network)?, + // Size is checked in `check_global_consensus_validity`. + match self.inner { + ShInner::Wsh(ref wsh) => Address::p2sh(&wsh.script_pubkey(), network) + .expect("redeem script within size bounds"), + ShInner::Wpkh(ref wpkh) => Address::p2sh(&wpkh.script_pubkey(), network) + .expect("redeem script within size bounds"), ShInner::Ms(ref ms) => { let redeem: bitcoin::script::RedeemScriptBuf = ms.encode(); - Address::p2sh(&redeem, network)? + Address::p2sh(&redeem, network).expect("redeem script within size bounds") } - }; - Ok(address) + } } /// Obtain the underlying miniscript for this descriptor, tagged as a diff --git a/src/lib.rs b/src/lib.rs index 5ee49af06..0cdda1904 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -455,8 +455,6 @@ pub enum Error { ScriptLexer(crate::miniscript::lex::Error), /// rust-bitcoin address error AddrError(bitcoin::address::ParseError), - /// rust-bitcoin p2sh address error - AddrP2shError(bitcoin::script::RedeemScriptSizeError), /// While parsing backward, hit beginning of script UnexpectedStart, /// Got something we were not expecting @@ -529,7 +527,6 @@ impl fmt::Display for Error { 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), @@ -595,7 +592,6 @@ impl std::error::Error for Error { | 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), @@ -654,11 +650,6 @@ impl From for Error { fn from(e: bitcoin::address::ParseError) -> Error { Error::AddrError(e) } } -#[doc(hidden)] -impl From for Error { - fn from(e: bitcoin::script::RedeemScriptSizeError) -> Error { Error::AddrP2shError(e) } -} - #[doc(hidden)] #[cfg(feature = "compiler")] impl From for Error { From 021bfde39e92a9d8e9bc5d51994cfcc740e969dc Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 16:08:53 -0600 Subject: [PATCH 18/23] bitcoin 0.33: surface invariant violation in plan.rs p2wsh construction `Plan::update_psbt_input` silently dropped the `redeem_script` when `WitnessScriptBuf::to_p2wsh()` failed, producing a quietly-broken PSBT input. Since the witness script was just constructed from a descriptor whose consensus size is already validated at construction time, the failure mode is an unreachable invariant violation, not a user error. Match the established pattern (`Wsh::address` in segwitv0.rs, `Sh::script_pubkey` in sh.rs): panic with an `.expect()` naming the invariant. A silent failure here would leave the PSBT in an unrecoverable state with no diagnostic for the caller. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/plan.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/plan.rs b/src/plan.rs index d2fd3f56f..89f95986a 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -340,7 +340,7 @@ impl Plan { Placeholder::TapScript(script) => data.tap_script = Some(script.clone()), Placeholder::TapControlBlock(cb) => data.control_block = Some(cb.clone()), Placeholder::SchnorrSigPk(pk, sig_type, _) => { - let raw_pk: XOnlyPublicKey = pk.to_x_only_pubkey().into(); + let raw_pk: XOnlyPublicKey = pk.to_x_only_pubkey(); match (&data.spend_type, sig_type) { // First encountered schnorr sig, update the `TrDescriptorData` accordingly @@ -415,10 +415,11 @@ impl Plan { descriptor::ShInner::Wsh(wsh) => { let inner = wsh.inner_script(); let witness_script = WitnessScriptBuf::from_bytes(inner.to_vec()); - input.redeem_script = witness_script + let p2wsh_spk = witness_script .to_p2wsh() - .ok() - .map(|spk| RedeemScriptBuf::from_bytes(spk.into_bytes())); + .expect("witness script size within bounds"); + input.redeem_script = + Some(RedeemScriptBuf::from_bytes(p2wsh_spk.into_bytes())); input.witness_script = Some(witness_script); } descriptor::ShInner::Wpkh(..) => { From 306385a887a4a183037a72edfa5336a977edc412 Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 16:09:14 -0600 Subject: [PATCH 19/23] bitcoin 0.33: adapt compiler tests to tag-generic encode() and bitcoin 0.33 Builder Two tests in `policy::compiler` compared `ms.encode()` directly against a `script::Builder::new().push_key(...).into_script()` value. Two adjustments for bitcoin 0.33: - `push_key` now takes `PublicKey` by value, not `&PublicKey`. - `push_int` returns `Result` for minimal-encoding guarantees; the unchecked-size numeric pushes these tests produce should use `push_int_unchecked`. - `Miniscript::encode` is now generic over the script tag. Bind the expected value to an explicit `script::WitnessScriptBuf` so the tag parameter `T` can be inferred, instead of leaving it ambiguous in the `assert_eq!` argument position. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/policy/compiler.rs | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/policy/compiler.rs b/src/policy/compiler.rs index 840cc773a..c0ea6a6ed 100644 --- a/src/policy/compiler.rs +++ b/src/policy/compiler.rs @@ -1367,13 +1367,11 @@ mod tests { let policy: BPolicy = Concrete::Key(keys[0]); let ms: SegwitMiniScript = policy.compile().unwrap(); - assert_eq!( - ms.encode(), - script::Builder::new() - .push_key(&keys[0]) - .push_opcode(opcodes::all::OP_CHECKSIG) - .into_script() - ); + let expected: script::WitnessScriptBuf = script::Builder::new() + .push_key(keys[0]) + .push_opcode(opcodes::all::OP_CHECKSIG) + .into_script(); + assert_eq!(ms.encode(), expected); // CSV reordering trick let policy: BPolicy = policy_str!( @@ -1383,19 +1381,17 @@ mod tests { keys[7] ); let ms: SegwitMiniScript = policy.compile().unwrap(); - assert_eq!( - ms.encode(), - script::Builder::new() - .push_opcode(opcodes::all::OP_PUSHNUM_2) - .push_key(&keys[5]) - .push_key(&keys[6]) - .push_key(&keys[7]) - .push_opcode(opcodes::all::OP_PUSHNUM_3) - .push_opcode(opcodes::all::OP_CHECKMULTISIGVERIFY) - .push_int(10000) - .push_opcode(opcodes::all::OP_CSV) - .into_script() - ); + let expected: script::WitnessScriptBuf = script::Builder::new() + .push_opcode(opcodes::all::OP_PUSHNUM_2) + .push_key(keys[5]) + .push_key(keys[6]) + .push_key(keys[7]) + .push_opcode(opcodes::all::OP_PUSHNUM_3) + .push_opcode(opcodes::all::OP_CHECKMULTISIGVERIFY) + .push_int_unchecked(10000) + .push_opcode(opcodes::all::OP_CSV) + .into_script(); + assert_eq!(ms.encode(), expected); // Liquid policy let policy: BPolicy = Concrete::Or(vec![ From cbf8e64793f5eecbce48a524994ee80eb2dcd5b7 Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 16:22:16 -0600 Subject: [PATCH 20/23] style: cargo +nightly fmt --- examples/taptree_of_horror/taptree_of_horror.rs | 3 +-- src/interpreter/mod.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/taptree_of_horror/taptree_of_horror.rs b/examples/taptree_of_horror/taptree_of_horror.rs index 53e3d95bf..edc096a95 100644 --- a/examples/taptree_of_horror/taptree_of_horror.rs +++ b/examples/taptree_of_horror/taptree_of_horror.rs @@ -57,8 +57,7 @@ fn main() { // ====== 2. Derive Keys, Preimages, Hashes, and Timelocks for Policy and Signing ====== - let internal_xpub: miniscript::DescriptorPublicKey = - internal_desc_secret.to_public().unwrap(); + let internal_xpub: miniscript::DescriptorPublicKey = internal_desc_secret.to_public().unwrap(); // example of how defining the internal xpriv that can be used for signing. // let internal_xpriv: DescriptorXKey = match internal_desc_secret { diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index a4d44b7b7..6700ccf38 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -277,8 +277,7 @@ impl<'txin> Interpreter<'txin> { }; let msg = sighash_msg.map(|hash| hash.to_byte_array()); let success = msg.map(|msg| { - secp256k1::schnorr::verify(&schnorr_sig.signature, &msg, xpk.as_inner()) - .is_ok() + secp256k1::schnorr::verify(&schnorr_sig.signature, &msg, xpk.as_inner()).is_ok() }); success.unwrap_or(false) // unwrap_or_default checks for errors, while success would have checksig results } From 20993cf89bfd7cde2d9301bc5bd2d38ef007953e Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 16:23:09 -0600 Subject: [PATCH 21/23] ci: regenerate minimal/recent lock files for bitcoin 0.33 Both `Cargo-minimal.lock` and `Cargo-recent.lock` were pinning `bitcoin = 0.32.6`, which conflicts with the `bitcoin = 0.33.0-beta` requirement in the working `Cargo.lock` and `Cargo.toml`. Left unchanged, the `Stable - {minimal,recent}`, `Nightly - {minimal,recent}`, and `MSRV - {minimal,recent}` matrix jobs would all fail resolution. Regenerate both files from the current `Cargo.lock` so the CI matrix resolves against bitcoin 0.33-beta. Co-Authored-By: Claude Opus 4.7 (1M context) --- Cargo-minimal.lock | 411 ++++++++++++++++++++++++++++++++++----------- Cargo-recent.lock | 411 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 628 insertions(+), 194 deletions(-) diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 91a74f3b2..5f0741905 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "base58ck" @@ -23,124 +23,257 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" dependencies = [ - "bitcoin-internals", - "bitcoin_hashes", + "bitcoin-internals 0.3.0", + "bitcoin_hashes 0.14.1", +] + +[[package]] +name = "base58ck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6a87a8367e7a4248c8dfd783c37ef492bca1307cd4b21b4cfad9cfd15bf060" +dependencies = [ + "bitcoin-internals 0.5.0", + "bitcoin_hashes 0.20.0", ] [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bech32" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" +checksum = "32637268377fc7b10a8c6d51de3e7fba1ce5dd371a96e342b34e6078db558e7f" [[package]] name = "bitcoin" -version = "0.32.6" +version = "0.32.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8929a18b8e33ea6b3c09297b687baaa71fb1b97353243a3f1029fad5c59c5b" +checksum = "1e499f9fc0407f50fe98af744ab44fa67d409f76b6772e1689ec8485eb0c0f66" dependencies = [ - "base58ck", - "base64", + "base58ck 0.1.0", "bech32", - "bitcoin-internals", - "bitcoin-io", - "bitcoin-units", - "bitcoin_hashes", - "hex-conservative 0.2.1", + "bitcoin-internals 0.3.0", + "bitcoin-io 0.1.4", + "bitcoin-units 0.1.2", + "bitcoin_hashes 0.14.1", + "hex-conservative 0.2.2", "hex_lit", - "secp256k1", + "secp256k1 0.29.1", +] + +[[package]] +name = "bitcoin" +version = "0.33.0-beta" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "517161def4ca8527bfc4ba36efe5b40923024f73308a1f9c0fc5cca1bee2f536" +dependencies = [ + "base58ck 0.4.0", + "base64", + "bech32", + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "bitcoin-io 0.5.0", + "bitcoin-network-kind", + "bitcoin-primitives", + "bitcoin-units 0.3.0", + "bitcoin_hashes 0.20.0", + "bitcoinconsensus", + "hex-conservative 0.3.2", + "hex-conservative 1.0.1", + "secp256k1 0.32.0-beta.2", "serde", ] +[[package]] +name = "bitcoin-consensus-encoding" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d7ca3dc8ff835693ad73bf1596240c06f974a31eeb3f611aaedf855f1f2725" +dependencies = [ + "bitcoin-internals 0.5.0", +] + [[package]] name = "bitcoin-internals" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" + +[[package]] +name = "bitcoin-internals" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a30a22d1f112dde8e16be7b45c63645dc165cef254f835b3e1e9553e485cfa64" dependencies = [ + "hex-conservative 0.3.2", "serde", ] [[package]] name = "bitcoin-io" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e5b76b88667412087beea1882980ad843b660490bbf6cce0a6cfc999c5b989" +checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" [[package]] -name = "bitcoin-units" +name = "bitcoin-io" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6fb823712b12e5cfccdb9a2b6a62de2dc42ddb5ec489511025eebeba1c21829" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "bitcoin_hashes 0.20.0", +] + +[[package]] +name = "bitcoin-network-kind" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d437fd727271c866d6fd5e71eb2c886437d4c97f80d89246be3189b1da4e58b" +checksum = "f85911fdff634a2e65f8175a54e609172a718d385ab4da87937f166d37eef4a3" dependencies = [ - "bitcoin-internals", + "bitcoin-internals 0.5.0", + "serde", +] + +[[package]] +name = "bitcoin-primitives" +version = "0.102.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48379e4d9a4456c038d78551ccbb8a3d7f9514c799f51ae815a6e947d64c9efe" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "bitcoin-units 0.3.0", + "bitcoin_hashes 0.20.0", + "hex-conservative 0.3.2", + "hex-conservative 1.0.1", + "serde", +] + +[[package]] +name = "bitcoin-units" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" +dependencies = [ + "bitcoin-internals 0.3.0", +] + +[[package]] +name = "bitcoin-units" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fe8fafd73be14659c450deb64f90d2fd5a354fce366a01223a8319cf4d98b40" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", "serde", ] [[package]] name = "bitcoin_hashes" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" dependencies = [ - "bitcoin-io", - "hex-conservative 0.2.1", + "bitcoin-io 0.1.4", + "hex-conservative 0.2.2", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8a45c2b41c457a9a9e4670422fcbdf109afb3b22bc920b4045e8bdfd788a3d" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "hex-conservative 0.3.2", "serde", ] +[[package]] +name = "bitcoinconsensus" +version = "0.106.0+26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12cba9cce5043cdda968e07b9df6d05ec6b0b38aa27a9a40bb575cf3e521ae9" +dependencies = [ + "cc", +] + [[package]] name = "cc" -version = "1.0.28" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" +dependencies = [ + "find-msvc-tools", + "shlex", +] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "descriptor-fuzz" version = "0.0.1" dependencies = [ "honggfuzz", - "miniscript 12.3.0", + "miniscript 12.3.5", "miniscript 13.0.0", "regex", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "getrandom" -version = "0.2.14" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "wasi", + "r-efi", + "wasip2", +] + +[[package]] +name = "hex-conservative" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" +dependencies = [ + "arrayvec", ] [[package]] name = "hex-conservative" -version = "0.2.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +checksum = "830e599c2904b08f0834ee6337d8fe8f0ed4a63b5d9e7a7f49c0ffa06d08d360" dependencies = [ "arrayvec", ] [[package]] name = "hex-conservative" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee770c000993d17c185713463d5ebfbd1af9afae4c17cc295640104383bfbf0" +checksum = "366fa3443ac84474447710ec17bb00b05dfbd096137817981e86f992f21a2793" [[package]] name = "hex_lit" @@ -150,50 +283,51 @@ checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" [[package]] name = "honggfuzz" -version = "0.5.56" +version = "0.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c76b6234c13c9ea73946d1379d33186151148e0da231506b964b44f3d023505" +checksum = "4d6510a410acedd7a7683b3a45dafdc5ccf3c72d6addaa373497005964fc4e23" dependencies = [ "lazy_static", "memmap2", "rustc_version", + "semver", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" dependencies = [ "libc", ] [[package]] name = "miniscript" -version = "12.3.0" +version = "12.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd3c9608217b0d6fa9c9c8ddd875b85ab72bd4311cfc8db35e1b5a08fc11f4d" +checksum = "487906208f38448e186e3deb02f2b8ef046a9078b0de00bdb28bf4fb9b76951c" dependencies = [ "bech32", - "bitcoin", + "bitcoin 0.32.8", ] [[package]] @@ -201,53 +335,61 @@ name = "miniscript" version = "13.0.0" dependencies = [ "bech32", - "bitcoin", - "hex-conservative 1.0.0", - "secp256k1", + "bitcoin 0.33.0-beta", + "hex-conservative 1.0.1", + "secp256k1 0.32.0-beta.2", "serde", "serde_test", ] [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" -version = "0.8.5" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ - "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", "rand_core", @@ -255,18 +397,30 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom", ] [[package]] name = "regex" -version = "1.7.3" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -275,60 +429,88 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "secp256k1" -version = "0.29.0" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +dependencies = [ + "bitcoin_hashes 0.14.1", + "secp256k1-sys 0.10.1", +] + +[[package]] +name = "secp256k1" +version = "0.32.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" +checksum = "3c5fdc7d6e800869d3fd60ff857c479bf0a83ea7bf44b389e64461e844204994" dependencies = [ - "bitcoin_hashes", "rand", - "secp256k1-sys", + "secp256k1-sys 0.12.0", "serde", ] [[package]] name = "secp256k1-sys" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + +[[package]] +name = "secp256k1-sys" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d3be00697c88c00fe102af8dc316038cc2062eab8da646e7463f4c0e70ca9fd" dependencies = [ "cc", ] [[package]] name = "semver" -version = "1.0.22" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" -version = "1.0.199" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.199" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -337,18 +519,24 @@ dependencies = [ [[package]] name = "serde_test" -version = "1.0.176" +version = "1.0.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab" +checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed" dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "syn" -version = "2.0.56" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2415488199887523e74fd9a5f7be804dfd42d868ae0eca382e3917094d210e" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -357,12 +545,41 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen", +] [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wit-bindgen" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo-recent.lock b/Cargo-recent.lock index 91a74f3b2..5f0741905 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "base58ck" @@ -23,124 +23,257 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" dependencies = [ - "bitcoin-internals", - "bitcoin_hashes", + "bitcoin-internals 0.3.0", + "bitcoin_hashes 0.14.1", +] + +[[package]] +name = "base58ck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6a87a8367e7a4248c8dfd783c37ef492bca1307cd4b21b4cfad9cfd15bf060" +dependencies = [ + "bitcoin-internals 0.5.0", + "bitcoin_hashes 0.20.0", ] [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bech32" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" +checksum = "32637268377fc7b10a8c6d51de3e7fba1ce5dd371a96e342b34e6078db558e7f" [[package]] name = "bitcoin" -version = "0.32.6" +version = "0.32.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8929a18b8e33ea6b3c09297b687baaa71fb1b97353243a3f1029fad5c59c5b" +checksum = "1e499f9fc0407f50fe98af744ab44fa67d409f76b6772e1689ec8485eb0c0f66" dependencies = [ - "base58ck", - "base64", + "base58ck 0.1.0", "bech32", - "bitcoin-internals", - "bitcoin-io", - "bitcoin-units", - "bitcoin_hashes", - "hex-conservative 0.2.1", + "bitcoin-internals 0.3.0", + "bitcoin-io 0.1.4", + "bitcoin-units 0.1.2", + "bitcoin_hashes 0.14.1", + "hex-conservative 0.2.2", "hex_lit", - "secp256k1", + "secp256k1 0.29.1", +] + +[[package]] +name = "bitcoin" +version = "0.33.0-beta" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "517161def4ca8527bfc4ba36efe5b40923024f73308a1f9c0fc5cca1bee2f536" +dependencies = [ + "base58ck 0.4.0", + "base64", + "bech32", + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "bitcoin-io 0.5.0", + "bitcoin-network-kind", + "bitcoin-primitives", + "bitcoin-units 0.3.0", + "bitcoin_hashes 0.20.0", + "bitcoinconsensus", + "hex-conservative 0.3.2", + "hex-conservative 1.0.1", + "secp256k1 0.32.0-beta.2", "serde", ] +[[package]] +name = "bitcoin-consensus-encoding" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d7ca3dc8ff835693ad73bf1596240c06f974a31eeb3f611aaedf855f1f2725" +dependencies = [ + "bitcoin-internals 0.5.0", +] + [[package]] name = "bitcoin-internals" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" + +[[package]] +name = "bitcoin-internals" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a30a22d1f112dde8e16be7b45c63645dc165cef254f835b3e1e9553e485cfa64" dependencies = [ + "hex-conservative 0.3.2", "serde", ] [[package]] name = "bitcoin-io" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e5b76b88667412087beea1882980ad843b660490bbf6cce0a6cfc999c5b989" +checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" [[package]] -name = "bitcoin-units" +name = "bitcoin-io" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6fb823712b12e5cfccdb9a2b6a62de2dc42ddb5ec489511025eebeba1c21829" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "bitcoin_hashes 0.20.0", +] + +[[package]] +name = "bitcoin-network-kind" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d437fd727271c866d6fd5e71eb2c886437d4c97f80d89246be3189b1da4e58b" +checksum = "f85911fdff634a2e65f8175a54e609172a718d385ab4da87937f166d37eef4a3" dependencies = [ - "bitcoin-internals", + "bitcoin-internals 0.5.0", + "serde", +] + +[[package]] +name = "bitcoin-primitives" +version = "0.102.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48379e4d9a4456c038d78551ccbb8a3d7f9514c799f51ae815a6e947d64c9efe" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "bitcoin-units 0.3.0", + "bitcoin_hashes 0.20.0", + "hex-conservative 0.3.2", + "hex-conservative 1.0.1", + "serde", +] + +[[package]] +name = "bitcoin-units" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" +dependencies = [ + "bitcoin-internals 0.3.0", +] + +[[package]] +name = "bitcoin-units" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fe8fafd73be14659c450deb64f90d2fd5a354fce366a01223a8319cf4d98b40" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", "serde", ] [[package]] name = "bitcoin_hashes" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" dependencies = [ - "bitcoin-io", - "hex-conservative 0.2.1", + "bitcoin-io 0.1.4", + "hex-conservative 0.2.2", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8a45c2b41c457a9a9e4670422fcbdf109afb3b22bc920b4045e8bdfd788a3d" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "hex-conservative 0.3.2", "serde", ] +[[package]] +name = "bitcoinconsensus" +version = "0.106.0+26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12cba9cce5043cdda968e07b9df6d05ec6b0b38aa27a9a40bb575cf3e521ae9" +dependencies = [ + "cc", +] + [[package]] name = "cc" -version = "1.0.28" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" +dependencies = [ + "find-msvc-tools", + "shlex", +] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "descriptor-fuzz" version = "0.0.1" dependencies = [ "honggfuzz", - "miniscript 12.3.0", + "miniscript 12.3.5", "miniscript 13.0.0", "regex", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "getrandom" -version = "0.2.14" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "wasi", + "r-efi", + "wasip2", +] + +[[package]] +name = "hex-conservative" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" +dependencies = [ + "arrayvec", ] [[package]] name = "hex-conservative" -version = "0.2.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +checksum = "830e599c2904b08f0834ee6337d8fe8f0ed4a63b5d9e7a7f49c0ffa06d08d360" dependencies = [ "arrayvec", ] [[package]] name = "hex-conservative" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee770c000993d17c185713463d5ebfbd1af9afae4c17cc295640104383bfbf0" +checksum = "366fa3443ac84474447710ec17bb00b05dfbd096137817981e86f992f21a2793" [[package]] name = "hex_lit" @@ -150,50 +283,51 @@ checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" [[package]] name = "honggfuzz" -version = "0.5.56" +version = "0.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c76b6234c13c9ea73946d1379d33186151148e0da231506b964b44f3d023505" +checksum = "4d6510a410acedd7a7683b3a45dafdc5ccf3c72d6addaa373497005964fc4e23" dependencies = [ "lazy_static", "memmap2", "rustc_version", + "semver", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" dependencies = [ "libc", ] [[package]] name = "miniscript" -version = "12.3.0" +version = "12.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd3c9608217b0d6fa9c9c8ddd875b85ab72bd4311cfc8db35e1b5a08fc11f4d" +checksum = "487906208f38448e186e3deb02f2b8ef046a9078b0de00bdb28bf4fb9b76951c" dependencies = [ "bech32", - "bitcoin", + "bitcoin 0.32.8", ] [[package]] @@ -201,53 +335,61 @@ name = "miniscript" version = "13.0.0" dependencies = [ "bech32", - "bitcoin", - "hex-conservative 1.0.0", - "secp256k1", + "bitcoin 0.33.0-beta", + "hex-conservative 1.0.1", + "secp256k1 0.32.0-beta.2", "serde", "serde_test", ] [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" -version = "0.8.5" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ - "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", "rand_core", @@ -255,18 +397,30 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom", ] [[package]] name = "regex" -version = "1.7.3" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -275,60 +429,88 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "secp256k1" -version = "0.29.0" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +dependencies = [ + "bitcoin_hashes 0.14.1", + "secp256k1-sys 0.10.1", +] + +[[package]] +name = "secp256k1" +version = "0.32.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" +checksum = "3c5fdc7d6e800869d3fd60ff857c479bf0a83ea7bf44b389e64461e844204994" dependencies = [ - "bitcoin_hashes", "rand", - "secp256k1-sys", + "secp256k1-sys 0.12.0", "serde", ] [[package]] name = "secp256k1-sys" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + +[[package]] +name = "secp256k1-sys" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d3be00697c88c00fe102af8dc316038cc2062eab8da646e7463f4c0e70ca9fd" dependencies = [ "cc", ] [[package]] name = "semver" -version = "1.0.22" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" -version = "1.0.199" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.199" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -337,18 +519,24 @@ dependencies = [ [[package]] name = "serde_test" -version = "1.0.176" +version = "1.0.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab" +checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed" dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "syn" -version = "2.0.56" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2415488199887523e74fd9a5f7be804dfd42d868ae0eca382e3917094d210e" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -357,12 +545,41 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen", +] [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wit-bindgen" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] From fc4f4ce70b676447268094f807e3b7d6ac2ffdfc Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 16:44:36 -0600 Subject: [PATCH 22/23] bitcoin 0.33: fix broken intra-doc link in taptree.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `bitcoin::Script` no longer exists in bitcoin 0.33 — it was replaced with role-tagged script types. Update the intra-doc link on `TapTreeIterItem::miniscript` to point at `bitcoin::script::TapScriptBuf`, which is what `Miniscript::encode` actually produces for a tap leaf. Caught by `cargo rbmt docsrs` (the docs.rs CI job) which runs rustdoc with `-D rustdoc::broken-intra-doc-links`. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/descriptor/tr/taptree.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/descriptor/tr/taptree.rs b/src/descriptor/tr/taptree.rs index d133c3ae9..16d526b01 100644 --- a/src/descriptor/tr/taptree.rs +++ b/src/descriptor/tr/taptree.rs @@ -188,8 +188,8 @@ pub struct TapTreeIterItem<'tr, Pk: MiniscriptKey> { impl<'tr, Pk: MiniscriptKey> TapTreeIterItem<'tr, Pk> { /// The Tapscript in the leaf. /// - /// To obtain a [`bitcoin::Script`] from this node, call [`Miniscript::encode`] - /// on the returned value. + /// To obtain a [`bitcoin::script::TapScriptBuf`] from this node, call + /// [`Miniscript::encode`] on the returned value. #[inline] pub fn miniscript(&self) -> &'tr Arc> { self.node } From a6d1e5a056d7a9096c1ed30615cc0e885761bf36 Mon Sep 17 00:00:00 2001 From: 42pupusas Date: Mon, 20 Apr 2026 17:25:53 -0600 Subject: [PATCH 23/23] bitcoin 0.33: migrate cfg(bench) benchmarks to secp256k1 0.32 API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `src/benchmarks.rs` is gated on `#[cfg(bench)]` so it wasn't caught by the main migration passes. The `keygen` helper used three APIs that changed in secp256k1 0.32 and bitcoin 0.33: - `SecretKey::from_slice(&bytes)` → `SecretKey::from_secret_bytes(bytes)` (takes the array by value now). - `SecretKey::public_key(&secp)` no longer takes a context, drop it. - `bitcoin::PublicKey { inner: pk, compressed: true }` → the fields are no longer public; use `bitcoin::PublicKey::new(pk)` which constructs a compressed key. Caught by `cargo rbmt bench` (the Bench CI job). Benchmarks now build and all 93 measured benches run clean. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/benchmarks.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/benchmarks.rs b/src/benchmarks.rs index 52823186c..6079c637f 100644 --- a/src/benchmarks.rs +++ b/src/benchmarks.rs @@ -9,7 +9,7 @@ use core::str::FromStr; -use bitcoin::secp256k1::{Secp256k1, SecretKey}; +use bitcoin::secp256k1::SecretKey; use test::{black_box, Bencher}; use crate::descriptor::{SinglePub, SinglePubKey}; @@ -19,15 +19,13 @@ use crate::{Descriptor, DescriptorPublicKey}; type Desc = Descriptor; fn keygen(n: u32) -> DescriptorPublicKey { - let secp = Secp256k1::new(); - let mut sk = [0; 32]; sk[31] = n as u8; sk[30] = (n >> 8) as u8; sk[29] = (n >> 16) as u8; sk[28] = (n >> 24) as u8; - let sk = SecretKey::from_slice(&sk).unwrap(); - let pk = bitcoin::PublicKey { inner: sk.public_key(&secp), compressed: true }; + let sk = SecretKey::from_secret_bytes(sk).unwrap(); + let pk = bitcoin::PublicKey::new(sk.public_key()); DescriptorPublicKey::Single(SinglePub { origin: None, key: SinglePubKey::FullKey(pk) }) }