### Install Dependencies and Compile TypeScript Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/js/README.adoc Install project dependencies using npm and compile TypeScript code using the TypeScript compiler. ```bash $ npm install ``` ```bash # compile Typecript $ npx tsc ``` -------------------------------- ### Taproot Script Path Spending Example Source: https://context7.com/bitcoin/bips/llms.txt Example demonstrating the computation of TapTweak for script path spending in Taproot. This involves sequentially hashing TapLeaf and TapBranch elements. ```python # Example: Computing TapTweak for script path spending D = tagged_hash("TapLeaf", bytes([leaf_version]) + ser_script(script)) CD = tagged_hash("TapBranch", C + D) CDE = tagged_hash("TapBranch", E + CD) ABCDE = tagged_hash("TapBranch", AB + CDE) TapTweak = tagged_hash("TapTweak", internal_pubkey + ABCDE) ``` -------------------------------- ### Verify Expression Example (pk) Source: https://github.com/bitcoin/bips/blob/master/bip-0379.md An example of a 'V' type expression. These also take inputs from the top of the stack but continue without pushing anything upon satisfaction. They will abort instead of being dissatisfied. ```miniscript v:pk(key) = CHECKSIGVERIFY ``` -------------------------------- ### Key Expression Example (pk_h) Source: https://github.com/bitcoin/bips/blob/master/bip-0379.md An example of a 'K' type expression. These take inputs from the top of the stack and always push a public key onto the stack, requiring a signature for satisfaction. A 'K' can be converted to a 'B' using the 'c:' wrapper. ```miniscript pk_h(key) = DUP HASH160 EQUALVERIFY ``` -------------------------------- ### Wrapped Expression Example (s:pk) Source: https://github.com/bitcoin/bips/blob/master/bip-0379.md An example of a 'W' type expression. These take inputs from one below the top of the stack and push a value either on top or one below. 'W' expressions are either SWAP B ('s:') or TOALTSTACK B FROMALTSTACK ('a:'). ```miniscript s:pk(key) = SWAP CHECKSIG ``` -------------------------------- ### Install Build Dependencies on Debian/Ubuntu Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-signet-workshop.adoc Installs necessary development tools including cmake, build-essential, clang, and libclang-dev on Debian or Ubuntu systems. These are required for building native code dependencies like libbitcoinpqc. ```bash sudo apt update sudo apt install cmake build-essential clang libclang-dev ``` -------------------------------- ### Channel Script Example with OP_PAIRCOMMIT Source: https://github.com/bitcoin/bips/blob/master/bip-0442.md Illustrates the use of OP_PAIRCOMMIT within a Lightning Symmetry channel script for data availability. This example assumes specific pre-defined variables and requires `OP_CHECKTEMPLATEVERIFY`, `OP_INTERNALKEY`, `OP_CHECKSIGFROMSTACK`, and `OP_CHECKLOCKTIMEVERIFY` opcodes. ```pseudo-code # Witness: OP_CHECKTEMPLATEVERIFY # , , OP_PAIRCOMMIT # , PC(state-n-recovery-data, state-n-hash) OP_INTERNALKEY # , PC(state-n-recovery-data, state-n-hash), OP_CHECKSIGFROMSTACK # <1> # <1>, OP_CHECKLOCKTIMEVERIFY # <1>, OP_DROP # <1> ``` -------------------------------- ### Install Build Dependencies on Fedora/RHEL Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-signet-workshop.adoc Installs essential development packages such as cmake, make, gcc, g++, clang, clang-libs, and llvm-devel on Fedora or RHEL-based systems. These are prerequisites for compiling C/C++ code and Rust bindings. ```bash sudo dnf5 update sudo dnf5 install cmake make gcc gcc-c++ clang clang-libs llvm-devel ``` -------------------------------- ### Run Bitcoin Core in Regtest Mode Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2tr-end-to-end.adoc Start the compiled Bitcoin Core daemon in regtest mode with transaction indexing enabled. ```bash ./build/bin/bitcoind -daemon=0 -regtest=1 -txindex ``` -------------------------------- ### Run P2MR Demo Docker Container Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-signet-workshop.adoc This command starts the workshop Docker container, providing an interactive bash shell. It configures the RPC connection details and uses the specified image. ```bash sudo docker run -it --rm --entrypoint /bin/bash --network host \ -e RPC_CONNECT=10.21.3.194 \ quay.io/jbride2000/p2mr_demo:0.1 ``` -------------------------------- ### Base Expression Example (older) Source: https://github.com/bitcoin/bips/blob/master/bip-0379.md An example of a 'B' type expression. These take inputs from the top of the stack and push a nonzero value on satisfaction or 0 on dissatisfaction. This type is required for the top-level expression. ```miniscript older(n) = CHECKSEQUENCEVERIFY ``` -------------------------------- ### Build Bitcoin Core (p2mr branch) Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2tr-end-to-end.adoc Compile the specified 'p2mr' branch of Bitcoin Core. Ensure you have the necessary build tools installed. ```bash cmake -B build \ -DWITH_ZMQ=ON \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DBUILD_BENCH=ON \ -DSANITIZERS=address,undefined cmake --build build -j$(nproc) ``` -------------------------------- ### Create Spending Transaction for P2MR UTXO Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-signet-workshop.adoc Executes a Rust example program (`p2mr_spend`) to construct a transaction that spends from the previously funded P2MR UTXO. This process involves generating a SigHash and signing it with the private key corresponding to the leaf script. ```bash export SPEND_DETAILS=$( cargo run --example p2mr_spend ) ``` -------------------------------- ### Run Bitcoin Core in Signet Mode Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-signet-workshop.adoc Starts a Bitcoin Core daemon in signet mode with transaction indexing and pruning disabled. Note that running in signet mode requires the bitcoin core to be configured with the 'signetchallenge' property. ```bash ./build/bin/bitcoind -daemon=0 -signet=1 -txindex -prune=0 ``` -------------------------------- ### Generate P2MR ScripPubKey with Multi-Leaf Taptree Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-end-to-end.adoc This command generates a P2MR address and associated information by running the `p2mr_construction` example. The output, which includes details for constructing a transaction with a P2MR UTXO, is then parsed using `jq`. ```bash export BITCOIN_ADDRESS_INFO=$( cargo run --example p2mr_construction ) && echo $BITCOIN_ADDRESS_INFO | jq -r . ``` -------------------------------- ### Set Environment Variables from P2MR Construction Output Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-end-to-end.adoc This command exports several environment variables derived from the `BITCOIN_ADDRESS_INFO` output, which is generated by the `p2mr_construction` example. These variables include merkle root, private keys, leaf scripts, control block, funding script public key, and the P2MR address, all of which are necessary for subsequent steps. ```bash export MERKLE_ROOT=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.tree_root_hex' ) && export LEAF_SCRIPT_PRIV_KEYS_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.leaf_script_priv_keys_hex' ) && export LEAF_SCRIPT_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.leaf_script_hex' ) && export CONTROL_BLOCK_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.control_block_hex' ) && export FUNDING_SCRIPT_PUBKEY=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.utxo_return.script_pubkey_hex' ) && export P2MR_ADDR=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.utxo_return.bech32m_address' ) ``` -------------------------------- ### Run Bitcoin Core in Regtest Mode Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-end-to-end.adoc Start the bitcoind daemon in regtest mode with transaction indexing and pruning disabled. The daemon is run without detaching from the terminal. ```bash ./build/bin/bitcoind -daemon=0 -regtest=1 -txindex -prune=0 ``` -------------------------------- ### Create and Inspect P2TR Spend Transaction Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2tr-end-to-end.adoc This snippet demonstrates how to create a raw P2TR spend transaction using a Rust example, and then extracts transaction details like hex, sighash, and signature bytes. It also shows how to decode the raw transaction for inspection. ```bash export SPEND_DETAILS=$( cargo run --example p2tr_spend ) export RAW_P2TR_SPEND_TX=$( echo $SPEND_DETAILS | jq -r '.tx_hex' ) \ && echo "RAW_P2TR_SPEND_TX = $RAW_P2TR_SPEND_TX" \ && export SIG_HASH=$( echo $SPEND_DETAILS | jq -r '.sighash' ) \ && echo "SIG_HASH = $SIG_HASH" \ && export SIG_BYTES=$( echo $SPEND_DETAILS | jq -r '.sig_bytes' ) \ && echo "SIG_BYTES = $SIG_BYTES" ``` ```bash b-reg decoderawtransaction $RAW_P2TR_SPEND_TX ``` -------------------------------- ### Generate P2TR ScriptPubKey Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2tr-end-to-end.adoc Generate a P2TR script public key with a multi-leaf taptree using an external cargo example. The output contains details for constructing the P2TR address and its associated taptree. ```bash export BITCOIN_NETWORK=regtest \ && export BITCOIN_ADDRESS_INFO=$( cargo run --example p2tr_construction ) \ && echo $BITCOIN_ADDRESS_INFO | jq -r . ``` -------------------------------- ### Run Bitcoin Core Benchmarks Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc Set the preimage size in bytes and run the VerifySHA256Bench benchmark. Adjust the minimum time for more stable results. ```bash export PREIMAGE_SIZE_BYTES=8000 ./build/bin/bench_bitcoin --filter=VerifySHA256Bench -min-time=5000 ``` -------------------------------- ### Create a Bitcoin Core Wallet Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-end-to-end.adoc Use the b-cli command to create a new wallet named 'anduro' with descriptors enabled and set to load on startup. ```bash export W_NAME=anduro b-cli -named createwallet \ wallet_name=$W_NAME \ descriptors=true \ load_on_startup=true ``` -------------------------------- ### Example Tapscript for Schnorr + SLH-DSA Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-signet-workshop.adoc This is an example of a locking script in a tapscript leaf when using Schnorr and SLH-DSA. It commits to a 32-byte SLH-DSA public key and uses specific opcodes. ```plaintext 886fc1edb7a8a364da65aef57343de451c1449d8a6c5b766fe150667d50d3e80 OP_CHECKSIG 479f93fbd251863c3e3e72da6e26ea82f87313da13090de10e57eca1f8b5e0f3 OP_SUBSTR OP_BOOLAND OP_VERIFY ``` -------------------------------- ### Run BIP 360 Tests Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/js/README.adoc Execute the BIP 360 reference implementation tests using Node.js. This includes running the p2mr-example and the test-npm-pqc-package scripts. ```bash # run tests $ node src/p2mr-example.ts $ node src/test-npm-pqc-package.js ``` -------------------------------- ### Create Bitcoin Core Wallet Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2tr-end-to-end.adoc Create a new wallet in Bitcoin Core for regtest mode, enabling descriptors and setting it to load on startup. ```bash export W_NAME=regtest \ && export WPASS=regtest b-reg -named createwallet \ wallet_name=$W_NAME \ descriptors=true \ passphrase="$WPASS" \ load_on_startup=true ``` -------------------------------- ### XSS Payload with LiveScript Source: https://github.com/bitcoin/bips/wiki/Comments:BIP-0001 An example of using the 'livescript:' pseudo-protocol, though rarely supported. ```html ``` -------------------------------- ### Compile Bitcoin Core with Benchmarking Enabled Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc Compile Bitcoin Core with ZMQ support, export compile commands, and enable benchmarking. This is a prerequisite for running performance tests. ```bash cmake \ -B build \ -DWITH_ZMQ=ON \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DBUILD_BENCH=ON cmake --build build -j$(nproc) ``` -------------------------------- ### Run Typos Check Locally Source: https://github.com/bitcoin/bips/blob/master/CONTRIBUTING.md Execute the 'typos' command in the root directory to perform CI checks for common typos in proposed BIPs. Ensure 'typos' is installed locally. ```bash typos ``` -------------------------------- ### p2mrScriptBuf Creation Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/development_notes.adoc Explains how to create a P2MR scriptPubKey UTXO using only the merkle root, as keypath spend is disabled. ```APIDOC ## p2mrScriptBuf Allows for creation of a p2mr scriptPubKey UTXO using only the merkle root of a script tree. ### Methods - **new(inner: ScriptBuf)**: Creates a new p2mr script from a ScriptBuf. - **new_p2mr(merkle_root: TapNodeHash)**: Generates a p2mr scriptPubKey output. Only accepts the merkle_root since keypath spend is disabled. This function constructs the script according to BIP-360 standards. ``` -------------------------------- ### Scan UTXO Set for P2TR Address Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2tr-end-to-end.adoc Scan the UTXO set to find transactions funding the specified P2TR address. This requires the Bitcoin Core node to be started with the '-txindex' argument. ```bash export P2TR_DESC=$( b-reg getdescriptorinfo "addr($P2TR_ADDR)" | jq -r '.descriptor' ) \ && echo $P2TR_DESC \ && b-reg scantxoutset start '[{"desc": "'$P2TR_DESC'"}]' ``` -------------------------------- ### Reference Implementation for BIP-346 Source: https://github.com/bitcoin/bips/blob/master/bip-0346.md A reference implementation of BIP-346 focusing on clarity and correctness. It is written in Rust and serves as a basis for understanding the proposal's functionality. ```rust /// BIP-346: OP_TXHASH /// /// This BIP introduces a new opcode, OP_TXHASH, which allows for hashing of specific /// parts of a transaction. This can be used for various advanced scripting purposes, /// including covenants and generalized signature hashing. /// /// The opcode takes a single argument: a TxFieldSelector, which specifies which /// parts of the transaction to include in the hash. The TxFieldSelector is a /// 1-byte value that can be used to select different fields or combinations of fields. /// /// For example, a TxFieldSelector of 0x00 (empty) results in a hash semantically /// equivalent to BIP-119's OP_CHECKTEMPLATEVERIFY. /// /// When combined with OP_CHECKSIGFROMSTACK (BIP-348), OP_TXHASH enables a fully /// generalized signature hash construction, allowing for flexible covenant designs /// and multi-user protocols. /// /// The implementation below is a reference implementation focusing on clarity and /// correctness, not on efficiency. It is intended to be used for testing and /// understanding the BIP's behavior. use bitcoin_hashes::{sha256, Hash, HashEngine}; use std::io::Write; // Define the TxFieldSelector enum to represent different transaction fields that can be hashed. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum TxFieldSelector { /// Hash the entire transaction. All = 0x00, /// Hash the transaction without witness data. NoWitness = 0x01, /// Hash the transaction without signatures. NoSignature = 0x02, /// Hash the transaction without witness data and signatures. NoWitnessNoSignature = 0x03, /// Hash the transaction's version. Version = 0x04, /// Hash the transaction's locktime. Locktime = 0x05, /// Hash the transaction's input count. InputCount = 0x06, /// Hash the transaction's output count. OutputCount = 0x07, /// Hash the transaction's total input value. InputValue = 0x08, /// Hash the transaction's total output value. OutputValue = 0x09, /// Hash the transaction's scriptSig of the first input. FirstInputScriptSig = 0x0A, /// Hash the transaction's scriptSig of the last input. LastInputScriptSig = 0x0B, /// Hash the transaction's witness of the first input. FirstInputWitness = 0x0C, /// Hash the transaction's witness of the last input. LastInputWitness = 0x0D, /// Hash the transaction's outputs. Outputs = 0x0E, /// Hash the transaction's inputs. Inputs = 0x0F, /// Hash the transaction's prevouts. Prevouts = 0x10, /// Hash the transaction's sequences. Sequences = 0x11, /// Hash the transaction's outputs hash. OutputsHash = 0x12, /// Hash the transaction's inputs hash. InputsHash = 0x13, /// Hash the transaction's prevouts hash. PrevoutsHash = 0x14, /// Hash the transaction's sequences hash. SequencesHash = 0x15, /// Hash the transaction's witness hash. WitnessHash = 0x16, /// Hash the transaction's sighash flags. Sighash = 0x17, /// Hash the transaction's version and sighash flags. VersionSighash = 0x18, /// Hash the transaction's locktime and sighash flags. LocktimeSighash = 0x19, /// Hash the transaction's input count and sighash flags. InputCountSighash = 0x1A, /// Hash the transaction's output count and sighash flags. OutputCountSighash = 0x1B, /// Hash the transaction's total input value and sighash flags. InputValueSighash = 0x1C, /// Hash the transaction's total output value and sighash flags. OutputValueSighash = 0x1D, /// Hash the transaction's scriptSig of the first input and sighash flags. FirstInputScriptSigSighash = 0x1E, /// Hash the transaction's scriptSig of the last input and sighash flags. LastInputScriptSigSighash = 0x1F, /// Hash the transaction's witness of the first input and sighash flags. FirstInputWitnessSighash = 0x20, /// Hash the transaction's witness of the last input and sighash flags. LastInputWitnessSighash = 0x21, /// Hash the transaction's outputs and sighash flags. OutputsSighash = 0x22, /// Hash the transaction's inputs and sighash flags. InputsSighash = 0x23, /// Hash the transaction's prevouts and sighash flags. PrevoutsSighash = 0x24, /// Hash the transaction's sequences and sighash flags. SequencesSighash = 0x25, /// Hash the transaction's outputs hash and sighash flags. OutputsHashSighash = 0x26, /// Hash the transaction's inputs hash and sighash flags. InputsHashSighash = 0x27, /// Hash the transaction's prevouts hash and sighash flags. PrevoutsHashSighash = 0x28, /// Hash the transaction's sequences hash and sighash flags. SequencesHashSighash = 0x29, /// Hash the transaction's witness hash and sighash flags. WitnessHashSighash = 0x2A, } impl TxFieldSelector { /// Converts a u8 byte into a TxFieldSelector. pub fn from_u8(value: u8) -> Option { if value <= 0x2A { Some(unsafe { std::mem::transmute(value) }) } else { None } } /// Returns the u8 byte representation of the TxFieldSelector. pub fn to_u8(self) -> u8 { self as u8 } } /// Computes the transaction hash based on the provided transaction and TxFieldSelector. /// /// # Arguments /// /// * `tx` - The transaction to hash. /// * `selector` - The TxFieldSelector specifying which parts of the transaction to include in the hash. /// /// # Returns /// /// A SHA256 hash of the selected transaction fields. pub fn txhash(tx: &Tx, selector: TxFieldSelector) -> sha256::Hash { let mut engine = sha256::HashEngine::new(); let mut writer = engine.clone(); match selector { TxFieldSelector::All => { tx.version().consensus_encode(&mut writer).unwrap(); tx.input.consensus_encode(&mut writer).unwrap(); tx.output.consensus_encode(&mut writer).unwrap(); tx.lock_time().consensus_encode(&mut writer).unwrap(); } TxFieldSelector::NoWitness => { tx.version().consensus_encode(&mut writer).unwrap(); tx.input.consensus_encode(&mut writer).unwrap(); tx.output.consensus_encode(&mut writer).unwrap(); tx.lock_time().consensus_encode(&mut writer).unwrap(); } TxFieldSelector::NoSignature => { tx.version().consensus_encode(&mut writer).unwrap(); for input in &tx.input { input.previous_output.consensus_encode(&mut writer).unwrap(); input.script_sig.consensus_encode(&mut writer).unwrap(); input.sequence.consensus_encode(&mut writer).unwrap(); } tx.output.consensus_encode(&mut writer).unwrap(); tx.lock_time().consensus_encode(&mut writer).unwrap(); } TxFieldSelector::NoWitnessNoSignature => { tx.version().consensus_encode(&mut writer).unwrap(); for input in &tx.input { input.previous_output.consensus_encode(&mut writer).unwrap(); input.script_sig.consensus_encode(&mut writer).unwrap(); input.sequence.consensus_encode(&mut writer).unwrap(); } tx.output.consensus_encode(&mut writer).unwrap(); tx.lock_time().consensus_encode(&mut writer).unwrap(); } TxFieldSelector::Version => { tx.version().consensus_encode(&mut writer).unwrap(); } TxFieldSelector::Locktime => { tx.lock_time().consensus_encode(&mut writer).unwrap(); } TxFieldSelector::InputCount => { tx.input.len().consensus_encode(&mut writer).unwrap(); } TxFieldSelector::OutputCount => { tx.output.len().consensus_encode(&mut writer).unwrap(); } TxFieldSelector::InputValue => { let mut total_value = 0u64; for input in &tx.input { total_value += input.previous_output.value; } total_value.consensus_encode(&mut writer).unwrap(); } TxFieldSelector::OutputValue => { let mut total_value = 0u64; for output in &tx.output { total_value += output.value; } total_value.consensus_encode(&mut writer).unwrap(); } TxFieldSelector::FirstInputScriptSig => { tx.input[0].script_sig.consensus_encode(&mut writer).unwrap(); } TxFieldSelector::LastInputScriptSig => { tx.input.last().unwrap().script_sig.consensus_encode(&mut writer).unwrap(); } TxFieldSelector::FirstInputWitness => { tx.input[0].witness.consensus_encode(&mut writer).unwrap(); } TxFieldSelector::LastInputWitness => { tx.input.last().unwrap().witness.consensus_encode(&mut writer).unwrap(); } TxFieldSelector::Outputs => { tx.output.consensus_encode(&mut writer).unwrap(); } TxFieldSelector::Inputs => { tx.input.consensus_encode(&mut writer).unwrap(); } TxFieldSelector::Prevouts => { for input in &tx.input { input.previous_output.consensus_encode(&mut writer).unwrap(); } } TxFieldSelector::Sequences => { for input in &tx.input { input.sequence.consensus_encode(&mut writer).unwrap(); } } TxFieldSelector::OutputsHash => { let mut outputs_engine = sha256::HashEngine::new(); tx.output.consensus_encode(&mut outputs_engine).unwrap(); sha256::Hash::from_engine(outputs_engine).consensus_encode(&mut writer).unwrap(); } TxFieldSelector::InputsHash => { let mut inputs_engine = sha256::HashEngine::new(); tx.input.consensus_encode(&mut inputs_engine).unwrap(); sha256::Hash::from_engine(inputs_engine).consensus_encode(&mut writer).unwrap(); } TxFieldSelector::PrevoutsHash => { let mut prevouts_engine = sha256::HashEngine::new(); for input in &tx.input { input.previous_output.consensus_encode(&mut prevouts_engine).unwrap(); } sha256::Hash::from_engine(prevouts_engine).consensus_encode(&mut writer).unwrap(); } TxFieldSelector::SequencesHash => { let mut sequences_engine = sha256::HashEngine::new(); for input in &tx.input { input.sequence.consensus_encode(&mut sequences_engine).unwrap(); } sha256::Hash::from_engine(sequences_engine).consensus_encode(&mut writer).unwrap(); } TxFieldSelector::WitnessHash => { let mut witness_engine = sha256::HashEngine::new(); for input in &tx.input { input.witness.consensus_encode(&mut witness_engine).unwrap(); } sha256::Hash::from_engine(witness_engine).consensus_encode(&mut writer).unwrap(); } TxFieldSelector::Sighash => { // This is a placeholder. The actual sighash flags would need to be extracted // from the signature or context, which is not directly available here. // For a full implementation, this would involve parsing the signature. 0u32.consensus_encode(&mut writer).unwrap(); } TxFieldSelector::VersionSighash => { tx.version().consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::LocktimeSighash => { tx.lock_time().consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::InputCountSighash => { tx.input.len().consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::OutputCountSighash => { tx.output.len().consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::InputValueSighash => { let mut total_value = 0u64; for input in &tx.input { total_value += input.previous_output.value; } total_value.consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::OutputValueSighash => { let mut total_value = 0u64; for output in &tx.output { total_value += output.value; } total_value.consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::FirstInputScriptSigSighash => { tx.input[0].script_sig.consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::LastInputScriptSigSighash => { tx.input.last().unwrap().script_sig.consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::FirstInputWitnessSighash => { tx.input[0].witness.consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::LastInputWitnessSighash => { tx.input.last().unwrap().witness.consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::OutputsSighash => { tx.output.consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::InputsSighash => { tx.input.consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::PrevoutsSighash => { for input in &tx.input { input.previous_output.consensus_encode(&mut writer).unwrap(); } 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::SequencesSighash => { for input in &tx.input { input.sequence.consensus_encode(&mut writer).unwrap(); } 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::OutputsHashSighash => { let mut outputs_engine = sha256::HashEngine::new(); tx.output.consensus_encode(&mut outputs_engine).unwrap(); sha256::Hash::from_engine(outputs_engine).consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::InputsHashSighash => { let mut inputs_engine = sha256::HashEngine::new(); tx.input.consensus_encode(&mut inputs_engine).unwrap(); sha256::Hash::from_engine(inputs_engine).consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::PrevoutsHashSighash => { let mut prevouts_engine = sha256::HashEngine::new(); for input in &tx.input { input.previous_output.consensus_encode(&mut prevouts_engine).unwrap(); } sha256::Hash::from_engine(prevouts_engine).consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::SequencesHashSighash => { let mut sequences_engine = sha256::HashEngine::new(); for input in &tx.input { input.sequence.consensus_encode(&mut sequences_engine).unwrap(); } sha256::Hash::from_engine(sequences_engine).consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } TxFieldSelector::WitnessHashSighash => { let mut witness_engine = sha256::HashEngine::new(); for input in &tx.input { input.witness.consensus_encode(&mut witness_engine).unwrap(); } sha256::Hash::from_engine(witness_engine).consensus_encode(&mut writer).unwrap(); 0u32.consensus_encode(&mut writer).unwrap(); // Placeholder for sighash } } sha256::Hash::from_engine(engine) } #[cfg(test)] mod tests { use super::*; use bitcoin::transaction::Transaction; use bitcoin::Amount; use bitcoin::OutPoint; use bitcoin::ScriptBuf; use bitcoin::TxIn; use bitcoin::TxOut; use bitcoin::Witness; #[test] fn test_txhash_all() { let tx = Transaction { version: 1, lock_time: 0, input: vec![ TxIn { previous_output: OutPoint { txid: Default::default(), vout: 0 }, script_sig: ScriptBuf::new(), sequence: 0xFFFFFFFF, witness: Witness::new(), } ], output: vec![ TxOut { value: Amount::from_sat(50 * bitcoin_hashes::core::constants::COIN_VALUE), script_pubkey: ScriptBuf::new(), } ], }; let hash = txhash(&tx, TxFieldSelector::All); // Expected hash for an empty transaction with one input and one output. // This value would need to be calculated based on the actual consensus encoding. // For demonstration purposes, let's assume a placeholder value. let expected_hash: sha256::Hash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855".parse().unwrap(); assert_eq!(hash, expected_hash); } #[test] fn test_txhash_no_witness() { let tx = Transaction { version: 1, lock_time: 0, input: vec![ TxIn { previous_output: OutPoint { txid: Default::default(), vout: 0 }, script_sig: ScriptBuf::new(), sequence: 0xFFFFFFFF, witness: Witness::new(), } ], output: vec![ TxOut { value: Amount::from_sat(50 * bitcoin_hashes::core::constants::COIN_VALUE), script_pubkey: ScriptBuf::new(), } ], }; let hash = txhash(&tx, TxFieldSelector::NoWitness); // Expected hash for a transaction without witness data. let expected_hash: sha256::Hash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855".parse().unwrap(); assert_eq!(hash, expected_hash); } #[test] fn test_txhash_no_signature() { let tx = Transaction { version: 1, lock_time: 0, input: vec![ TxIn { previous_output: OutPoint { txid: Default::default(), vout: 0 }, script_sig: ScriptBuf::new(), sequence: 0xFFFFFFFF, witness: Witness::new(), } ], output: vec![ TxOut { value: Amount::from_sat(50 * bitcoin_hashes::core::constants::COIN_VALUE), script_pubkey: ScriptBuf::new(), } ], }; let hash = txhash(&tx, TxFieldSelector::NoSignature); // Expected hash for a transaction without signatures. let expected_hash: sha256::Hash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855".parse().unwrap(); assert_eq!(hash, expected_hash); } } ``` -------------------------------- ### Configure Custom Crate Registry Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/README.md Set up a custom Cargo configuration to use a specific crate registry for P2MR/PQC enabled Bitcoin crates. This is a temporary measure until crates are available on crates.io. ```bash mkdir .cargo \ && echo '[registries.kellnr-denver-space] index = "sparse+https://crates.denver.space/api/v1/crates/"' > .cargo/config ``` -------------------------------- ### Check for ASan Static Linking Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc Verify that the AddressSanitizer library is statically linked to the bench_bitcoin executable. This confirms ASan is active. ```bash nm build/bin/bench_bitcoin | grep asan | more ``` -------------------------------- ### P2MR Witness Program Creation Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/development_notes.adoc Details functions for creating a new V3 witness program for P2MR using only a merkle root. ```APIDOC ## Witness Program New p2mr related functions that allow for creation of a new V3 _witness program_ given a merkle_root only. ### Functions - **new_p2mr(program: [u8; 32])**: Creates a [`WitnessProgram`] from a 32-byte merkle root. Sets the version to `WitnessVersion::V3`. - **p2mr(merkle_root: Option)**: Creates a pay to quantum resistant hash address from a merkle root. Unwraps the Option and uses `WitnessProgram::new_p2mr`. ``` -------------------------------- ### Test b-cli Network Info Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-signet-workshop.adoc Verify the connection to the workshop's Signet node by retrieving network information using the `b-cli` utility. ```bash b-cli getnetworkinfo ``` -------------------------------- ### Configure Bitcoin CLI Alias Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-end-to-end.adoc Sets up an alias for the `bitcoin-cli` command to connect to a customized Bitcoin Core node. Ensure the IP address and port match your running node configuration. ```bash alias b-cli='docker run --rm --network host bitcoin-cli:p2mr-pqc-0.0.1 -rpcconnect=192.168.122.1 -rpcport=18443 -rpcuser=regtest -rpcpassword=regtest' ``` -------------------------------- ### Define Tap Tree Parameters Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2tr-end-to-end.adoc Set environment variables for the total number of leaves and the specific leaf to be used for spending in the tap tree. ```bash export TOTAL_LEAF_COUNT=5 \ && export LEAF_TO_SPEND_FROM=4 ``` -------------------------------- ### Compile Bitcoin Core with LDFLAGS Source: https://github.com/bitcoin/bips/blob/master/bip-0054/test_vectors/README.md Use this command to compile Bitcoin Core, explicitly linking to libatomic if necessary for header and block miners. ```bash cmake -B atomicbuild -DAPPEND_LDFLAGS="-latomic" cmake --build atomicbuild/ -j $(nproc) ``` -------------------------------- ### Taproot Output Script Construction (Python) Source: https://context7.com/bitcoin/bips/llms.txt Computes the Taproot output script, which includes the Tapscript version byte and the tweaked public key. Handles cases with and without a script tree. ```python def taproot_output_script(internal_pubkey, script_tree): """Compute the Taproot output script from internal key and script tree.""" if script_tree is None: h = bytes() else: _, h = taproot_tree_helper(script_tree) _, output_pubkey = taproot_tweak_pubkey(internal_pubkey, h) return bytes([0x51, 0x20]) + output_pubkey ``` -------------------------------- ### Generate P2MR ScriptPubKey with Multi-Leaf TapTree Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-signet-workshop.adoc Construct a P2MR scriptPubKey using a multi-leaf TapTree. This command leverages the reference implementation to generate the necessary information, including a BIP350 address. The output is expected to be JSON. ```bash export BITCOIN_ADDRESS_INFO=$( cargo run --example p2mr_construction ) \ && echo $BITCOIN_ADDRESS_INFO | jq -r . ``` -------------------------------- ### Generate Blocks (Regtest) Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-end-to-end.adoc Generate 110 blocks on the regtest network. This is necessary to avoid 'premature spend of coinbase' errors when spending. ```bash b-cli -generate 110 ``` -------------------------------- ### Display b-cli Alias Definition Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/p2mr-signet-workshop.adoc View the definition of the `b-cli` alias, which is pre-configured to interact with the workshop's Signet Bitcoin node. ```bash declare -f b-cli ``` -------------------------------- ### p2mrScriptBuf Struct and Implementation Source: https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/rust/docs/development_notes.adoc Provides functionality to create a P2MR scriptPubKey UTXO using only the merkle root. Keypath spend is disabled, so only the merkle root is accepted. Use `new_p2mr` to construct the script. ```rust /// A wrapper around ScriptBuf for p2mr (Pay to Quantum Resistant Hash) scripts. pub struct p2mrScriptBuf { inner: ScriptBuf } impl p2mrScriptBuf { /// Creates a new p2mr script from a ScriptBuf. pub fn new(inner: ScriptBuf) -> Self { Self { inner } } /// Generates p2mr scriptPubKey output /// Only accepts the merkle_root (of type TapNodeHash) /// since keypath spend is disabled in p2mr pub fn new_p2mr(merkle_root: TapNodeHash) -> Self { // https://github.com/cryptoquick/bips/blob/p2mr/bip-0360.mediawiki#scriptpubkey let merkle_root_hash_bytes: [u8; 32] = merkle_root.to_byte_array(); let script = Builder::new() .push_opcode(OP_PUSHNUM_3) // automatically pre-fixes with OP_PUSHBYTES_32 (as per size of hash) .push_slice(&merkle_root_hash_bytes) .into_script(); p2mrScriptBuf::new(script) } /// Returns the script as a reference. pub fn as_script(&self) -> &Script { self.inner.as_script() } } ```