mirror of
https://github.com/bitcoin/bips.git
synced 2026-02-23 15:38:22 +00:00
Review comments and assistance by: Armin Sabouri <armins88@gmail.com> D++ <82842780+dplusplus1024@users.noreply.github.com> Jameson Lopp <jameson.lopp@gmail.com> jbride <jbride2001@yahoo.com> Joey Yandle <xoloki@gmail.com> Jon Atack <jon@atack.com> Jonas Nick <jonasd.nick@gmail.com> Kyle Crews <kylecrews@Kyles-Mac-Studio.local> Mark "Murch" Erhardt <murch@murch.one> notmike-5 <notmike-5@users.noreply.github.com> Vojtěch Strnad <43024885+vostrnad@users.noreply.github.com> Co-authored-by: Ethan Heilman <ethan.r.heilman@gmail.com> Co-authored-by: Isabel Foxen Duke <110147802+Isabelfoxenduke@users.noreply.github.com>
103 lines
5.0 KiB
Rust
103 lines
5.0 KiB
Rust
use log::info;
|
|
use bitcoin::blockdata::witness::Witness;
|
|
|
|
use p2mr_ref::{ pay_to_p2wpkh_tx, serialize_script };
|
|
|
|
use p2mr_ref::data_structures::{SpendDetails, LeafScriptType};
|
|
|
|
/* The rust-bitcoin crate does not provide a single high-level API that builds the full Taproot script-path witness stack for you.
|
|
It does expose all the necessary types and primitives to build it manually and correctly.
|
|
*/
|
|
|
|
// https://learnmeabitcoin.com/technical/upgrades/taproot/#example-2-script-path-spend-simple
|
|
#[test]
|
|
fn test_script_path_spend_simple() {
|
|
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
|
|
|
|
let script_inputs_count = hex::decode("03").unwrap();
|
|
let script_inputs_bytes: Vec<u8> = hex::decode("08").unwrap();
|
|
let leaf_script_bytes: Vec<u8> = hex::decode("5887").unwrap();
|
|
let control_block_bytes: Vec<u8> =
|
|
hex::decode("c1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap();
|
|
let test_witness_bytes: Vec<u8> = hex::decode(
|
|
"03010802588721c1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329",
|
|
)
|
|
.unwrap();
|
|
|
|
let mut derived_witness: Witness = Witness::new();
|
|
derived_witness.push(script_inputs_count);
|
|
derived_witness.push(serialize_script(&script_inputs_bytes));
|
|
derived_witness.push(serialize_script(&leaf_script_bytes));
|
|
derived_witness.push(serialize_script(&control_block_bytes));
|
|
|
|
info!("witness: {:?}", derived_witness);
|
|
|
|
let derived_witness_vec: Vec<u8> = derived_witness.iter().flatten().cloned().collect();
|
|
|
|
assert_eq!(derived_witness_vec, test_witness_bytes);
|
|
}
|
|
|
|
|
|
// Inspired by: https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature
|
|
// Spends from a p2mr UTXO to a p2wpk UTXO
|
|
#[test]
|
|
fn test_script_path_spend_signatures() {
|
|
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
|
|
|
|
let funding_tx_id_bytes: Vec<u8> =
|
|
hex::decode("d1c40446c65456a9b11a9dddede31ee34b8d3df83788d98f690225d2958bfe3c").unwrap();
|
|
|
|
// The input index of the funding tx
|
|
let funding_tx_index: u32 = 0;
|
|
|
|
let funding_utxo_amount_sats: u64 = 20000;
|
|
|
|
// OP_PUSHBYTES_32 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0 OP_CHECKSIG
|
|
let input_leaf_script_bytes: Vec<u8> =
|
|
hex::decode("206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac").unwrap();
|
|
|
|
// Modified from learnmeabitcoin example
|
|
// Changed from c0 to c1 control byte to reflect p2mr specification: The parity bit of the control byte is always 1 since P2MR does not have a key-spend path.
|
|
let input_control_block_bytes: Vec<u8> =
|
|
hex::decode("c1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap();
|
|
|
|
let input_script_pubkey_bytes: Vec<u8> =
|
|
hex::decode("5120f3778defe5173a9bf7169575116224f961c03c725c0e98b8da8f15df29194b80")
|
|
.unwrap();
|
|
let input_script_priv_key_bytes: Vec<u8> = hex::decode("9b8de5d7f20a8ebb026a82babac3aa47a008debbfde5348962b2c46520bd5189").unwrap();
|
|
|
|
// Convert to Vec<Vec<u8>> format expected by the function
|
|
let input_script_priv_keys_bytes: Vec<Vec<u8>> = vec![input_script_priv_key_bytes];
|
|
|
|
|
|
// https://learnmeabitcoin.com/explorer/tx/797505b104b5fb840931c115ea35d445eb1f64c9279bf23aa5bb4c3d779da0c2#outputs
|
|
let spend_output_pubkey_bytes: Vec<u8> = hex::decode("0de745dc58d8e62e6f47bde30cd5804a82016f9e").unwrap();
|
|
|
|
let spend_output_amount_sats: u64 = 15000;
|
|
|
|
let test_sighash_bytes: Vec<u8> = hex::decode("752453d473e511a0da2097d664d69fe5eb89d8d9d00eab924b42fc0801a980c9").unwrap();
|
|
let test_signature_bytes: Vec<u8> = hex::decode("01769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f").unwrap();
|
|
|
|
// Modified from learnmeabitcoin example
|
|
// Changed from c0 to c1 control byte to reflect p2mr specification: The parity bit of the control byte is always 1 since P2MR does not have a key-spend path.
|
|
let test_witness_bytes: Vec<u8> = hex::decode("01769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f01206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0acc1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap();
|
|
|
|
let result: SpendDetails = pay_to_p2wpkh_tx(funding_tx_id_bytes,
|
|
funding_tx_index,
|
|
funding_utxo_amount_sats,
|
|
input_script_pubkey_bytes,
|
|
input_control_block_bytes,
|
|
input_leaf_script_bytes,
|
|
input_script_priv_keys_bytes, // Now passing Vec<Vec<u8>> format
|
|
spend_output_pubkey_bytes,
|
|
spend_output_amount_sats,
|
|
LeafScriptType::SchnorrOnly // This test uses a Schnorr signature
|
|
);
|
|
|
|
assert_eq!(result.sighash.as_slice(), test_sighash_bytes.as_slice(), "sighash mismatch");
|
|
assert_eq!(result.sig_bytes, test_signature_bytes, "signature mismatch");
|
|
assert_eq!(result.derived_witness_vec, test_witness_bytes, "derived_witness mismatch");
|
|
|
|
}
|
|
|