What changed, and why it matters
This commit adds a new helper function to build Bitcoin transaction witnesses for a common payment type (P2WSH). It is purely additive code with no bug fixes, no changes to existing behavior, and no security-related claims by the authors.
No security action needed. Treat as a normal feature addition; review for API consistency if desired.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces Witness::p2wsh(satisfaction, witness_script) in bitcoin/src/blockdata/witness.rs. The constructor collects satisfaction stack items and appends the witness script as the final element, matching the Bitcoin protocol layout for P2WSH (and P2SH-P2WSH) inputs. It includes a unit test using a 2-of-2 multisig witness script and two dummy signatures. No existing APIs are modified.
Changed components
bitcoin/src/blockdata/witness.rsInspect captured patch +33 / −0
diff --git a/bitcoin/src/blockdata/witness.rs b/bitcoin/src/blockdata/witness.rs
index c1b2efee..e4535e88 100644
--- a/bitcoin/src/blockdata/witness.rs
+++ b/bitcoin/src/blockdata/witness.rs
@@ -56,6 +56,21 @@ internal_macros::define_extension_trait! {
witness
}
+ ///Constructs a new witness required to spend a P2WSH output.
+ ///
+ /// The witness will be made up of the satisfaction elements (signatures, preimages, etc.)
+ /// followed by the witness script as the last element. Also useful for spending a
+ /// P2SH-P2WSH output (with the appropriate scriptSig).
+ ///
+ /// The `satisfaction` slice should contain the script satisfaction stack items in the
+ /// order they are pushed onto the stack (e.g., `&[&[][..], &sig1[..], &sig2[..]]` for a
+ /// 2-of-3 multisig).
+ fn p2wsh(satisfaction: &[&[u8]], witness_script: &WitnessScript) -> Self {
+ let mut witness: Witness = satisfaction.iter().collect();
+ witness.push(witness_script.as_bytes());
+ witness
+ }
+
/// Constructs a new witness required to do a key path spend of a P2TR output.
fn p2tr_key_spend(signature: &taproot::Signature) -> Self {
let mut witness = Witness::new();
@@ -426,6 +441,24 @@ mod test {
assert_eq!(tx_bytes_back, tx_bytes);
}
+ #[test]
+ fn p2wsh_witness() {
+ let witness_script_bytes = hex!("522103e5529d8eaa3d559903adb2e881eb06c86ac2574ffa503c45f4e942e2a693b33e2102e5f10fcdcdbab211e0af6a481f5532536ec61a5fdbf7183770cf8680fe729d8152ae");
+ let witness_script = WitnessScript::from_bytes(&witness_script_bytes);
+ let sig1 = hex!("304402201234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef02201234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef01");
+ let sig2 = hex!("3044022011111111111111111111111111111111111111111111111111111111111111110220222222222222222222222222222222222222222222222222222222222222222201");
+
+ // 2-of-2 multisig satisfaction: OP_0 bug push, then two sigs
+ let satisfaction: &[&[u8]] = &[&[], &sig1, &sig2];
+ let witness = Witness::p2wsh(satisfaction, witness_script);
+
+ assert_eq!(witness.len(), 4); // empty push + sig1 + sig2 + witness_script
+ assert_eq!(witness[0], *b"");
+ assert_eq!(witness[1], sig1[..]);
+ assert_eq!(witness[2], sig2[..]);
+ assert_eq!(witness[3], *witness_script.as_bytes());
+ }
+
#[test]
fn fuzz_cases() {
let bytes = hex!("26ff0000000000c94ce592cf7a4cbb68eb00ce374300000057cd0000000000000026");
Why this scored 15/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.