primitives: split TapScript and TapScriptBuf from script
What changed, and why it matters
This commit is a routine internal code reorganization in the rust-bitcoin library. It introduces separate type names, TapScript and TapScriptBuf, for scripts used in Taproot spending paths, replacing the more generic Script/ScriptBuf names in those places. There is no change to how Bitcoin data is parsed, validated, or serialized, and no security fix or vulnerability is described.
No security action required; treat as normal API refactoring. Review downstream code for type-name compatibility if upgrading.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change splits TapScript/TapScriptBuf out of the generic Script/ScriptBuf types as part of a larger refactoring (the commit message notes the next step deletes the old ScriptBuf/Script types). It updates re-exports, extension trait names (ScriptExt -> TapScriptExt), function signatures, and tests to use the new TapScript types. The underlying data representation remains the same (GenericScript
Changed components
bitcoin/src/blockdata/script/borrowed.rsbitcoin/src/blockdata/script/mod.rsbitcoin/src/blockdata/witness.rsbitcoin/src/crypto/sighash.rsbitcoin/src/taproot/mod.rsbitcoin/src/psbt/map/input.rsbitcoin/src/psbt/serialize.rsprimitives/src/script/mod.rsprimitives/src/script/tag.rsInspect captured patch +116 / −87
diff --git a/bitcoin/examples/taproot-psbt.rs b/bitcoin/examples/taproot-psbt.rs
index 21d3c056..c95bf16d 100644
--- a/bitcoin/examples/taproot-psbt.rs
+++ b/bitcoin/examples/taproot-psbt.rs
@@ -87,8 +87,8 @@ use bitcoin::secp256k1::Secp256k1;
use bitcoin::sighash::{self, SighashCache, TapSighash, TapSighashType};
use bitcoin::taproot::{self, LeafVersion, TapLeafHash, TaprootBuilder, TaprootSpendInfo};
use bitcoin::{
- absolute, script, transaction, Address, Amount, Network, OutPoint, ScriptBuf, ScriptPubKeyBuf,
- ScriptSigBuf, Transaction, TxIn, TxOut, Witness,
+ absolute, script, transaction, Address, Amount, Network, OutPoint, ScriptPubKeyBuf,
+ ScriptSigBuf, TapScriptBuf, Transaction, TxIn, TxOut, Witness,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -369,7 +369,7 @@ impl BenefactorWallet {
fn time_lock_script(
locktime: absolute::LockTime,
beneficiary_key: XOnlyPublicKey,
- ) -> ScriptBuf {
+ ) -> TapScriptBuf {
script::Builder::new()
.push_lock_time(locktime)
.push_opcode(OP_CLTV)
diff --git a/bitcoin/src/blockdata/script/borrowed.rs b/bitcoin/src/blockdata/script/borrowed.rs
index d69d09bd..90874cd6 100644
--- a/bitcoin/src/blockdata/script/borrowed.rs
+++ b/bitcoin/src/blockdata/script/borrowed.rs
@@ -10,7 +10,7 @@ use secp256k1::{Secp256k1, Verification};
use super::witness_version::WitnessVersion;
use super::{
Builder, GenericScript, Instruction, InstructionIndices, Instructions, PushBytes, RedeemScript,
- RedeemScriptSizeError, Script, ScriptHash, ScriptHashableTag, ScriptPubKey, ScriptSig,
+ RedeemScriptSizeError, ScriptHash, ScriptHashableTag, ScriptPubKey, ScriptSig, TapScript,
WScriptHash, WitnessScript, WitnessScriptSizeError,
};
use crate::consensus::{self, Encodable};
@@ -270,7 +270,7 @@ internal_macros::define_extension_trait! {
crate::internal_macros::define_extension_trait! {
/// Extension functionality for the [`Script`] type.
- pub trait ScriptExt impl for Script {
+ pub trait TapScriptExt impl for TapScript {
/// Computes leaf hash of tapscript.
#[inline]
fn tapscript_leaf_hash(&self) -> TapLeafHash {
diff --git a/bitcoin/src/blockdata/script/mod.rs b/bitcoin/src/blockdata/script/mod.rs
index 18895d7e..9ffc15a4 100644
--- a/bitcoin/src/blockdata/script/mod.rs
+++ b/bitcoin/src/blockdata/script/mod.rs
@@ -74,7 +74,7 @@ use crate::OutPoint;
#[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)]
pub use self::{
- borrowed::{GenericScriptExt, ScriptExt, ScriptPubKeyExt, WitnessScriptExt, ScriptSigExt},
+ borrowed::{GenericScriptExt, TapScriptExt, ScriptPubKeyExt, WitnessScriptExt, ScriptSigExt},
builder::Builder,
instruction::{Instruction, Instructions, InstructionIndices},
owned::{GenericScriptBufExt, ScriptPubKeyBufExt},
@@ -84,8 +84,9 @@ pub use self::{
pub use primitives::script::{
GenericScript, GenericScriptBuf, RedeemScript, RedeemScriptBuf, RedeemScriptSizeError,
RedeemScriptTag, Script, ScriptBuf, ScriptHash, ScriptHashableTag, ScriptPubKey,
- ScriptPubKeyBuf, ScriptPubKeyTag, ScriptSig, ScriptSigBuf, ScriptSigTag, Tag, WScriptHash,
- Whatever, WitnessScript, WitnessScriptBuf, WitnessScriptSizeError, WitnessScriptTag,
+ ScriptPubKeyBuf, ScriptPubKeyTag, ScriptSig, ScriptSigBuf, ScriptSigTag, Tag, TapScript,
+ TapScriptBuf, WScriptHash, Whatever, WitnessScript, WitnessScriptBuf, WitnessScriptSizeError,
+ WitnessScriptTag,
};
pub(crate) use self::borrowed::GenericScriptExtPriv;
diff --git a/bitcoin/src/blockdata/script/tests.rs b/bitcoin/src/blockdata/script/tests.rs
index 5a7b382c..7e9efc8b 100644
--- a/bitcoin/src/blockdata/script/tests.rs
+++ b/bitcoin/src/blockdata/script/tests.rs
@@ -5,7 +5,7 @@ use hex_lit::hex;
use super::*;
use crate::consensus::encode::{deserialize, serialize};
use crate::crypto::key::{PublicKey, XOnlyPublicKey};
-use crate::script::borrowed::{ScriptExt as _, ScriptPubKeyExt as _, ScriptPubKeyExtPriv as _};
+use crate::script::borrowed::{ScriptPubKeyExt as _, ScriptPubKeyExtPriv as _, TapScriptExt as _};
use crate::script::witness_program::WitnessProgram;
use crate::script::witness_version::WitnessVersion;
use crate::{opcodes, Amount, FeeRate};
@@ -408,7 +408,7 @@ fn script_hashes() {
"3e1525eb183ad4f9b3c5fa3175bdca2a52e947b135bbb90383bf9f6408e2c324"
);
assert_eq!(
- ScriptBuf::from_hex_no_length_prefix(
+ TapScriptBuf::from_hex_no_length_prefix(
"20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac"
)
.unwrap()
diff --git a/bitcoin/src/blockdata/witness.rs b/bitcoin/src/blockdata/witness.rs
index cb5d4dcf..300be3c5 100644
--- a/bitcoin/src/blockdata/witness.rs
+++ b/bitcoin/src/blockdata/witness.rs
@@ -12,10 +12,8 @@ use crate::consensus::{Decodable, Encodable};
use crate::crypto::ecdsa;
use crate::crypto::key::SerializedXOnlyPublicKey;
use crate::prelude::Vec;
-#[cfg(doc)]
-use crate::script::ScriptExt as _;
use crate::taproot::{self, ControlBlock, LeafScript, TaprootMerkleBranch, TAPROOT_ANNEX_PREFIX};
-use crate::{internal_macros, Script, WitnessScript};
+use crate::{internal_macros, TapScript, WitnessScript};
type BorrowedControlBlock<'a> = ControlBlock<&'a TaprootMerkleBranch, &'a SerializedXOnlyPublicKey>;
@@ -136,7 +134,7 @@ internal_macros::define_extension_trait! {
}
/// Finishes constructing the P2TR script spend witness by pushing the required items.
- fn push_p2tr_script_spend(&mut self, script: &Script, control_block: &ControlBlock<impl AsRef<TaprootMerkleBranch>>, annex: Option<&[u8]>) {
+ fn push_p2tr_script_spend(&mut self, script: &TapScript, control_block: &ControlBlock<impl AsRef<TaprootMerkleBranch>>, annex: Option<&[u8]>) {
self.push(script.as_bytes());
self.push(&*control_block.encode_to_arrayvec());
if let Some(annex) = annex {
@@ -157,7 +155,8 @@ internal_macros::define_extension_trait! {
/// assumes a leaf version may be subtly broken once a new Tapscript version
/// is deployed.
#[deprecated(since = "TBD", note = "use taproot_leaf_script instead")]
- fn tapscript(&self) -> Option<&Script> {
+ /// See [`WitnessScript::is_p2tr`] to check whether this is actually a Taproot witness.
+ fn tapscript(&self) -> Option<&TapScript> {
match P2TrSpend::from_witness(self) {
Some(P2TrSpend::Script { leaf_script, .. }) => Some(leaf_script),
_ => None,
@@ -175,7 +174,7 @@ internal_macros::define_extension_trait! {
/// to have a Taproot-shaped witness).
/// See [BIP-0341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki),
/// in particular footnote 7, for more information.
- fn taproot_leaf_script(&self) -> Option<LeafScript<&Script>> {
+ fn taproot_leaf_script(&self) -> Option<LeafScript<&TapScript>> {
match P2TrSpend::from_witness(self) {
Some(P2TrSpend::Script { leaf_script, control_block, .. }) => {
Some(LeafScript { version: control_block.leaf_version, script: leaf_script, })
@@ -232,7 +231,7 @@ enum P2TrSpend<'a> {
annex: Option<&'a [u8]>,
},
Script {
- leaf_script: &'a Script,
+ leaf_script: &'a TapScript,
control_block: BorrowedControlBlock<'a>,
annex: Option<&'a [u8]>,
},
@@ -275,7 +274,7 @@ impl<'a> P2TrSpend<'a> {
let control_block = witness.get_back(1).expect("len > 1");
let control_block = BorrowedControlBlock::decode_borrowed(control_block).ok()?;
let spend = P2TrSpend::Script {
- leaf_script: Script::from_bytes(witness.get_back(2).expect("len > 2")),
+ leaf_script: TapScript::from_bytes(witness.get_back(2).expect("len > 2")),
control_block,
annex: witness.last(),
};
@@ -285,7 +284,7 @@ impl<'a> P2TrSpend<'a> {
let control_block = witness.last().expect("len > 0");
let control_block = BorrowedControlBlock::decode_borrowed(control_block).ok()?;
let spend = P2TrSpend::Script {
- leaf_script: Script::from_bytes(witness.get_back(1).expect("len > 1")),
+ leaf_script: TapScript::from_bytes(witness.get_back(1).expect("len > 1")),
control_block,
annex: None,
};
@@ -395,8 +394,8 @@ mod test {
let witness_annex = Witness::from([tapscript.as_slice(), &control_block, &annex]);
// With or without annex, the tapscript should be returned.
- assert_eq!(witness.tapscript(), Some(Script::from_bytes(&tapscript[..])));
- assert_eq!(witness_annex.tapscript(), Some(Script::from_bytes(&tapscript[..])));
+ assert_eq!(witness.tapscript(), Some(TapScript::from_bytes(&tapscript[..])));
+ assert_eq!(witness_annex.tapscript(), Some(TapScript::from_bytes(&tapscript[..])));
}
#[test]
@@ -410,8 +409,10 @@ mod test {
let witness = Witness::from([tapscript.as_slice(), &control_block]);
let witness_annex = Witness::from([tapscript.as_slice(), &control_block, &annex]);
- let expected_leaf_script =
- LeafScript { version: LeafVersion::TapScript, script: Script::from_bytes(&tapscript) };
+ let expected_leaf_script = LeafScript {
+ version: LeafVersion::TapScript,
+ script: TapScript::from_bytes(&tapscript),
+ };
// With or without annex, the tapscript should be returned.
assert_eq!(witness.taproot_leaf_script().unwrap(), expected_leaf_script);
diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs
index 088fe085..feb2a66a 100644
--- a/bitcoin/src/crypto/sighash.rs
+++ b/bitcoin/src/crypto/sighash.rs
@@ -27,7 +27,7 @@ use crate::taproot::{LeafVersion, TapLeafHash, TapLeafTag, TAPROOT_ANNEX_PREFIX}
use crate::transaction::TransactionExt as _;
use crate::witness::Witness;
use crate::{
- transaction, Amount, Script, ScriptPubKey, Sequence, Transaction, TxOut, WitnessScript,
+ transaction, Amount, ScriptPubKey, Sequence, TapScript, Transaction, TxOut, WitnessScript,
};
/// Used for signature hash for invalid use of SIGHASH_SINGLE.
@@ -160,7 +160,7 @@ const KEY_VERSION_0: u8 = 0u8;
/// This can be hashed into a [`TapLeafHash`].
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct ScriptPath<'s> {
- script: &'s Script,
+ script: &'s TapScript,
leaf_version: LeafVersion,
}
@@ -331,11 +331,13 @@ impl std::error::Error for PrevoutsIndexError {
impl<'s> ScriptPath<'s> {
/// Constructs a new `ScriptPath` structure.
- pub fn new(script: &'s Script, leaf_version: LeafVersion) -> Self {
+ pub fn new(script: &'s TapScript, leaf_version: LeafVersion) -> Self {
ScriptPath { script, leaf_version }
}
/// Constructs a new `ScriptPath` structure using default leaf version value.
- pub fn with_defaults(script: &'s Script) -> Self { Self::new(script, LeafVersion::TapScript) }
+ pub fn with_defaults(script: &'s TapScript) -> Self {
+ Self::new(script, LeafVersion::TapScript)
+ }
/// Computes the leaf hash for this `ScriptPath`.
pub fn leaf_hash(&self) -> TapLeafHash {
let mut enc = sha256t::Hash::<TapLeafTag>::engine();
@@ -1540,7 +1542,7 @@ mod tests {
use crate::consensus::deserialize;
use crate::locktime::absolute;
use crate::script::{
- GenericScriptBufExt as _, ScriptBuf, ScriptPubKey, ScriptPubKeyBuf, WitnessScriptBuf,
+ GenericScriptBufExt as _, ScriptPubKey, ScriptPubKeyBuf, TapScriptBuf, WitnessScriptBuf,
};
use crate::TxIn;
@@ -1835,7 +1837,7 @@ mod tests {
let leaf_hash = match (script_hex, script_leaf_hash) {
(Some(script_hex), _) => {
- let script_inner = ScriptBuf::from_hex_no_length_prefix(script_hex).unwrap();
+ let script_inner = TapScriptBuf::from_hex_no_length_prefix(script_hex).unwrap();
Some(ScriptPath::with_defaults(&script_inner).leaf_hash())
}
(_, Some(script_leaf_hash)) => Some(script_leaf_hash.parse::<TapLeafHash>().unwrap()),
diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs
index 66755b2b..b938f5ef 100644
--- a/bitcoin/src/lib.rs
+++ b/bitcoin/src/lib.rs
@@ -108,13 +108,13 @@ pub mod ext {
//! use bitcoin::ext::*;
//!
//! // If, for some reason, you want the name to be in scope access it via the module. E.g.
- //! use bitcoin::script::ScriptExt;
+ //! use bitcoin::script::ScriptSigExt;
//! ```
#[rustfmt::skip] // Use terse custom grouping.
pub use crate::{
block::{BlockUncheckedExt as _, BlockCheckedExt as _, HeaderExt as _},
pow::CompactTargetExt as _,
- script::{GenericScriptExt as _, GenericScriptBufExt as _, ScriptExt as _, ScriptPubKeyExt as _, ScriptPubKeyBufExt as _, WitnessScriptExt as _, ScriptSigExt as _},
+ script::{GenericScriptExt as _, GenericScriptBufExt as _, TapScriptExt as _, ScriptPubKeyExt as _, ScriptPubKeyBufExt as _, WitnessScriptExt as _, ScriptSigExt as _},
transaction::{TxidExt as _, WtxidExt as _, OutPointExt as _, TxInExt as _, TxOutExt as _, TransactionExt as _},
witness::WitnessExt as _,
};
@@ -154,7 +154,7 @@ pub use primitives::{
pow::CompactTarget, // No `pow` module outside of `primitives`.
script::{
RedeemScript, RedeemScriptBuf, Script, ScriptBuf, ScriptPubKey, ScriptPubKeyBuf, ScriptSig,
- ScriptSigBuf, WitnessScript, WitnessScriptBuf,
+ ScriptSigBuf, TapScript, TapScriptBuf, WitnessScript, WitnessScriptBuf,
},
sequence::{self, Sequence}, // No `sequence` module outside of `primitives`.
transaction::{OutPoint, Transaction, TxIn, TxOut, Txid, Version as TransactionVersion, Wtxid},
diff --git a/bitcoin/src/psbt/map/input.rs b/bitcoin/src/psbt/map/input.rs
index 7675bd78..6974da8e 100644
--- a/bitcoin/src/psbt/map/input.rs
+++ b/bitcoin/src/psbt/map/input.rs
@@ -12,7 +12,7 @@ use crate::prelude::{btree_map, BTreeMap, Borrow, Box, ToOwned, Vec};
use crate::psbt::map::Map;
use crate::psbt::serialize::Deserialize;
use crate::psbt::{error, raw, Error};
-use crate::script::{RedeemScriptBuf, ScriptBuf, ScriptSigBuf, WitnessScriptBuf};
+use crate::script::{RedeemScriptBuf, ScriptSigBuf, TapScriptBuf, WitnessScriptBuf};
use crate::sighash::{
EcdsaSighashType, InvalidSighashTypeError, NonStandardSighashTypeError, SighashTypeParseError,
TapSighashType,
@@ -108,7 +108,7 @@ pub struct Input {
/// Map of `<xonlypubkey>|<leafhash>` with signature.
pub tap_script_sigs: BTreeMap<(XOnlyPublicKey, TapLeafHash), taproot::Signature>,
/// Map of Control blocks to Script version pair.
- pub tap_scripts: BTreeMap<ControlBlock, (ScriptBuf, LeafVersion)>,
+ pub tap_scripts: BTreeMap<ControlBlock, (TapScriptBuf, LeafVersion)>,
/// Map of tap root x only keys to origin info and leaf hashes contained in it.
pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
/// Taproot Internal key.
@@ -338,7 +338,7 @@ impl Input {
}
PSBT_IN_TAP_LEAF_SCRIPT => {
impl_psbt_insert_pair! {
- self.tap_scripts <= <raw_key: ControlBlock>|< raw_value: (ScriptBuf, LeafVersion)>
+ self.tap_scripts <= <raw_key: ControlBlock>|< raw_value: (TapScriptBuf, LeafVersion)>
}
}
PSBT_IN_TAP_BIP32_DERIVATION => {
diff --git a/bitcoin/src/psbt/serialize.rs b/bitcoin/src/psbt/serialize.rs
index 1d3141b0..6804cc26 100644
--- a/bitcoin/src/psbt/serialize.rs
+++ b/bitcoin/src/psbt/serialize.rs
@@ -437,7 +437,7 @@ fn key_source_len(key_source: &KeySource) -> usize { 4 + 4 * (key_source.1).as_r
mod tests {
use super::*;
use crate::script::GenericScriptBufExt as _;
- use crate::ScriptBuf;
+ use crate::TapScriptBuf;
// Composes tree matching a given depth map, filled with dumb script leafs,
// each of which consists of a single push-int op code, with int value
@@ -449,7 +449,7 @@ mod tests {
let mut val = opcode;
let mut builder = TaprootBuilder::new();
for depth in depth_map {
- let script = ScriptBuf::from_hex_no_length_prefix(&format!("{:02x}", val)).unwrap();
+ let script = TapScriptBuf::from_hex_no_length_prefix(&format!("{:02x}", val)).unwrap();
builder = builder.add_leaf(*depth, script).unwrap();
let (new_val, _) = val.overflowing_add(1);
val = new_val;
@@ -464,7 +464,7 @@ mod tests {
builder = builder
.add_leaf_with_ver(
3,
- ScriptBuf::from_hex_no_length_prefix("b9").unwrap(),
+ TapScriptBuf::from_hex_no_length_prefix("b9").unwrap(),
LeafVersion::from_consensus(0xC2).unwrap(),
)
.unwrap();
@@ -478,7 +478,7 @@ mod tests {
builder = builder
.add_leaf_with_ver(
3,
- ScriptBuf::from_hex_no_length_prefix("b9").unwrap(),
+ TapScriptBuf::from_hex_no_length_prefix("b9").unwrap(),
LeafVersion::from_consensus(0xC2).unwrap(),
)
.unwrap();
diff --git a/bitcoin/src/taproot/mod.rs b/bitcoin/src/taproot/mod.rs
index 57fa88cd..18b37a9e 100644
--- a/bitcoin/src/taproot/mod.rs
+++ b/bitcoin/src/taproot/mod.rs
@@ -27,7 +27,7 @@ use crate::crypto::key::{
};
use crate::key::ParseXOnlyPublicKeyError;
use crate::prelude::{BTreeMap, BTreeSet, BinaryHeap, Vec};
-use crate::{Script, ScriptBuf};
+use crate::{TapScript, TapScriptBuf};
// Re-export these so downstream only has to use one `taproot` module.
#[rustfmt::skip]
@@ -123,7 +123,7 @@ impl TapTweakHash {
impl TapLeafHash {
/// Computes the leaf hash from components.
- pub fn from_script(script: &Script, ver: LeafVersion) -> TapLeafHash {
+ pub fn from_script(script: &TapScript, ver: LeafVersion) -> TapLeafHash {
let mut eng = sha256t::Hash::<TapLeafTag>::engine();
ver.to_consensus().consensus_encode(&mut eng).expect("engines don't error");
script.consensus_encode(&mut eng).expect("engines don't error");
@@ -154,7 +154,7 @@ impl TapNodeHash {
pub fn assume_hidden(hash: [u8; 32]) -> TapNodeHash { TapNodeHash::from_byte_array(hash) }
/// Computes the [`TapNodeHash`] from a script and a leaf version.
- pub fn from_script(script: &Script, ver: LeafVersion) -> TapNodeHash {
+ pub fn from_script(script: &TapScript, ver: LeafVersion) -> TapNodeHash {
TapNodeHash::from(TapLeafHash::from_script(script, ver))
}
}
@@ -201,12 +201,12 @@ pub const TAPROOT_CONTROL_MAX_SIZE: usize =
pub struct LeafScript<S> {
/// The version of the script.
pub version: LeafVersion,
- /// The script, usually `ScriptBuf` or `&Script`.
+ /// The script, usually `TapScriptBuf` or `&TapScript`.
pub script: S,
}
// type alias for versioned tap script corresponding Merkle proof
-type ScriptMerkleProofMap = BTreeMap<(ScriptBuf, LeafVersion), BTreeSet<TaprootMerkleBranchBuf>>;
+type ScriptMerkleProofMap = BTreeMap<(TapScriptBuf, LeafVersion), BTreeSet<TaprootMerkleBranchBuf>>;
/// Represents Taproot spending information.
///
@@ -255,7 +255,7 @@ impl TaprootSpendInfo {
script_weights: I,
) -> Result<Self, TaprootBuilderError>
where
- I: IntoIterator<Item = (u32, ScriptBuf)>,
+ I: IntoIterator<Item = (u32, TapScriptBuf)>,
C: secp256k1::Verification,
K: Into<UntweakedPublicKey>,
{
@@ -354,13 +354,13 @@ impl TaprootSpendInfo {
///
/// - If there are multiple control blocks possible, returns the shortest one.
/// - If the script is not contained in the [`TaprootSpendInfo`], returns `None`.
- pub fn control_block(&self, script_ver: &(ScriptBuf, LeafVersion)) -> Option<ControlBlock> {
+ pub fn control_block(&self, script_ver: &(TapScriptBuf, LeafVersion)) -> Option<ControlBlock> {
let merkle_branch_set = self.script_map.get(script_ver)?;
// Choose the smallest one amongst the multiple script maps
let smallest = merkle_branch_set
.iter()
.min_by(|x, y| x.len().cmp(&y.len()))
- .expect("Invariant: ScriptBuf map key must contain non-empty set value");
+ .expect("Invariant: TapScriptBuf map key must contain non-empty set value");
Some(ControlBlock {
internal_key: self.internal_key,
output_key_parity: self.output_key_parity,
@@ -437,7 +437,7 @@ impl TaprootBuilder {
/// The weights represent the probability of each branch being taken. If probabilities/weights
/// for each condition are known, constructing the tree as a Huffman tree is the optimal way to
/// minimize average case satisfaction cost. This function takes as input an iterator of
- /// `tuple(u32, ScriptBuf)` where `u32` represents the satisfaction weights of the branch. For
+ /// `tuple(u32, TapScriptBuf)` where `u32` represents the satisfaction weights of the branch. For
/// example, [(3, S1), (2, S2), (5, S3)] would construct a [`TapTree`] that has optimal
/// satisfaction weight when probability for S1 is 30%, S2 is 20% and S3 is 50%.
///
@@ -454,7 +454,7 @@ impl TaprootBuilder {
/// [`TapTree`]: crate::taproot::TapTree
pub fn with_huffman_tree<I>(script_weights: I) -> Result<Self, TaprootBuilderError>
where
- I: IntoIterator<Item = (u32, ScriptBuf)>,
+ I: IntoIterator<Item = (u32, TapScriptBuf)>,
{
let mut node_weights = BinaryHeap::<(Reverse<u32>, NodeInfo)>::new();
for (p, leaf) in script_weights {
@@ -492,7 +492,7 @@ impl TaprootBuilder {
pub fn add_leaf_with_ver(
self,
depth: u8,
- script: ScriptBuf,
+ script: TapScriptBuf,
ver: LeafVersion,
) -> Result<Self, TaprootBuilderError> {
let leaf = NodeInfo::new_leaf_with_ver(script, ver);
@@ -508,7 +508,7 @@ impl TaprootBuilder {
/// # Errors
///
/// Errors if the leaves are not provided in DFS walk order.
- pub fn add_leaf(self, depth: u8, script: ScriptBuf) -> Result<Self, TaprootBuilderError> {
+ pub fn add_leaf(self, depth: u8, script: TapScriptBuf) -> Result<Self, TaprootBuilderError> {
self.add_leaf_with_ver(depth, script, LeafVersion::TapScript)
}
@@ -923,8 +923,8 @@ impl NodeInfo {
Self { hash, leaves: vec![], has_hidden_nodes: true }
}
- /// Constructs a new leaf [`NodeInfo`] with given [`ScriptBuf`] and [`LeafVersion`].
- pub fn new_leaf_with_ver(script: ScriptBuf, ver: LeafVersion) -> Self {
+ /// Constructs a new leaf [`NodeInfo`] with given [`TapScriptBuf`] and [`LeafVersion`].
+ pub fn new_leaf_with_ver(script: TapScriptBuf, ver: LeafVersion) -> Self {
Self {
hash: TapNodeHash::from_script(&script, ver),
leaves: vec![LeafNode::new_script(script, ver)],
@@ -1044,7 +1044,7 @@ impl<'de> serde::Deserialize<'de> for NodeInfo {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TapLeaf {
/// A known script
- Script(ScriptBuf, LeafVersion),
+ Script(TapScriptBuf, LeafVersion),
/// Hidden Node with the given leaf hash
Hidden(TapNodeHash),
}
@@ -1060,7 +1060,7 @@ impl TapLeaf {
}
/// Obtains a reference to script and version if the leaf is known.
- pub fn as_script(&self) -> Option<(&Script, LeafVersion)> {
+ pub fn as_script(&self) -> Option<(&TapScript, LeafVersion)> {
if let Self::Script(script, ver) = self {
Some((script, *ver))
} else {
@@ -1080,7 +1080,7 @@ pub struct LeafNode {
impl LeafNode {
/// Constructs a new [`ScriptLeaf`] from `script` and `ver` and no Merkle branch.
- pub fn new_script(script: ScriptBuf, ver: LeafVersion) -> Self {
+ pub fn new_script(script: TapScriptBuf, ver: LeafVersion) -> Self {
Self { leaf: TapLeaf::Script(script, ver), merkle_branch: Default::default() }
}
@@ -1122,7 +1122,7 @@ impl LeafNode {
/// Returns reference to the leaf script if the leaf is known.
#[inline]
- pub fn script(&self) -> Option<&Script> { self.leaf.as_script().map(|x| x.0) }
+ pub fn script(&self) -> Option<&TapScript> { self.leaf.as_script().map(|x| x.0) }
/// Returns leaf version of the script if the leaf is known.
#[inline]
@@ -1145,7 +1145,7 @@ pub struct ScriptLeaf<'leaf> {
/// The version of the script leaf.
version: LeafVersion,
/// The script.
- script: &'leaf Script,
+ script: &'leaf TapScript,
/// The Merkle proof (hashing partners) to get this node.
merkle_branch: &'leaf TaprootMerkleBranch,
}
@@ -1155,7 +1155,7 @@ impl<'leaf> ScriptLeaf<'leaf> {
pub fn version(&self) -> LeafVersion { self.version }
/// Obtains a reference to the script inside the leaf.
- pub fn script(&self) -> &Script { self.script }
+ pub fn script(&self) -> &TapScript { self.script }
/// Obtains a reference to the Merkle proof of the leaf.
pub fn merkle_branch(&self) -> &TaprootMerkleBranch { self.merkle_branch }
@@ -1296,7 +1296,7 @@ impl<Branch: AsRef<TaprootMerkleBranch> + ?Sized> ControlBlock<Branch> {
&self,
secp: &Secp256k1<C>,
output_key: XOnlyPublicKey,
- script: &Script,
+ script: &TapScript,
) -> bool {
// compute the script hash
// Initially the curr_hash is the leaf hash
@@ -1789,7 +1789,7 @@ mod test {
) {
let out_pk = out_spk_hex[4..].parse::<XOnlyPublicKey>().unwrap();
let out_pk = TweakedPublicKey::dangerous_assume_tweaked(out_pk);
- let script = ScriptBuf::from_hex_no_length_prefix(script_hex).unwrap();
+ let script = TapScriptBuf::from_hex_no_length_prefix(script_hex).unwrap();
let control_block = ControlBlock::from_hex(control_block_hex).unwrap();
assert_eq!(control_block_hex, control_block.serialize().to_lower_hex_string());
assert!(control_block.verify_taproot_commitment(
@@ -1859,11 +1859,11 @@ mod test {
.unwrap();
let script_weights = [
- (10, ScriptBuf::from_hex_no_length_prefix("51").unwrap()), // semantics of script don't matter for this test
- (20, ScriptBuf::from_hex_no_length_prefix("52").unwrap()),
- (20, ScriptBuf::from_hex_no_length_prefix("53").unwrap()),
- (30, ScriptBuf::from_hex_no_length_prefix("54").unwrap()),
- (19, ScriptBuf::from_hex_no_length_prefix("55").unwrap()),
+ (10, TapScriptBuf::from_hex_no_length_prefix("51").unwrap()), // semantics of script don't matter for this test
+ (20, TapScriptBuf::from_hex_no_length_prefix("52").unwrap()),
+ (20, TapScriptBuf::from_hex_no_length_prefix("53").unwrap()),
+ (30, TapScriptBuf::from_hex_no_length_prefix("54").unwrap()),
+ (19, TapScriptBuf::from_hex_no_length_prefix("55").unwrap()),
];
let tree_info =
TaprootSpendInfo::with_huffman_tree(&secp, internal_key, script_weights.clone())
@@ -1885,7 +1885,7 @@ mod test {
tree_info
.script_map
.get(&(
- ScriptBuf::from_hex_no_length_prefix(script).unwrap(),
+ TapScriptBuf::from_hex_no_length_prefix(script).unwrap(),
LeafVersion::TapScript
))
.expect("Present Key")
@@ -1928,11 +1928,11 @@ mod test {
// / \ / \
// A B C / \
// D E
- let a = ScriptBuf::from_hex_no_length_prefix("51").unwrap();
- let b = ScriptBuf::from_hex_no_length_prefix("52").unwrap();
- let c = ScriptBuf::from_hex_no_length_prefix("53").unwrap();
- let d = ScriptBuf::from_hex_no_length_prefix("54").unwrap();
- let e = ScriptBuf::from_hex_no_length_prefix("55").unwrap();
+ let a = TapScriptBuf::from_hex_no_length_prefix("51").unwrap();
+ let b = TapScriptBuf::from_hex_no_length_prefix("52").unwrap();
+ let c = TapScriptBuf::from_hex_no_length_prefix("53").unwrap();
+ let d = TapScriptBuf::from_hex_no_length_prefix("54").unwrap();
+ let e = TapScriptBuf::from_hex_no_length_prefix("55").unwrap();
let builder = builder.add_leaf(2, a.clone()).unwrap();
let builder = builder.add_leaf(2, b.clone()).unwrap();
let builder = builder.add_leaf(2, c.clone()).unwrap();
@@ -2030,7 +2030,7 @@ mod test {
fn process_script_trees(
v: &serde_json::Value,
mut builder: TaprootBuilder,
- leaves: &mut Vec<(ScriptBuf, LeafVersion)>,
+ leaves: &mut Vec<(TapScriptBuf, LeafVersion)>,
depth: u8,
) -> TaprootBuilder {
if v.is_null() {
@@ -2041,7 +2041,7 @@ mod test {
}
} else {
let script =
- ScriptBuf::from_hex_no_length_prefix(v["script"].as_str().unwrap()).unwrap();
+ TapScriptBuf::from_hex_no_length_prefix(v["script"].as_str().unwrap()).unwrap();
let ver =
LeafVersion::from_consensus(v["leafVersion"].as_u64().unwrap() as u8).unwrap();
leaves.push((script.clone(), ver));
diff --git a/bitcoin/tests/psbt-sign-taproot.rs b/bitcoin/tests/psbt-sign-taproot.rs
index 6cf1ec05..87d485b4 100644
--- a/bitcoin/tests/psbt-sign-taproot.rs
+++ b/bitcoin/tests/psbt-sign-taproot.rs
@@ -6,12 +6,12 @@ use bitcoin::bip32::{DerivationPath, Fingerprint};
use bitcoin::consensus::encode::serialize_hex;
use bitcoin::opcodes::all::OP_CHECKSIG;
use bitcoin::psbt::{GetKey, Input, KeyRequest, PsbtSighashType, SignError};
-use bitcoin::script::ScriptExt as _;
+use bitcoin::script::TapScriptExt as _;
use bitcoin::taproot::{LeafVersion, TaprootBuilder, TaprootSpendInfo};
use bitcoin::transaction::Version;
use bitcoin::{
- absolute, script, Address, Amount, Network, OutPoint, PrivateKey, Psbt, ScriptBuf,
- ScriptSigBuf, Sequence, Transaction, TxIn, TxOut, Witness, XOnlyPublicKey,
+ absolute, script, Address, Amount, Network, OutPoint, PrivateKey, Psbt, ScriptSigBuf, Sequence,
+ TapScriptBuf, Transaction, TxIn, TxOut, Witness, XOnlyPublicKey,
};
use secp256k1::{Keypair, Secp256k1, Signing};
@@ -166,7 +166,7 @@ fn psbt_sign_taproot() {
}
}
-fn create_basic_single_sig_script(secp: &Secp256k1<secp256k1::All>, sk: &str) -> ScriptBuf {
+fn create_basic_single_sig_script(secp: &Secp256k1<secp256k1::All>, sk: &str) -> TapScriptBuf {
let kp = Keypair::from_seckey_str(secp, sk).expect("failed to create keypair");
let x_only_pubkey = kp.x_only_public_key().0;
script::Builder::new()
@@ -177,9 +177,9 @@ fn create_basic_single_sig_script(secp: &Secp256k1<secp256k1::All>, sk: &str) ->
fn create_taproot_tree<K: Into<XOnlyPublicKey>>(
secp: &Secp256k1<secp256k1::All>,
- script1: ScriptBuf,
- script2: ScriptBuf,
- script3: ScriptBuf,
+ script1: TapScriptBuf,
+ script2: TapScriptBuf,
+ script3: TapScriptBuf,
internal_key: K,
) -> TaprootSpendInfo {
let internal_key = internal_key.into();
@@ -273,7 +273,7 @@ fn create_psbt_for_taproot_script_path_spend<K: Into<XOnlyPublicKey>>(
tree: TaprootSpendInfo,
x_only_pubkey_of_signing_key: K,
signing_key_path: &str,
- use_script: ScriptBuf,
+ use_script: TapScriptBuf,
) -> Psbt {
let x_only_pubkey_of_signing_key = x_only_pubkey_of_signing_key.into();
let utxo_value = 6280;
diff --git a/bitcoin/tests/serde.rs b/bitcoin/tests/serde.rs
index 2810f193..625b45da 100644
--- a/bitcoin/tests/serde.rs
+++ b/bitcoin/tests/serde.rs
@@ -33,7 +33,8 @@ use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapTree, TaprootBuilder}
use bitcoin::witness::Witness;
use bitcoin::{
ecdsa, transaction, Address, Amount, NetworkKind, OutPoint, PrivateKey, PublicKey, ScriptBuf,
- ScriptPubKeyBuf, ScriptSigBuf, Sequence, Target, Transaction, TxIn, TxOut, Txid, Work,
+ ScriptPubKeyBuf, ScriptSigBuf, Sequence, TapScriptBuf, Target, Transaction, TxIn, TxOut, Txid,
+ Work,
};
#[test]
@@ -321,7 +322,7 @@ fn serde_regression_taproot_sig() {
#[test]
fn serde_regression_taptree() {
let ver = LeafVersion::from_consensus(0).unwrap();
- let script = ScriptBuf::from(vec![0u8, 1u8, 2u8]);
+ let script = TapScriptBuf::from(vec![0u8, 1u8, 2u8]);
let mut builder = TaprootBuilder::new().add_leaf_with_ver(1, script.clone(), ver).unwrap();
builder = builder.add_leaf(1, script).unwrap();
let tree = TapTree::try_from(builder).unwrap();
diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs
index 7499c347..8e2c251a 100644
--- a/primitives/src/lib.rs
+++ b/primitives/src/lib.rs
@@ -76,7 +76,7 @@ pub use self::{
},
script::{
RedeemScript, RedeemScriptBuf, Script, ScriptBuf, ScriptPubKey, ScriptPubKeyBuf, ScriptSig,
- ScriptSigBuf, WitnessScript, WitnessScriptBuf,
+ ScriptSigBuf, TapScript, TapScriptBuf, WitnessScript, WitnessScriptBuf,
},
transaction::{Transaction, TxIn, TxOut},
witness::Witness,
diff --git a/primitives/src/script/mod.rs b/primitives/src/script/mod.rs
index 5c87560e..8ed2378f 100644
--- a/primitives/src/script/mod.rs
+++ b/primitives/src/script/mod.rs
@@ -30,7 +30,7 @@ use crate::prelude::{Borrow, BorrowMut, Box, Cow, ToOwned, Vec};
pub use self::{
borrowed::GenericScript,
owned::GenericScriptBuf,
- tag::{Tag, RedeemScriptTag, ScriptPubKeyTag, ScriptSigTag, Whatever, WitnessScriptTag},
+ tag::{Tag, RedeemScriptTag, ScriptPubKeyTag, ScriptSigTag, TapScriptTag, Whatever, WitnessScriptTag},
};
/// Placeholder doc (will be replaced in later commit)
@@ -57,6 +57,12 @@ pub type ScriptPubKeyBuf = GenericScriptBuf<ScriptPubKeyTag>;
/// A script signature (scriptSig).
pub type ScriptSigBuf = GenericScriptBuf<ScriptSigTag>;
+/// A Segwit v1 Taproot script.
+pub type TapScriptBuf = GenericScriptBuf<TapScriptTag>;
+
+/// A reference to a Segwit v1 Taproot script.
+pub type TapScript = GenericScript<TapScriptTag>;
+
/// A Segwit v0 witness script.
pub type WitnessScriptBuf = GenericScriptBuf<WitnessScriptTag>;
diff --git a/primitives/src/script/tag.rs b/primitives/src/script/tag.rs
index fa70f174..34081064 100644
--- a/primitives/src/script/tag.rs
+++ b/primitives/src/script/tag.rs
@@ -29,6 +29,11 @@ impl Tag for ScriptSigTag {}
pub enum ScriptPubKeyTag {}
impl Tag for ScriptPubKeyTag {}
+/// A Segwit v1 Taproot script.
+#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
+pub enum TapScriptTag {}
+impl Tag for TapScriptTag {}
+
/// A Segwit v0 witness script.
#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub enum WitnessScriptTag {}
diff --git a/primitives/tests/api.rs b/primitives/tests/api.rs
index bbb6eef0..f0581dc7 100644
--- a/primitives/tests/api.rs
+++ b/primitives/tests/api.rs
@@ -19,7 +19,8 @@ use bitcoin_primitives::script::{self, ScriptHash, WScriptHash};
use bitcoin_primitives::{
absolute, block, merkle_tree, pow, relative, transaction, witness, OutPoint, RedeemScript,
RedeemScriptBuf, Script, ScriptBuf, ScriptPubKey, ScriptPubKeyBuf, ScriptSig, ScriptSigBuf,
- Sequence, Transaction, TxIn, TxOut, Txid, Witness, WitnessScript, WitnessScriptBuf, Wtxid,
+ Sequence, TapScript, TapScriptBuf, Transaction, TxIn, TxOut, Txid, Witness, WitnessScript,
+ WitnessScriptBuf, Wtxid,
};
use hashes::sha256t;
@@ -48,6 +49,7 @@ struct Structs<'a> {
j1: &'a RedeemScript,
j2: &'a ScriptPubKey,
j3: &'a ScriptSig,
+ j4: &'a TapScript,
j5: &'a WitnessScript,
k: ScriptHash,
l: WScriptHash,
@@ -55,6 +57,7 @@ struct Structs<'a> {
m1: RedeemScriptBuf,
m2: ScriptPubKeyBuf,
m3: ScriptSigBuf,
+ m4: TapScriptBuf,
m5: WitnessScriptBuf,
n: Sequence,
o: Transaction,
@@ -72,6 +75,7 @@ static SCRIPT: ScriptBuf = ScriptBuf::new();
static REDEEM_SCRIPT: RedeemScriptBuf = RedeemScriptBuf::new();
static SCRIPT_SIG: ScriptSigBuf = ScriptSigBuf::new();
static SCRIPT_PUB_KEY: ScriptPubKeyBuf = ScriptPubKeyBuf::new();
+static TAP_SCRIPT: TapScriptBuf = TapScriptBuf::new();
static WITNESS_SCRIPT: WitnessScriptBuf = WitnessScriptBuf::new();
static BYTES: [u8; 32] = [0x00; 32];
@@ -95,6 +99,7 @@ struct CommonTraits {
m1: RedeemScriptBuf,
m2: ScriptPubKeyBuf,
m3: ScriptSigBuf,
+ m4: TapScriptBuf,
m5: WitnessScriptBuf,
n: Sequence,
o: Transaction,
@@ -127,6 +132,7 @@ struct Clone<'a> {
m1: RedeemScriptBuf,
m2: ScriptPubKeyBuf,
m3: ScriptSigBuf,
+ m4: TapScriptBuf,
m5: WitnessScriptBuf,
n: Sequence,
o: Transaction,
@@ -160,6 +166,7 @@ struct Ord {
m1: RedeemScriptBuf,
m2: ScriptPubKeyBuf,
m3: ScriptSigBuf,
+ m4: TapScriptBuf,
m5: WitnessScriptBuf,
n: Sequence,
o: Transaction,
@@ -181,11 +188,13 @@ struct Default {
b1: &'static RedeemScript,
b2: &'static ScriptPubKey,
b3: &'static ScriptSig,
+ b4: &'static TapScript,
b5: &'static WitnessScript,
c: ScriptBuf,
c1: RedeemScriptBuf,
c2: ScriptPubKeyBuf,
c3: ScriptSigBuf,
+ c4: TapScriptBuf,
c5: WitnessScriptBuf,
d: Sequence,
e: Witness,
@@ -303,6 +312,7 @@ fn api_all_non_error_types_have_non_empty_debug() {
REDEEM_SCRIPT.as_script();
SCRIPT_SIG.as_script();
SCRIPT_PUB_KEY.as_script();
+ TAP_SCRIPT.as_script();
WITNESS_SCRIPT.as_script();
ScriptHash::from_script(&REDEEM_SCRIPT).unwrap();
WScriptHash::from_script(&WITNESS_SCRIPT).unwrap();
@@ -310,6 +320,7 @@ fn api_all_non_error_types_have_non_empty_debug() {
REDEEM_SCRIPT.clone();
SCRIPT_SIG.clone();
SCRIPT_PUB_KEY.clone();
+ TAP_SCRIPT.clone();
WITNESS_SCRIPT.clone();
Sequence::arbitrary(&mut u).unwrap();
Transaction::arbitrary(&mut u).unwrap();
@@ -349,11 +360,13 @@ fn regression_default() {
b1: RedeemScript::from_bytes(&[]),
b2: ScriptPubKey::from_bytes(&[]),
b3: ScriptSig::from_bytes(&[]),
+ b4: TapScript::from_bytes(&[]),
b5: WitnessScript::from_bytes(&[]),
c: ScriptBuf::from_bytes(Vec::new()),
c1: RedeemScriptBuf::from_bytes(Vec::new()),
c2: ScriptPubKeyBuf::from_bytes(Vec::new()),
c3: ScriptSigBuf::from_bytes(Vec::new()),
+ c4: TapScriptBuf::from_bytes(Vec::new()),
c5: WitnessScriptBuf::from_bytes(Vec::new()),
d: Sequence::MAX,
e: Witness::new(),
Why this scored 19/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.