From 1fa248506e2bedd7ecf8f04d1784e63147f5c181 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Fri, 27 Sep 2024 10:05:14 -0600 Subject: [PATCH 001/131] QuBit - P2QRH spending rules - Final draft before submitting upstream to bitcoin/bips --- bip-p2qrh.mediawiki | 240 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 bip-p2qrh.mediawiki diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki new file mode 100644 index 0000000000..c03e13ec28 --- /dev/null +++ b/bip-p2qrh.mediawiki @@ -0,0 +1,240 @@ +
+  BIP: TBD
+  Title: QuBit - P2QRH spending rules
+  Author: Hunter Beast 
+  Comments-Summary: No comments yet.
+  Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-TBD
+  Status: Draft
+  Type: Standards Track
+  License: BSD-3-Clause
+  Created: 2024-06-08
+
+ +== Introduction == + +=== Abstract === + +This document proposes a new SegWit output type, with spending rules based initially-- but not solely-- upon FALCON signatures. (For more on why, see the Rationale and Security sections.) A constraint is that no hard fork or increase in block size are necessary. This document is inspired by [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341], which introduced the design of the P2TR (Taproot) address type using Schnorr signatures. + + +=== Copyright === + +This document is licensed under the 3-clause BSD license. + + +=== Motivation === + +This proposal aims to improve the quantum resistance of bitcoin's signature security should the Discrete Logarithm Problem (DLP) which secures Elliptic Curve Cryptography (ECC) no longer prove to be computationally hard, likely through quantum advantage by Cryptographically-Relevant Quantum Computers (CRQCs). [https://arxiv.org/pdf/quant-ph/0301141 A variant of Shor's algorithm] is believed to be capable of deriving the private key from a public key exponentially faster than classical means. The application of this variant of Shor's algorithm is herein referred to as quantum key decryption. Note that doubling the public key length, such as with a hypothetical secp512k1 curve, would only make deriving the private key twice as hard. The computational complexity of this is investigated further in the paper, [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault tolerant regime'']. + +Mining may one day be vulnerable to disruption by very advanced quantum computers making use of Grover's algorithm. However, Grover's [https://arxiv.org/pdf/1902.02332 scales very poorly] compared to Shor's, requiring 10^40 quantum operations in comparison to 10^8 for running Shor's over ECC. It's for this reason that the primary threat to Bitcoin by quantum computers is to its signature algorithm and not Proof of Work, hence the focus on a new address format. + +The vulnerability of existing bitcoin addresses is investigated in [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the bitcoin supply is held within addresses vulnerable to quantum attack. + +Ordinarily, when a transaction is signed, the public key can be recovered from the signature. This makes a transaction submitted to the mempool vulnerable to quantum attack until it's mined. One way to mitigate this is to submit the transaction directly to a mining pool, which bypasses the mempool. This process is known as an out-of-band transaction. The mining pool must be trusted not to reveal the key to attackers. + +It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) address type that relies on a post-quantum cryptographic (PQC) signature algorithm. This new address type protects transactions submitted to the mempool and helps preserve the free market by reducing the need for private, out-of-band mempool transactions. + +The following table is non-exhaustive, but meant to inform the average bitcoin user whether their bitcoin is vulnerable to quantum attack. + +{| +|+ Vulnerable address types +|- +! Address type !! Vulnerable !! Prefix !! Example +|- +| P2PK || Yes || 04 || 0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee +|- +| P2PKH || No || 1 || 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa +|- +| P2WPKH || No || bc1q || bc1qsnh5ktku9ztqeqfr89yrqjd05eh58nah884mku +|- +| P2TR || Yes || bc1p || bc1p92aslsnseq786wxfk3ekra90ds9ku47qttupfjsqmmj4z82xdq4q3rr58u +|} + +It should be noted that Taproot addresses are vulnerable in that they encode a 32-byte x-only public key, from which a full public key can be reconstructed. + +Should quantum advantage manifest, a convention is proposed in spending the full 65-byte P2PK key used by the coinbase output in Block 1 back to itself. It is proposed to call this the [https://mempool.space/address/0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee Canary address]. The reasoning behind this is that this can only be done by Satoshi, and given his absence, this can only be spent by others if there is a significant vulnerability in secp256k1. Should the Canary coins move, that will signal that bitcoin is presently vulnerable. Without the Canary, or an address like it, there may be some doubt as to whether the coins were moved with keys belonging to the original owner. + +As an interesting aside, coinbase outputs to P2PK keys go as far as block 200,000, so it's possible there are between 1-2 million coins that are vulnerable from the first epoch. These coins can be considered "Satoshi's Shield." Any addresses with a balance of less than the original block subsidy of 50 coins can be considered incentive incompatible to capture until all of these are mined. + +It's for this reason that, for those who wish to be prepared for quantum emergency, it is recommended that no more than 50 bitcoin are kept under a single distinct, unused Native SegWit (P2WPKH, "bc1q") address at a time. This is assuming that the attacker is financially-motivated instead of, for example, a nation state looking to break confidence in Bitcoin. Additionally, this assumes that other vulnerable targets such as central banks have upgraded their cryptography already. + +The Commercial National Security Algorithm Suite (CNSA) 2.0 has a timeline for software and networking equipment to be upgraded by 2030, with browsers and operating systems fully upgraded by 2033. + +Lastly, it is worth noting by way of comparison that [https://ethresear.ch/t/how-to-hard-fork-to-save-most-users-funds-in-a-quantum-emergency/18901 Vitalik Buterin's proposed solution] in an Ethereum quantum emergency is quite different from the approach in this BIP. His plan involves a hard fork of the chain, reverting all blocks after a sufficient amount of theft, and using STARKs based on BIP-32 seeds to act as the authoritative secret when signing. These measures are deemed far too heavy-handed for bitcoin. + + +=== Rationale === + +This is the first in a series of BIPs under a QuBit soft fork. A qubit is a fundamental unit of quantum computing, and the capital B represents its connection to bitcoin. The name QuBit also rhymes to some extent with SegWit. + +It is proposed to use SegWit version 3. This results in addresses that start with bc1r, which could be a useful way to remember that these are [r]esistant addresses, similar to how bc1q corresponds to Se[q]Wit and bc1p corresponds to Ta[p]root. This is referencing the lookup table under [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. + +The proposal above also leaves a gap in case it makes sense to use version 2, or bc1z, for implementation of other address formats such as those that employ Cross Input Signature Aggregation (CISA). + +P2QRH is meant to be implemented on top of P2TR, combining the security of classical Schnorr signatures along with post-quantum cryptography. This is a form of "hybrid cryptography" such that no regression in security is presented should a vulnerability exist in one of the signature algorithms used. One key distinction between P2QRH and P2TR however is that P2QRH will encode a hash of the public key. This is a significant change in how Taproot works, but is necessary to avoid exposing public keys on-chain in advance of attackers. + +P2QRH uses a 32-byte HASH256 (specifically SHA-256 twice-over, which is similar to that used in [https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#specification BIP-16]) of the public key to reduce the size of new outputs and also to increase security by not having the public key available on-chain. This hash serves as a minimal cryptographic commitment to a public key. It goes into the output spend script, which does not receive the witness discount. + +Not having public keys exposed on-chain is an important step for quantum security. Otherwise funds would need to be spent to new addresses on a regular basis in order to prevent the possibility of a "long-range CRQC attack" recovering the key behind high value addresses. A long-range quantum attack can be considered one performed with chain data, such as that from a used address or one encoded in a spend script. A "short-range quantum attack" would be one done on keys in the mempool, which is seen as impractical given transaction throughput and block time. As the value being sent increases, so too should the fee in order to commit the transaction to the chain as soon as possible. This makes useless the public key revealed by spending a UTXO, so long as it is never reused. + +Post-quantum public keys are generally larger than those used by ECC, depending on the security level. To promote user adoption and general user-friendliness, the most secure variant (NIST V, 256 bit) is proposed, despite the increase in key length and verification time. + +Support for FALCON signatures will be introduced first, with the intention of adding SQIsign and other post-quantum algorithms as they are approved. By way of comparison, FALCON signatures are roughly 4x larger than SQIsign signatures and 20x larger than Schnorr signatures. FALCON is a more conservative approach to applied lattice cryptography than SQIsign, and its use has recently been approved by NIST. NIST approval streamlines implementations through establishing consensus in the scientific and developer community. However, even SQIsign signatures are roughly 5x larger than Schnorr signatures. This means, to maintain present transaction throughput, an increase in the witness discount will likely be desired in a QuBit soft fork. That will be specified in a future QuBit BIP. + +An increase in the witness discount must not be taken lightly. It must be resistant to applications that might take advantage of this discount (e.g. storage of arbitrary data as seen with "inscriptions") without a corresponding increase in economic activity. Such an increase would not only impact node runners but those with inscriptions would also have the scarcity of their non-monetary assets affected. The only way to prevent this while also increasing the discount is to have a completely separate witness, a quantum witness, or "quitness," that is solely responsible for providing post-quantum signatures. + +To address the risk of arbitrary data being stored using P2QRH (QuBit) addresses, very specific rules will be applied to spending from the witness stack in SegWit v3 outputs. A fixed signature size will be necessary for spending the output, and the output must be spendable to be considered valid within node consensus. A fixed signature size will also be helpful to disambiguate between signature types without an additional version byte, as SQIsign signatures are substantially smaller than FALCON signatures. Consequently, the correct signature algorithm can be inferred through byte length. The public key and signature will be pushed separately to the quitness stack. Multiple signatures can be included in order to support multisig applications, and also for spending multiple inputs. + +Since only valid signatures can be committed to in a SegWit v3 quitness, arbitrary data cannot be added by miners, as that would affect the consensus of their block. A CRQC operator is economically disincentivized from computing a spendable public key that matched arbitrary signature data due to the cost of that computation. That is because the cost of such a computation could prove quite substantial, rather than simply putting the arbitrary data within a Taproot witness. Doing the work to meet the requirement for it to be consensus-valid data would prove cost-prohibitive. + +Additionally, it should be noted, whether an output with a P2QRH spend script corresponds to a FALCON or SQIsign signature is not known until the output is spent. + +While it might be seen as a maintenance burden for bitcoin ecosystem devs to go from a single cryptosystem implementation to two distinct cryptosystems-- and it most certainly is-- the ramifications of a chain broken through extrinsic factors should provide sufficient motivation. An increase in software maintenance everywhere signatures are used should be seen as an acceptable compromise for maintained integrity of bitcoin transfers during a regime of quantum advantage. + +In the distant future, following the implementation of the P2QRH address format in a QuBit soft fork, there will likely be a need for Pay to Quantum Secure (P2QS) addresses. These will require specialized quantum hardware for signing, while still [https://quantum-journal.org/papers/q-2023-01-19-901/ using public keys that are verifiable via classical means]. Additional follow-on BIPs will be needed to implement P2QS. However, until specialized quantum cryptography hardware is widespread, quantum resistant addresses should be an adequate intermediate solution. + + +== Description == + +We first build up a definition of the signature scheme by going through the design choices. Afterwards, we specify the exact encodings and operations. + + +=== Design === + +For P2QRH descriptors, qrh() should be used. + +> Further specific details to be completed later in the draft process as outlined in [https://github.com/bitcoin/bips/blob/master/bip-0002.mediawiki BIP-2] + + +== Security == + +{| +|+ Proposed quantum resistant signature algorithms ordered by largest to smallest signature size, NIST I +|- +! Signature algorithm !! Year first introduced !! Signature size, NIST I !! Public key size, NIST I +|- +| [https://sphincs.org/data/sphincs+-r3.1-specification.pdf SPHINCS+ Rd. 3.1 (FIPS 205 - SLH-DSA)] || 2015 || 7856 bytes || 32 bytes +|- +| [https://pq-crystals.org/dilithium/ CRYSTALS-Dilithium (FIPS 204 - ML-DSA)] || 2017 || 2420 bytes || 1312 bytes +|- +| [https://eprint.iacr.org/2014/457.pdf pqNTRUsign] || 2016 || 702 bytes || 752 bytes +|- +| [https://falcon-sign.info FALCON (FIPS 206 - FN-DSA)] || 2017 || 666 bytes || 897 bytes +|- +| [https://eprint.iacr.org/2022/1155.pdf HAWK] || 2022 || 652 bytes || 1006 bytes +|- +| [https://sqisign.org SQIsign] || 2023 || 177 bytes || 64 bytes +|- +| [https://eprint.iacr.org/2024/760.pdf SQIsign2D-West] || 2024 || 148 bytes || 66 bytes +|- +| [https://link.springer.com/content/pdf/10.1007/978-3-031-58716-0_1.pdf SQIsignHD] || 2024 || 109 bytes || not provided +|} + +{| +|+ Proposed quantum resistant signature algorithms ordered by largest to smallest signature size, NIST V +|- +! Signature algorithm !! Year first introduced !! Signature size, NIST V !! Public key size, NIST V +|- +| Lamport signature || 1977 || 8192 bytes || 16384 bytes +|- +| SPHINCS+ Rd. 3.1 (FIPS 205 - SLH-DSA) || 2015 || 29792 bytes || 64 bytes +|- +| CRYSTALS-Dilithium (FIPS 204 - ML-DSA) || 2017 || 4595 bytes || 2592 bytes +|- +| pqNTRUsign || 2016 || 1814 bytes || 1927 bytes +|- +| FALCON (FIPS 206 - FN-DSA) || 2017 || 1280 bytes || 1793 bytes +|- +| HAWK || 2022 || 1261 bytes || 2329 bytes +|- +| SQIsign || 2023 || 335 bytes || 128 bytes +|- +| SQIsign2D-West || 2024 || 294 bytes || 130 bytes +|- +| SQIsignHD || 2023 || not provided || not provided +|} + +As shown, supersingular elliptic curve quaternion isogeny signature algorithms represent the state of the art in post-quantum cryptography, beyond lattice cryptography alone, especially when key and signature length are major constraints. This makes inclusion of SQIsign attractive, and support is planned, but it will be some time until it is approved for production use. Meanwhile, FALCON signatures are already approved and have achieved broader community consensus. + +In comparison, the size of currently used signature algorithms are: + +* ECDSA - 70-72 bytes +* Schnorr - 64 bytes + +In comparison to year, secp256k1 [https://www.secg.org/SEC1-Ver-1.0.pdf was originally specified in 2000]. + +One consideration for choosing an algorithm is its maturity. secp256k1 was already 8 years old by the time it was chosen as bitcoin's curve. Isogeny cryptography when it was first introduced was broken over a weekend. + +Ideally SQIsign also proves to be flexible enough to support [https://www.pierrickdartois.fr/homepage/wp-content/uploads/2022/04/Report_OSIDH_DARTOIS.pdf Isogeny Diffie-Hellman] to replace ECDH applications, and also provide methods for the key tweaking necessary to support TapScript for P2QR addresses. Additionally, isogeny-based post-quantum cryptography is based on higher-order elliptic curves, and so it might be possible to implement Isogeny Schnorr signatures. + +Signature verification speed as it compares to Schnorr or ECDSA isn't seen as high a consideration as signature size due to block space being the primary fee constraint. As a P2QRH implementation materializes, a benchmark will be added for performance comparison. Fortunately, SQIsign signatures are substantially faster to verify than it is to generate keys or to sign, which is a major consideration when a transaction need only be signed once, or a handful of times with PSBT, compared to being verified simultaneously on tens of thousands of nodes. Key generation may need to cached in [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32 HD wallets]. + +An additional consideration is security levels. Longer signature sizes provide more security. NIST has standardized five security levels for post-quantum cryptography. NIST security level I provides security equivalent to 128-bit keys, and security level V provides 256-bit security. + + +== Specification == + +How the quitness is differentiated from the witness can be accomplished similar to how [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#user-content-Transaction_ID BIP-141] introduced the marker and flag, with the QuBit flag being set to 0x02. This means all QuBit transactions are also SegWit transactions. The additional data would be included as a second array of byte arrays following the witness stack. + +The new transaction serialization format would be as follows: + + [nVersion][marker][flag][txins][txouts][witness][quitness][nLockTime] + +WIP + +=== Public Key Generation === + +TBD, pending test vectors + +=== Public Key Conversion === + +TBD + +=== Default Signing === + +TBD + +=== Alternative Signing === + +TBD + +=== Verification === + +TBD + +=== Batch Verification === + +TBD + +=== Usage Considerations === + +TBD + +== Test Vectors and Reference Code == + +TBD + + +== References == + +* [https://groups.google.com/g/bitcoindev/c/Aee8xKuIC2s/m/cu6xej1mBQAJ Mailing list discussion] +* [https://delvingbitcoin.org/t/proposing-a-p2qrh-bip-towards-a-quantum-resistant-soft-fork/956?u=cryptoquick Delving Bitcoin discussion] +* [https://bitcoinops.org/en/newsletters/2024/06/14/ Bitcoin OpTech newsletter] +* [https://bitcoinops.org/en/podcast/2024/06/18/#draft-bip-for-quantum-safe-address-format Bitcoin OpTech discussion transcript] + + + + +== Changelog == + +To help implementors understand updates to this BIP, we keep a list of substantial changes. + +* 2024-06: High level rough draft +* 2024-07: Additional algorithms in PQC table +* 2024-08: Add FALCON signatures, update to use NIST standard terminology, add public key sizes. +* 2024-09: Additional detail on P2QS. Deprecate P2QR. Postpone SQIsign. Add details on quitness. + + +== Acknowledgements == + +Much gratitude to my co-founder, Kyle Crews for proofreading and editing, and to David Croisant. who suggested the name "QuBit." Thank you as well to those who took the time to review and contribute, including Adam Borcany, Antoine Riard, and Pierre-Luc Dallaire-Demers. From 6f67a3d6860921bf869404e14239581c139ff69d Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Fri, 27 Sep 2024 10:23:41 -0600 Subject: [PATCH 002/131] Add pqNTRUsign to .typos.toml. --- .typos.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/.typos.toml b/.typos.toml index 15d831fa1e..4f9fbef9af 100644 --- a/.typos.toml +++ b/.typos.toml @@ -15,6 +15,7 @@ extend-ignore-re = [ "ser.*", "prefix.*", "value: .*", + "pqNTRUsign", ] [default.extend-words] From d83c29d59b78443e20a040395ca23777bfc332f1 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Sat, 28 Sep 2024 11:57:31 -0600 Subject: [PATCH 003/131] QuBit - P2QRH --- bip-p2qrh.mediawiki | 131 +++++++++++++++++++++++++++----------------- 1 file changed, 81 insertions(+), 50 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index c03e13ec28..4d94886509 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -26,11 +26,13 @@ This document is licensed under the 3-clause BSD license. This proposal aims to improve the quantum resistance of bitcoin's signature security should the Discrete Logarithm Problem (DLP) which secures Elliptic Curve Cryptography (ECC) no longer prove to be computationally hard, likely through quantum advantage by Cryptographically-Relevant Quantum Computers (CRQCs). [https://arxiv.org/pdf/quant-ph/0301141 A variant of Shor's algorithm] is believed to be capable of deriving the private key from a public key exponentially faster than classical means. The application of this variant of Shor's algorithm is herein referred to as quantum key decryption. Note that doubling the public key length, such as with a hypothetical secp512k1 curve, would only make deriving the private key twice as hard. The computational complexity of this is investigated further in the paper, [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault tolerant regime'']. -Mining may one day be vulnerable to disruption by very advanced quantum computers making use of Grover's algorithm. However, Grover's [https://arxiv.org/pdf/1902.02332 scales very poorly] compared to Shor's, requiring 10^40 quantum operations in comparison to 10^8 for running Shor's over ECC. It's for this reason that the primary threat to Bitcoin by quantum computers is to its signature algorithm and not Proof of Work, hence the focus on a new address format. +The primary threat to Bitcoin by CRQCs is [https://en.bitcoin.it/wiki/Quantum_computing_and_Bitcoin#QC_attacks generally considered to be to its uses of ECC used in signatures and Taproot commitments], hence the focus on a new address format. This is because Shor's algorithm enables a CRQC to break the cryptographic assumptions of ECC in roughly 10^8 quantum operations. While a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a quadratic speed up on brute force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes using Grover's algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques post on this]. -The vulnerability of existing bitcoin addresses is investigated in [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the bitcoin supply is held within addresses vulnerable to quantum attack. +The vulnerability of existing bitcoin addresses is investigated in [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the bitcoin supply is held within addresses vulnerable to quantum attack. As of the time of writing, that number is now closer to 20%. Additionally, Peter Wuille estimates even more might be vulnerable, for the reasons provided [https://x.com/pwuille/status/1108085284862713856 here]. -Ordinarily, when a transaction is signed, the public key can be recovered from the signature. This makes a transaction submitted to the mempool vulnerable to quantum attack until it's mined. One way to mitigate this is to submit the transaction directly to a mining pool, which bypasses the mempool. This process is known as an out-of-band transaction. The mining pool must be trusted not to reveal the key to attackers. +Ordinarily, when a transaction is signed, the public key can be recovered from the signature. This makes a transaction submitted to the mempool vulnerable to quantum attack until it's mined. One way to mitigate this is to submit the transaction directly to a mining pool, which bypasses the mempool. This process is known as an out-of-band transaction. The mining pool must be trusted not to reveal the transaction public key to attackers. + +Not having public keys exposed on-chain is an important step for quantum security. Otherwise funds would need to be spent to new addresses on a regular basis in order to prevent the possibility of a "long-range CRQC attack" recovering the key behind high value addresses. A long-range quantum attack can be considered one performed with chain data, such as that from a used address or one encoded in a spend script. A "short-range quantum attack" would be one done on keys in the mempool, which is seen as impractical given transaction throughput and block time. As the value being sent increases, so too should the fee in order to commit the transaction to the chain as soon as possible. This makes useless the public key revealed by spending a UTXO, so long as it is never reused. It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) address type that relies on a post-quantum cryptographic (PQC) signature algorithm. This new address type protects transactions submitted to the mempool and helps preserve the free market by reducing the need for private, out-of-band mempool transactions. @@ -52,6 +54,28 @@ The following table is non-exhaustive, but meant to inform the average bitcoin u It should be noted that Taproot addresses are vulnerable in that they encode a 32-byte x-only public key, from which a full public key can be reconstructed. +If a key is recovered by a CRQC, it can also be trivially checked to see if any child keys were produced using an unhardened [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32] derivation path. + +The following table summarizes the scenarios in which public keys are revealed when using Bitcoin, and what type of attack they're vulnerable to: + +{| +|+ Scenarios for revealed public keys on Bitcoin +|- +! Scenario !! Type of attack +|- +| Early addresses (Satoshi's coins, CPU miners, starts with 04) || Long-range +|- +| Reused addresses (any type, except bc1r) || Long-range +|- +| Taproot addresses (starts with bc1p) || Long-range +|- +| Any transaction in the mempool (except for bc1r) || Short-range +|- +| Unhardened BIP-32 HD wallet keys || Both Long-range or Short-range +|} + +The only time a short-range attack can occur is when the transaction is in the mempool, whereas long-range attacks are when the public key is known well in advance. Short-range attacks require much larger, more expensive CRQCs. + Should quantum advantage manifest, a convention is proposed in spending the full 65-byte P2PK key used by the coinbase output in Block 1 back to itself. It is proposed to call this the [https://mempool.space/address/0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee Canary address]. The reasoning behind this is that this can only be done by Satoshi, and given his absence, this can only be spent by others if there is a significant vulnerability in secp256k1. Should the Canary coins move, that will signal that bitcoin is presently vulnerable. Without the Canary, or an address like it, there may be some doubt as to whether the coins were moved with keys belonging to the original owner. As an interesting aside, coinbase outputs to P2PK keys go as far as block 200,000, so it's possible there are between 1-2 million coins that are vulnerable from the first epoch. These coins can be considered "Satoshi's Shield." Any addresses with a balance of less than the original block subsidy of 50 coins can be considered incentive incompatible to capture until all of these are mined. @@ -75,21 +99,21 @@ P2QRH is meant to be implemented on top of P2TR, combining the security of class P2QRH uses a 32-byte HASH256 (specifically SHA-256 twice-over, which is similar to that used in [https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#specification BIP-16]) of the public key to reduce the size of new outputs and also to increase security by not having the public key available on-chain. This hash serves as a minimal cryptographic commitment to a public key. It goes into the output spend script, which does not receive the witness discount. -Not having public keys exposed on-chain is an important step for quantum security. Otherwise funds would need to be spent to new addresses on a regular basis in order to prevent the possibility of a "long-range CRQC attack" recovering the key behind high value addresses. A long-range quantum attack can be considered one performed with chain data, such as that from a used address or one encoded in a spend script. A "short-range quantum attack" would be one done on keys in the mempool, which is seen as impractical given transaction throughput and block time. As the value being sent increases, so too should the fee in order to commit the transaction to the chain as soon as possible. This makes useless the public key revealed by spending a UTXO, so long as it is never reused. - Post-quantum public keys are generally larger than those used by ECC, depending on the security level. To promote user adoption and general user-friendliness, the most secure variant (NIST V, 256 bit) is proposed, despite the increase in key length and verification time. Support for FALCON signatures will be introduced first, with the intention of adding SQIsign and other post-quantum algorithms as they are approved. By way of comparison, FALCON signatures are roughly 4x larger than SQIsign signatures and 20x larger than Schnorr signatures. FALCON is a more conservative approach to applied lattice cryptography than SQIsign, and its use has recently been approved by NIST. NIST approval streamlines implementations through establishing consensus in the scientific and developer community. However, even SQIsign signatures are roughly 5x larger than Schnorr signatures. This means, to maintain present transaction throughput, an increase in the witness discount will likely be desired in a QuBit soft fork. That will be specified in a future QuBit BIP. -An increase in the witness discount must not be taken lightly. It must be resistant to applications that might take advantage of this discount (e.g. storage of arbitrary data as seen with "inscriptions") without a corresponding increase in economic activity. Such an increase would not only impact node runners but those with inscriptions would also have the scarcity of their non-monetary assets affected. The only way to prevent this while also increasing the discount is to have a completely separate witness, a quantum witness, or "quitness," that is solely responsible for providing post-quantum signatures. +An increase in the witness discount must not be taken lightly. It must be resistant to applications that might take advantage of this discount (e.g. storage of arbitrary data as seen with "inscriptions") without a corresponding increase in economic activity. Such an increase would not only impact node runners but those with inscriptions would also have the scarcity of their non-monetary assets affected. The only way to prevent this while also increasing the discount is to have a completely separate witness, a "quantum witness". Because it is meant only for public keys and signatures, we call this section of the transaction the attestation. -To address the risk of arbitrary data being stored using P2QRH (QuBit) addresses, very specific rules will be applied to spending from the witness stack in SegWit v3 outputs. A fixed signature size will be necessary for spending the output, and the output must be spendable to be considered valid within node consensus. A fixed signature size will also be helpful to disambiguate between signature types without an additional version byte, as SQIsign signatures are substantially smaller than FALCON signatures. Consequently, the correct signature algorithm can be inferred through byte length. The public key and signature will be pushed separately to the quitness stack. Multiple signatures can be included in order to support multisig applications, and also for spending multiple inputs. +To address the risk of arbitrary data being stored using P2QRH (QuBit) addresses, very specific rules will be applied to spending from the witness stack in SegWit v3 outputs. A fixed signature size will be necessary for spending the output, and the output must be spendable to be considered valid within node consensus. A fixed signature size will also be helpful to disambiguate between signature types without an additional version byte, as SQIsign signatures are substantially smaller than FALCON signatures. Consequently, the correct signature algorithm can be inferred through byte length. The public key and signature will be pushed separately to the attestation stack. Multiple signatures can be included in order to support multisig applications, and also for spending multiple inputs. -Since only valid signatures can be committed to in a SegWit v3 quitness, arbitrary data cannot be added by miners, as that would affect the consensus of their block. A CRQC operator is economically disincentivized from computing a spendable public key that matched arbitrary signature data due to the cost of that computation. That is because the cost of such a computation could prove quite substantial, rather than simply putting the arbitrary data within a Taproot witness. Doing the work to meet the requirement for it to be consensus-valid data would prove cost-prohibitive. +Since only valid signatures can be committed to in a SegWit v3 attestation, arbitrary data cannot be added by miners, as that would affect the consensus of their block. A CRQC operator is economically disincentivized from computing a spendable public key that matched arbitrary signature data due to the cost of that computation. That is because the cost of such a computation could prove quite substantial, rather than simply putting the arbitrary data within a Taproot witness. Doing the work to meet the requirement for it to be consensus-valid data would prove cost-prohibitive. Additionally, it should be noted, whether an output with a P2QRH spend script corresponds to a FALCON or SQIsign signature is not known until the output is spent. -While it might be seen as a maintenance burden for bitcoin ecosystem devs to go from a single cryptosystem implementation to two distinct cryptosystems-- and it most certainly is-- the ramifications of a chain broken through extrinsic factors should provide sufficient motivation. An increase in software maintenance everywhere signatures are used should be seen as an acceptable compromise for maintained integrity of bitcoin transfers during a regime of quantum advantage. +While it might be seen as a maintenance burden for bitcoin ecosystem devs to go from a single cryptosystem implementation to four additional distinct PQC cryptosystems-- and it most certainly is-- the ramifications of a chain broken through extrinsic factors should provide sufficient motivation. An increase in software maintenance everywhere signatures are used should be seen as an acceptable compromise for maintained integrity of bitcoin transfers during a regime of quantum advantage. + +The inclusion of these four cryptosystems: SPHINCS, XMSS, FALCON, and SQIsign have various advocates within the community due to their varying security assumptions. Hash-based cryptosystems are more conservative, time-tested, and well-reviewed. Lattice cryptography is relatively new and introduces novel security assumptions to Bitcoin, but their signatures are smaller and might be considered by some to be an adequate alternative to Hash-based signatures. SQIsign is much smaller, however, it is based on a very novel form of cryptography known as supersingular elliptic curve quaternion isogeny, and at the time of writing, is not yet approved by NIST or the broader PQC community. In the distant future, following the implementation of the P2QRH address format in a QuBit soft fork, there will likely be a need for Pay to Quantum Secure (P2QS) addresses. These will require specialized quantum hardware for signing, while still [https://quantum-journal.org/papers/q-2023-01-19-901/ using public keys that are verifiable via classical means]. Additional follow-on BIPs will be needed to implement P2QS. However, until specialized quantum cryptography hardware is widespread, quantum resistant addresses should be an adequate intermediate solution. @@ -109,51 +133,35 @@ For P2QRH descriptors, qrh() should be used. == Security == {| -|+ Proposed quantum resistant signature algorithms ordered by largest to smallest signature size, NIST I +|+ Proposed quantum resistant signature algorithms ordered by largest to smallest NIST V signature size |- -! Signature algorithm !! Year first introduced !! Signature size, NIST I !! Public key size, NIST I +! Signature Algorithm !! Year First Introduced !! Signature Size !! Public Key Size || Cryptographic Assumptions |- -| [https://sphincs.org/data/sphincs+-r3.1-specification.pdf SPHINCS+ Rd. 3.1 (FIPS 205 - SLH-DSA)] || 2015 || 7856 bytes || 32 bytes +| [https://en.wikipedia.org/wiki/Lamport_signature Lamport signature] || 1977 || 8192 bytes || 16384 bytes || Hash-based cryptography |- -| [https://pq-crystals.org/dilithium/ CRYSTALS-Dilithium (FIPS 204 - ML-DSA)] || 2017 || 2420 bytes || 1312 bytes +| [https://eprint.iacr.org/2011/191.pdf Winternitz signature] || 1982 || 2368 bytes* || 2368 bytesFootnote: Winternitz signatures are much smaller than Lamport signatures due to efficient chunking, but computation is much higher, especially with high values for w. Winternitz values are for w of 4. || Hash-based cryptography |- -| [https://eprint.iacr.org/2014/457.pdf pqNTRUsign] || 2016 || 702 bytes || 752 bytes +| [https://sphincs.org/data/sphincs+-r3.1-specification.pdf SPHINCS+ Rd. 3.1 (FIPS 205 - SLH-DSA)] || 2015 || 29792 bytes || 64 bytes || Hash-based cryptography |- -| [https://falcon-sign.info FALCON (FIPS 206 - FN-DSA)] || 2017 || 666 bytes || 897 bytes +| [https://eprint.iacr.org/2011/484.pdf XMSS]XMSS, which is based on Winternitz, uses a value of 108 for its most compact signature size, with only a 4.6x (2.34/0.51) increase in verification time. Signing and key generation are not considered a significant factor because they are not distributed throughout the entire Bitcoin network, which take place only inside of wallets one time. || 2011 || 15384 bytes || 13568 bytes || Hash-based cryptography (Winternitz OTS) |- -| [https://eprint.iacr.org/2022/1155.pdf HAWK] || 2022 || 652 bytes || 1006 bytes +| [https://pq-crystals.org/dilithium/ CRYSTALS-Dilithium (FIPS 204 - ML-DSA)] || 2017 || 4595 bytes || 2592 bytes || Lattice cryptography |- -| [https://sqisign.org SQIsign] || 2023 || 177 bytes || 64 bytes +| [https://eprint.iacr.org/2014/457.pdf pqNTRUsign] || 2016 || 1814 bytes || 1927 bytes || Lattice cryptography (NTRU) |- -| [https://eprint.iacr.org/2024/760.pdf SQIsign2D-West] || 2024 || 148 bytes || 66 bytes +| [https://falcon-sign.info FALCON (FIPS 206 - FN-DSA)] || 2017 || 1280 bytes || 1793 bytes || Lattice cryptography (NTRU) |- -| [https://link.springer.com/content/pdf/10.1007/978-3-031-58716-0_1.pdf SQIsignHD] || 2024 || 109 bytes || not provided -|} - -{| -|+ Proposed quantum resistant signature algorithms ordered by largest to smallest signature size, NIST V +| [https://eprint.iacr.org/2022/1155.pdf HAWK] || 2022 || 1261 bytes || 2329 bytes || Lattice cryptography |- -! Signature algorithm !! Year first introduced !! Signature size, NIST V !! Public key size, NIST V +| [https://sqisign.org SQIsign] || 2023 || 335 bytes || 128 bytes || Supersingular Elliptic Curve Isogeny |- -| Lamport signature || 1977 || 8192 bytes || 16384 bytes +| [https://eprint.iacr.org/2024/760.pdf SQIsign2D-West] || 2024 || 294 bytes || 130 bytes || Supersingular Elliptic Curve Isogeny |- -| SPHINCS+ Rd. 3.1 (FIPS 205 - SLH-DSA) || 2015 || 29792 bytes || 64 bytes -|- -| CRYSTALS-Dilithium (FIPS 204 - ML-DSA) || 2017 || 4595 bytes || 2592 bytes -|- -| pqNTRUsign || 2016 || 1814 bytes || 1927 bytes -|- -| FALCON (FIPS 206 - FN-DSA) || 2017 || 1280 bytes || 1793 bytes -|- -| HAWK || 2022 || 1261 bytes || 2329 bytes -|- -| SQIsign || 2023 || 335 bytes || 128 bytes -|- -| SQIsign2D-West || 2024 || 294 bytes || 130 bytes -|- -| SQIsignHD || 2023 || not provided || not provided +| [https://eprint.iacr.org/2023/436.pdf SQIsignHD] || 2023 || 109 butes (NIST I) || not provided || Supersingular Elliptic Curve Isogeny |} + + As shown, supersingular elliptic curve quaternion isogeny signature algorithms represent the state of the art in post-quantum cryptography, beyond lattice cryptography alone, especially when key and signature length are major constraints. This makes inclusion of SQIsign attractive, and support is planned, but it will be some time until it is approved for production use. Meanwhile, FALCON signatures are already approved and have achieved broader community consensus. In comparison, the size of currently used signature algorithms are: @@ -167,20 +175,40 @@ One consideration for choosing an algorithm is its maturity. secp256k1 was alrea Ideally SQIsign also proves to be flexible enough to support [https://www.pierrickdartois.fr/homepage/wp-content/uploads/2022/04/Report_OSIDH_DARTOIS.pdf Isogeny Diffie-Hellman] to replace ECDH applications, and also provide methods for the key tweaking necessary to support TapScript for P2QR addresses. Additionally, isogeny-based post-quantum cryptography is based on higher-order elliptic curves, and so it might be possible to implement Isogeny Schnorr signatures. -Signature verification speed as it compares to Schnorr or ECDSA isn't seen as high a consideration as signature size due to block space being the primary fee constraint. As a P2QRH implementation materializes, a benchmark will be added for performance comparison. Fortunately, SQIsign signatures are substantially faster to verify than it is to generate keys or to sign, which is a major consideration when a transaction need only be signed once, or a handful of times with PSBT, compared to being verified simultaneously on tens of thousands of nodes. Key generation may need to cached in [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32 HD wallets]. +Signature verification speed as it compares to Schnorr or ECDSA isn't seen as high a consideration as signature size due to block space being the primary fee constraint. As a P2QRH implementation materializes, a benchmark will be added for performance comparison. Fortunately, SQIsign signatures are substantially faster to verify than it is to generate keys or to sign, which is a major consideration when a transaction need only be signed once, or a handful of times with PSBT, compared to being verified simultaneously on tens of thousands of nodes. Key generation may need to cached in BIP-32 Hierarchical Deterministic wallets. An additional consideration is security levels. Longer signature sizes provide more security. NIST has standardized five security levels for post-quantum cryptography. NIST security level I provides security equivalent to 128-bit keys, and security level V provides 256-bit security. == Specification == -How the quitness is differentiated from the witness can be accomplished similar to how [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#user-content-Transaction_ID BIP-141] introduced the marker and flag, with the QuBit flag being set to 0x02. This means all QuBit transactions are also SegWit transactions. The additional data would be included as a second array of byte arrays following the witness stack. +How the attestation is differentiated from the witness can be accomplished similar to how [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#user-content-Transaction_ID BIP-141] introduced the marker and flag, with the QuBit flag being set to 0x02. This means all QuBit transactions are also SegWit transactions. The additional data would be included as a second array of byte arrays following the witness stack. + +The new transaction serialization format is as follows: -The new transaction serialization format would be as follows: + [nVersion][marker][flag][txins][txouts][witness][attestation][nLockTime] - [nVersion][marker][flag][txins][txouts][witness][quitness][nLockTime] +QuBit spend scripts are as follows: + +* OP_PUSHNUM_3 to indicate SegWit version 3 +* OP_PUSHBYTES_32 +* HASH256 of the following bytes concatenated: + * HASH256 of the public key at attestation index 0 + * If there are more public keys: + * All public keys are hashed via HASH256 and concatenated + +In short, the new spend script serialization format is as follows: + + OP_PUSHNUM_3 HASH256([HASH256(Public Key Bytes at Attestation Index 0)][HASH256(PK Q1)][..]) + +Addresses then encode this script using bech32m. + +32-byte attestation fields are assumed to be Schnorr public keys for Taproot fields, because they are ordinarily included in the spend script, but cannot be included in P2QRH for security reasons. Public key / signature pairs for Taproot fields come before QuBit public key / signature pairs. + +Which key type is inferred by its size, as provided by the attestation varint pair, determining whether it's processed as secp256k1 Schnorr, SPHINCS, XMSS, FALCON, and SQIsign. + +If the transaction fails to include the public keys needed to match the spend script hash, it is an invalid transaction, because the cryptographic commitment for the keys has not been met. Because of this, only valid public keys and signatures can be included within the attestation, and no other data. -WIP === Public Key Generation === @@ -222,6 +250,9 @@ TBD * [https://bitcoinops.org/en/newsletters/2024/06/14/ Bitcoin OpTech newsletter] * [https://bitcoinops.org/en/podcast/2024/06/18/#draft-bip-for-quantum-safe-address-format Bitcoin OpTech discussion transcript] + +== Footnotes == + @@ -229,12 +260,12 @@ TBD To help implementors understand updates to this BIP, we keep a list of substantial changes. -* 2024-06: High level rough draft -* 2024-07: Additional algorithms in PQC table -* 2024-08: Add FALCON signatures, update to use NIST standard terminology, add public key sizes. -* 2024-09: Additional detail on P2QS. Deprecate P2QR. Postpone SQIsign. Add details on quitness. +* 2024-09-30 - Refactor the ECC vs PoW section. Swap quitness for attestation. +* 2024-09-29 - Update section on PoW to include partial-preimage. +* 2024-09-28 - Add Winternitz, XMSS signatures, and security assumption types to PQC table. Omit NIST I table. Add spend script specification. Add revealed public key scenario table. +* 2024-09-27 - Initial draft proposal == Acknowledgements == -Much gratitude to my co-founder, Kyle Crews for proofreading and editing, and to David Croisant. who suggested the name "QuBit." Thank you as well to those who took the time to review and contribute, including Adam Borcany, Antoine Riard, and Pierre-Luc Dallaire-Demers. +Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name "QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as well to those who took the time to review and contribute, including Adam Borcany, Antoine Riard, Pierre-Luc Dallaire-Demers, Ethan Heilman, and Jon Atack. From ae0936ae6f46fa12301b523c9b26dd4af9769f31 Mon Sep 17 00:00:00 2001 From: Jameson Lopp Date: Wed, 2 Oct 2024 10:30:43 -0400 Subject: [PATCH 004/131] typo fix --- bip-p2qrh.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index 4d94886509..211d1c4746 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -157,7 +157,7 @@ For P2QRH descriptors, qrh() should be used. |- | [https://eprint.iacr.org/2024/760.pdf SQIsign2D-West] || 2024 || 294 bytes || 130 bytes || Supersingular Elliptic Curve Isogeny |- -| [https://eprint.iacr.org/2023/436.pdf SQIsignHD] || 2023 || 109 butes (NIST I) || not provided || Supersingular Elliptic Curve Isogeny +| [https://eprint.iacr.org/2023/436.pdf SQIsignHD] || 2023 || 109 bytes (NIST I) || not provided || Supersingular Elliptic Curve Isogeny |} From b4c329b55b9205f78a6896ed0627228cb5baafbd Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Mon, 21 Oct 2024 10:01:30 -0600 Subject: [PATCH 005/131] QuBit - P2QRH spending rules --- bip-p2qrh.mediawiki | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index 211d1c4746..85c72e2f6b 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -113,7 +113,7 @@ Additionally, it should be noted, whether an output with a P2QRH spend script co While it might be seen as a maintenance burden for bitcoin ecosystem devs to go from a single cryptosystem implementation to four additional distinct PQC cryptosystems-- and it most certainly is-- the ramifications of a chain broken through extrinsic factors should provide sufficient motivation. An increase in software maintenance everywhere signatures are used should be seen as an acceptable compromise for maintained integrity of bitcoin transfers during a regime of quantum advantage. -The inclusion of these four cryptosystems: SPHINCS, XMSS, FALCON, and SQIsign have various advocates within the community due to their varying security assumptions. Hash-based cryptosystems are more conservative, time-tested, and well-reviewed. Lattice cryptography is relatively new and introduces novel security assumptions to Bitcoin, but their signatures are smaller and might be considered by some to be an adequate alternative to Hash-based signatures. SQIsign is much smaller, however, it is based on a very novel form of cryptography known as supersingular elliptic curve quaternion isogeny, and at the time of writing, is not yet approved by NIST or the broader PQC community. +The inclusion of these four cryptosystems: SPHINCS, CRYSTALS-Dilithium, FALCON, and SQIsign have various advocates within the community due to their varying security assumptions. Hash-based cryptosystems are more conservative, time-tested, and well-reviewed. Lattice cryptography is relatively new and introduces novel security assumptions to Bitcoin, but their signatures are smaller and might be considered by some to be an adequate alternative to Hash-based signatures. SQIsign is much smaller, however, it is based on a very novel form of cryptography known as supersingular elliptic curve quaternion isogeny, and at the time of writing, is not yet approved by NIST or the broader PQC community. In the distant future, following the implementation of the P2QRH address format in a QuBit soft fork, there will likely be a need for Pay to Quantum Secure (P2QS) addresses. These will require specialized quantum hardware for signing, while still [https://quantum-journal.org/papers/q-2023-01-19-901/ using public keys that are verifiable via classical means]. Additional follow-on BIPs will be needed to implement P2QS. However, until specialized quantum cryptography hardware is widespread, quantum resistant addresses should be an adequate intermediate solution. @@ -260,6 +260,7 @@ TBD To help implementors understand updates to this BIP, we keep a list of substantial changes. +* 2024-10-21 - Replace XMSS with CRYSTALS-Dilithium due to NIST approval and size constraints. * 2024-09-30 - Refactor the ECC vs PoW section. Swap quitness for attestation. * 2024-09-29 - Update section on PoW to include partial-preimage. * 2024-09-28 - Add Winternitz, XMSS signatures, and security assumption types to PQC table. Omit NIST I table. Add spend script specification. Add revealed public key scenario table. @@ -268,4 +269,4 @@ To help implementors understand updates to this BIP, we keep a list of substanti == Acknowledgements == -Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name "QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as well to those who took the time to review and contribute, including Adam Borcany, Antoine Riard, Pierre-Luc Dallaire-Demers, Ethan Heilman, and Jon Atack. +Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name "QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as well to those who took the time to review and contribute, including Adam Borcany, Antoine Riard, Pierre-Luc Dallaire-Demers, Ethan Heilman, Jon Atack, and Jameson Lopp. From 53d497e376f499c210bce4980e28d8f503b9a2b9 Mon Sep 17 00:00:00 2001 From: Kyle Crews Date: Tue, 5 Nov 2024 09:12:26 -0600 Subject: [PATCH 006/131] Adds clarity and brevity --- bip-p2qrh.mediawiki | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index 85c72e2f6b..b332e77250 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -14,7 +14,7 @@ === Abstract === -This document proposes a new SegWit output type, with spending rules based initially-- but not solely-- upon FALCON signatures. (For more on why, see the Rationale and Security sections.) A constraint is that no hard fork or increase in block size are necessary. This document is inspired by [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341], which introduced the design of the P2TR (Taproot) address type using Schnorr signatures. +This document proposes a new SegWit output type, with spending rules based initially-- but not solely-- upon FALCON signatures. (For more on why, see the Rationale and Security sections.) A constraint is that no hard fork or increase in block size is necessary. This document is inspired by [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341], which introduced the design of the P2TR (Taproot) address type using Schnorr signatures. === Copyright === @@ -26,17 +26,17 @@ This document is licensed under the 3-clause BSD license. This proposal aims to improve the quantum resistance of bitcoin's signature security should the Discrete Logarithm Problem (DLP) which secures Elliptic Curve Cryptography (ECC) no longer prove to be computationally hard, likely through quantum advantage by Cryptographically-Relevant Quantum Computers (CRQCs). [https://arxiv.org/pdf/quant-ph/0301141 A variant of Shor's algorithm] is believed to be capable of deriving the private key from a public key exponentially faster than classical means. The application of this variant of Shor's algorithm is herein referred to as quantum key decryption. Note that doubling the public key length, such as with a hypothetical secp512k1 curve, would only make deriving the private key twice as hard. The computational complexity of this is investigated further in the paper, [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault tolerant regime'']. -The primary threat to Bitcoin by CRQCs is [https://en.bitcoin.it/wiki/Quantum_computing_and_Bitcoin#QC_attacks generally considered to be to its uses of ECC used in signatures and Taproot commitments], hence the focus on a new address format. This is because Shor's algorithm enables a CRQC to break the cryptographic assumptions of ECC in roughly 10^8 quantum operations. While a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a quadratic speed up on brute force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes using Grover's algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques post on this]. +The primary threat to Bitcoin by CRQCs is [https://en.bitcoin.it/wiki/Quantum_computing_and_Bitcoin#QC_attacks generally considered to be to its breaking of ECC used in signatures and Taproot commitments], hence the focus on a new address format. This is because Shor's algorithm enables a CRQC to break the cryptographic assumptions of ECC in roughly 10^8 quantum operations. While a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a quadratic speed up on brute force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes using Grover's algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques post on this]. -The vulnerability of existing bitcoin addresses is investigated in [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the bitcoin supply is held within addresses vulnerable to quantum attack. As of the time of writing, that number is now closer to 20%. Additionally, Peter Wuille estimates even more might be vulnerable, for the reasons provided [https://x.com/pwuille/status/1108085284862713856 here]. +The vulnerability of existing bitcoin addresses is investigated in [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the bitcoin supply is held within addresses vulnerable to quantum attack. As of the time of writing, that number is now closer to 20%. Additionally, cryptographer Peter Wuille estimates even more might be vulnerable, for the reasons provided [https://x.com/pwuille/status/1108085284862713856 here]. Ordinarily, when a transaction is signed, the public key can be recovered from the signature. This makes a transaction submitted to the mempool vulnerable to quantum attack until it's mined. One way to mitigate this is to submit the transaction directly to a mining pool, which bypasses the mempool. This process is known as an out-of-band transaction. The mining pool must be trusted not to reveal the transaction public key to attackers. -Not having public keys exposed on-chain is an important step for quantum security. Otherwise funds would need to be spent to new addresses on a regular basis in order to prevent the possibility of a "long-range CRQC attack" recovering the key behind high value addresses. A long-range quantum attack can be considered one performed with chain data, such as that from a used address or one encoded in a spend script. A "short-range quantum attack" would be one done on keys in the mempool, which is seen as impractical given transaction throughput and block time. As the value being sent increases, so too should the fee in order to commit the transaction to the chain as soon as possible. This makes useless the public key revealed by spending a UTXO, so long as it is never reused. +Not having public keys exposed on-chain is an important step for quantum security. Otherwise funds would need to be spent to new addresses on a regular basis in order to prevent the possibility of a "long-range CRQC attack" recovering the key behind high value addresses. A long-range quantum attack can be considered one performed with chain data, such as that from a used address or one encoded in a spend script. A "short-range quantum attack" would be one performed on keys in the mempool, which is seen as impractical given transaction throughput and block time. As the value being sent increases, so too should the fee in order to commit the transaction to the chain as soon as possible. This makes useless the public key revealed by spending a UTXO, so long as it is never reused. -It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) address type that relies on a post-quantum cryptographic (PQC) signature algorithm. This new address type protects transactions submitted to the mempool and helps preserve the free market by reducing the need for private, out-of-band mempool transactions. +It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) address type that relies on a Post-Quantum Cryptographic (PQC) signature algorithm. This new address type protects transactions submitted to the mempool and helps preserve the free market by reducing the need for private, out-of-band mempool transactions. -The following table is non-exhaustive, but meant to inform the average bitcoin user whether their bitcoin is vulnerable to quantum attack. +The following table is non-exhaustive but intended to inform the average bitcoin user whether their bitcoin is vulnerable to quantum attack. {| |+ Vulnerable address types @@ -54,9 +54,9 @@ The following table is non-exhaustive, but meant to inform the average bitcoin u It should be noted that Taproot addresses are vulnerable in that they encode a 32-byte x-only public key, from which a full public key can be reconstructed. -If a key is recovered by a CRQC, it can also be trivially checked to see if any child keys were produced using an unhardened [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32] derivation path. +If a key is recovered by a CRQC it can also be trivially checked to see if any child keys were produced using an unhardened [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32] derivation path. -The following table summarizes the scenarios in which public keys are revealed when using Bitcoin, and what type of attack they're vulnerable to: +The following table summarizes the scenarios in which public keys are revealed when using Bitcoin and what type of attack the underlying addresses are vulnerable to: {| |+ Scenarios for revealed public keys on Bitcoin @@ -74,13 +74,13 @@ The following table summarizes the scenarios in which public keys are revealed w | Unhardened BIP-32 HD wallet keys || Both Long-range or Short-range |} -The only time a short-range attack can occur is when the transaction is in the mempool, whereas long-range attacks are when the public key is known well in advance. Short-range attacks require much larger, more expensive CRQCs. +The only time a short-range attack can occur is when the transaction is in the mempool, whereas a long-range attack occurs when the public key is known well in advance. Short-range attacks require much larger, more expensive CRQCs. -Should quantum advantage manifest, a convention is proposed in spending the full 65-byte P2PK key used by the coinbase output in Block 1 back to itself. It is proposed to call this the [https://mempool.space/address/0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee Canary address]. The reasoning behind this is that this can only be done by Satoshi, and given his absence, this can only be spent by others if there is a significant vulnerability in secp256k1. Should the Canary coins move, that will signal that bitcoin is presently vulnerable. Without the Canary, or an address like it, there may be some doubt as to whether the coins were moved with keys belonging to the original owner. +Should quantum advantage manifest, a convention is proposed in spending the full 65-byte P2PK key used by the coinbase output in Block 1 back to itself. It is proposed to call the address in Block 1 the [https://mempool.space/address/0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee Canary address] since it can only be spent from by others (assuming Satoshi's continued absence) if secp256k1 is broken. Should the Canary coins move, that will signal that reliance on secp256k1 is presently vulnerable. Without the Canary, or an address like it, there may be some doubt as to whether the coins were moved with keys belonging to the original owner. As an interesting aside, coinbase outputs to P2PK keys go as far as block 200,000, so it's possible there are between 1-2 million coins that are vulnerable from the first epoch. These coins can be considered "Satoshi's Shield." Any addresses with a balance of less than the original block subsidy of 50 coins can be considered incentive incompatible to capture until all of these are mined. -It's for this reason that, for those who wish to be prepared for quantum emergency, it is recommended that no more than 50 bitcoin are kept under a single distinct, unused Native SegWit (P2WPKH, "bc1q") address at a time. This is assuming that the attacker is financially-motivated instead of, for example, a nation state looking to break confidence in Bitcoin. Additionally, this assumes that other vulnerable targets such as central banks have upgraded their cryptography already. +It's for the above reason that, for those who wish to be prepared for quantum emergency, it is recommended that no more than 50 bitcoin are kept under a single distinct, unused Native SegWit (P2WPKH, "bc1q") address at a time. This is assuming that the attacker is financially-motivated instead of, for example, a nation state looking to break confidence in Bitcoin. Additionally, this assumes that other vulnerable targets such as central banks have upgraded their cryptography already. The Commercial National Security Algorithm Suite (CNSA) 2.0 has a timeline for software and networking equipment to be upgraded by 2030, with browsers and operating systems fully upgraded by 2033. @@ -89,13 +89,13 @@ Lastly, it is worth noting by way of comparison that [https://ethresear.ch/t/how === Rationale === -This is the first in a series of BIPs under a QuBit soft fork. A qubit is a fundamental unit of quantum computing, and the capital B represents its connection to bitcoin. The name QuBit also rhymes to some extent with SegWit. +This is the first in a series of BIPs under a QuBit soft fork. A qubit is a fundamental unit of quantum computing, and the capital B refers to bitcoin. The name QuBit also rhymes to some extent with SegWit. -It is proposed to use SegWit version 3. This results in addresses that start with bc1r, which could be a useful way to remember that these are [r]esistant addresses, similar to how bc1q corresponds to Se[q]Wit and bc1p corresponds to Ta[p]root. This is referencing the lookup table under [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. +It is proposed to use SegWit version 3. This results in addresses that start with bc1r, which could be a useful way to remember that these are quantum [r]esistant addresses (similar to how bc1q corresponds to Se[q]Wit and bc1p corresponds to Ta[p]root). This is referencing the lookup table under [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. The proposal above also leaves a gap in case it makes sense to use version 2, or bc1z, for implementation of other address formats such as those that employ Cross Input Signature Aggregation (CISA). -P2QRH is meant to be implemented on top of P2TR, combining the security of classical Schnorr signatures along with post-quantum cryptography. This is a form of "hybrid cryptography" such that no regression in security is presented should a vulnerability exist in one of the signature algorithms used. One key distinction between P2QRH and P2TR however is that P2QRH will encode a hash of the public key. This is a significant change in how Taproot works, but is necessary to avoid exposing public keys on-chain in advance of attackers. +P2QRH is meant to be implemented on top of P2TR, combining the security of classical Schnorr signatures along with post-quantum cryptography. This is a form of "hybrid cryptography" such that no regression in security is presented should a vulnerability exist in one of the signature algorithms used. One key distinction between P2QRH and P2TR however is that P2QRH will encode a hash of the public key. This is a significant deviation from how Taproot works by itself, but it is necessary to avoid exposing public keys on-chain where they are vulnerable to attack. P2QRH uses a 32-byte HASH256 (specifically SHA-256 twice-over, which is similar to that used in [https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#specification BIP-16]) of the public key to reduce the size of new outputs and also to increase security by not having the public key available on-chain. This hash serves as a minimal cryptographic commitment to a public key. It goes into the output spend script, which does not receive the witness discount. @@ -103,11 +103,11 @@ Post-quantum public keys are generally larger than those used by ECC, depending Support for FALCON signatures will be introduced first, with the intention of adding SQIsign and other post-quantum algorithms as they are approved. By way of comparison, FALCON signatures are roughly 4x larger than SQIsign signatures and 20x larger than Schnorr signatures. FALCON is a more conservative approach to applied lattice cryptography than SQIsign, and its use has recently been approved by NIST. NIST approval streamlines implementations through establishing consensus in the scientific and developer community. However, even SQIsign signatures are roughly 5x larger than Schnorr signatures. This means, to maintain present transaction throughput, an increase in the witness discount will likely be desired in a QuBit soft fork. That will be specified in a future QuBit BIP. -An increase in the witness discount must not be taken lightly. It must be resistant to applications that might take advantage of this discount (e.g. storage of arbitrary data as seen with "inscriptions") without a corresponding increase in economic activity. Such an increase would not only impact node runners but those with inscriptions would also have the scarcity of their non-monetary assets affected. The only way to prevent this while also increasing the discount is to have a completely separate witness, a "quantum witness". Because it is meant only for public keys and signatures, we call this section of the transaction the attestation. +An increase in the witness discount must not be taken lightly. It must be resistant to applications that might take advantage of this discount (e.g. storage of arbitrary data as seen with "inscriptions") without a corresponding increase in economic activity. An increase in the witness discount would not only impact node runners but those with inscriptions would also have the scarcity of their non-monetary assets affected. The only way to prevent these affects while also increasing the discount is to have a completely separate witness-- a "quantum witness." Because it is meant only for public keys and signatures, we call this section of the transaction the attestation. To address the risk of arbitrary data being stored using P2QRH (QuBit) addresses, very specific rules will be applied to spending from the witness stack in SegWit v3 outputs. A fixed signature size will be necessary for spending the output, and the output must be spendable to be considered valid within node consensus. A fixed signature size will also be helpful to disambiguate between signature types without an additional version byte, as SQIsign signatures are substantially smaller than FALCON signatures. Consequently, the correct signature algorithm can be inferred through byte length. The public key and signature will be pushed separately to the attestation stack. Multiple signatures can be included in order to support multisig applications, and also for spending multiple inputs. -Since only valid signatures can be committed to in a SegWit v3 attestation, arbitrary data cannot be added by miners, as that would affect the consensus of their block. A CRQC operator is economically disincentivized from computing a spendable public key that matched arbitrary signature data due to the cost of that computation. That is because the cost of such a computation could prove quite substantial, rather than simply putting the arbitrary data within a Taproot witness. Doing the work to meet the requirement for it to be consensus-valid data would prove cost-prohibitive. +Since only valid signatures can be committed to in a SegWit v3 attestation, arbitrary data cannot be added by miners, as that would affect the consensus of their block. A CRQC operator is economically disincentivized from computing a spendable public key that matched arbitrary signature data due to the cost of that computation. That is because the cost of such a computation could prove quite substantial, rather than simply putting the arbitrary data within a Taproot witness. Additionally, it should be noted, whether an output with a P2QRH spend script corresponds to a FALCON or SQIsign signature is not known until the output is spent. @@ -133,7 +133,7 @@ For P2QRH descriptors, qrh() should be used. == Security == {| -|+ Proposed quantum resistant signature algorithms ordered by largest to smallest NIST V signature size +|+ Candidate quantum resistant signature algorithms ordered by largest to smallest NIST V signature size |- ! Signature Algorithm !! Year First Introduced !! Signature Size !! Public Key Size || Cryptographic Assumptions |- @@ -169,7 +169,7 @@ In comparison, the size of currently used signature algorithms are: * ECDSA - 70-72 bytes * Schnorr - 64 bytes -In comparison to year, secp256k1 [https://www.secg.org/SEC1-Ver-1.0.pdf was originally specified in 2000]. +In comparison to inception date, secp256k1 [https://www.secg.org/SEC1-Ver-1.0.pdf was originally specified in 2000]. One consideration for choosing an algorithm is its maturity. secp256k1 was already 8 years old by the time it was chosen as bitcoin's curve. Isogeny cryptography when it was first introduced was broken over a weekend. @@ -177,7 +177,7 @@ Ideally SQIsign also proves to be flexible enough to support [https://www.pierri Signature verification speed as it compares to Schnorr or ECDSA isn't seen as high a consideration as signature size due to block space being the primary fee constraint. As a P2QRH implementation materializes, a benchmark will be added for performance comparison. Fortunately, SQIsign signatures are substantially faster to verify than it is to generate keys or to sign, which is a major consideration when a transaction need only be signed once, or a handful of times with PSBT, compared to being verified simultaneously on tens of thousands of nodes. Key generation may need to cached in BIP-32 Hierarchical Deterministic wallets. -An additional consideration is security levels. Longer signature sizes provide more security. NIST has standardized five security levels for post-quantum cryptography. NIST security level I provides security equivalent to 128-bit keys, and security level V provides 256-bit security. +An additional consideration is security level. Longer signature sizes provide more security. NIST has standardized five security levels for post-quantum cryptography. NIST security level I provides security equivalent to 128-bit keys, and security level V provides 256-bit security. == Specification == @@ -203,11 +203,11 @@ In short, the new spend script serialization format is as follows: Addresses then encode this script using bech32m. -32-byte attestation fields are assumed to be Schnorr public keys for Taproot fields, because they are ordinarily included in the spend script, but cannot be included in P2QRH for security reasons. Public key / signature pairs for Taproot fields come before QuBit public key / signature pairs. +32-byte attestation fields are assumed to be Schnorr public keys for Taproot fields because they are ordinarily included in the spend script, but they cannot be included in P2QRH for security reasons. Public key / signature pairs for Taproot fields come before QuBit public key / signature pairs. -Which key type is inferred by its size, as provided by the attestation varint pair, determining whether it's processed as secp256k1 Schnorr, SPHINCS, XMSS, FALCON, and SQIsign. +The exact key type is inferred by its size, as provided by the attestation variant pair, which determines whether it's processed as secp256k1 Schnorr, SPHINCS, XMSS, FALCON, or SQIsign. -If the transaction fails to include the public keys needed to match the spend script hash, it is an invalid transaction, because the cryptographic commitment for the keys has not been met. Because of this, only valid public keys and signatures can be included within the attestation, and no other data. +If the transaction fails to include the public keys needed to match the spend script hash, it is an invalid transaction because the cryptographic commitment for the keys has not been met. Consequently, only valid public keys and signatures can be included within the attestation and no other data. === Public Key Generation === From 0a2ed4a23f232abdbb09db9c55edb5f489f020bc Mon Sep 17 00:00:00 2001 From: Hunter Beast Date: Wed, 20 Nov 2024 18:15:32 -0700 Subject: [PATCH 007/131] Apply suggestions from review Co-authored-by: Mark "Murch" Erhardt --- bip-p2qrh.mediawiki | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index b332e77250..3f7cecdafb 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -14,7 +14,7 @@ === Abstract === -This document proposes a new SegWit output type, with spending rules based initially-- but not solely-- upon FALCON signatures. (For more on why, see the Rationale and Security sections.) A constraint is that no hard fork or increase in block size is necessary. This document is inspired by [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341], which introduced the design of the P2TR (Taproot) address type using Schnorr signatures. +This document proposes the introduction of a new output type based on FALCON signatures. This approach for adding a post-quantum secure output type does not require a hard fork or block size increase. === Copyright === @@ -26,9 +26,9 @@ This document is licensed under the 3-clause BSD license. This proposal aims to improve the quantum resistance of bitcoin's signature security should the Discrete Logarithm Problem (DLP) which secures Elliptic Curve Cryptography (ECC) no longer prove to be computationally hard, likely through quantum advantage by Cryptographically-Relevant Quantum Computers (CRQCs). [https://arxiv.org/pdf/quant-ph/0301141 A variant of Shor's algorithm] is believed to be capable of deriving the private key from a public key exponentially faster than classical means. The application of this variant of Shor's algorithm is herein referred to as quantum key decryption. Note that doubling the public key length, such as with a hypothetical secp512k1 curve, would only make deriving the private key twice as hard. The computational complexity of this is investigated further in the paper, [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault tolerant regime'']. -The primary threat to Bitcoin by CRQCs is [https://en.bitcoin.it/wiki/Quantum_computing_and_Bitcoin#QC_attacks generally considered to be to its breaking of ECC used in signatures and Taproot commitments], hence the focus on a new address format. This is because Shor's algorithm enables a CRQC to break the cryptographic assumptions of ECC in roughly 10^8 quantum operations. While a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a quadratic speed up on brute force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes using Grover's algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques post on this]. +The primary threat to Bitcoin by CRQCs is [https://en.bitcoin.it/wiki/Quantum_computing_and_Bitcoin#QC_attacks generally considered to be to its breaking of ECC used in signatures and Taproot commitments], hence the focus on a new address format. This is because Shor's algorithm enables a CRQC to break the cryptographic assumptions of ECC in roughly 10^8 quantum operations. While a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a quadratic speed up on brute force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes using Grover's algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques’ post on this]. -The vulnerability of existing bitcoin addresses is investigated in [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the bitcoin supply is held within addresses vulnerable to quantum attack. As of the time of writing, that number is now closer to 20%. Additionally, cryptographer Peter Wuille estimates even more might be vulnerable, for the reasons provided [https://x.com/pwuille/status/1108085284862713856 here]. +The vulnerability of existing bitcoin addresses is investigated in [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the bitcoin supply is held within addresses vulnerable to quantum attack. As of the time of writing, that number is now closer to 20%. Additionally, cryptographer Pieter Wuille [https://x.com/pwuille/status/1108085284862713856 reasons] even more might be vulnerable. Ordinarily, when a transaction is signed, the public key can be recovered from the signature. This makes a transaction submitted to the mempool vulnerable to quantum attack until it's mined. One way to mitigate this is to submit the transaction directly to a mining pool, which bypasses the mempool. This process is known as an out-of-band transaction. The mining pool must be trusted not to reveal the transaction public key to attackers. @@ -36,7 +36,7 @@ Not having public keys exposed on-chain is an important step for quantum securit It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) address type that relies on a Post-Quantum Cryptographic (PQC) signature algorithm. This new address type protects transactions submitted to the mempool and helps preserve the free market by reducing the need for private, out-of-band mempool transactions. -The following table is non-exhaustive but intended to inform the average bitcoin user whether their bitcoin is vulnerable to quantum attack. +The following table is non-exhaustive but intended to inform the average bitcoin user whether their bitcoin is vulnerable to a long-range quantum attack. {| |+ Vulnerable address types From c92a9b0e4db7e46ff11c7fc9efd32c991e635074 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Wed, 20 Nov 2024 18:17:59 -0700 Subject: [PATCH 008/131] QuBit - P2QRH spending rules --- bip-p2qrh.mediawiki | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index 3f7cecdafb..a1e63e59b1 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -14,7 +14,7 @@ === Abstract === -This document proposes the introduction of a new output type based on FALCON signatures. This approach for adding a post-quantum secure output type does not require a hard fork or block size increase. +This document proposes the introduction of a new output type using signatures based on Post-Quantum Cryptography (PQC). This approach for adding a post-quantum secure output type does not require a hard fork or block size increase. === Copyright === @@ -30,11 +30,11 @@ The primary threat to Bitcoin by CRQCs is [https://en.bitcoin.it/wiki/Quantum_co The vulnerability of existing bitcoin addresses is investigated in [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the bitcoin supply is held within addresses vulnerable to quantum attack. As of the time of writing, that number is now closer to 20%. Additionally, cryptographer Pieter Wuille [https://x.com/pwuille/status/1108085284862713856 reasons] even more might be vulnerable. -Ordinarily, when a transaction is signed, the public key can be recovered from the signature. This makes a transaction submitted to the mempool vulnerable to quantum attack until it's mined. One way to mitigate this is to submit the transaction directly to a mining pool, which bypasses the mempool. This process is known as an out-of-band transaction. The mining pool must be trusted not to reveal the transaction public key to attackers. +Ordinarily, when a transaction is signed, the public key can be recovered from the signature. This makes a transaction submitted to the mempool vulnerable to quantum attack until it's mined. One way to mitigate this is to submit the transaction directly to a mining pool, which bypasses the mempool. This process is known as an out-of-band transaction. The mining pool must be trusted not to reveal the transaction public key to attackers. The problem with this approach is that it requires a trusted third party, which is what this P2QRH proposal aims to avoid. -Not having public keys exposed on-chain is an important step for quantum security. Otherwise funds would need to be spent to new addresses on a regular basis in order to prevent the possibility of a "long-range CRQC attack" recovering the key behind high value addresses. A long-range quantum attack can be considered one performed with chain data, such as that from a used address or one encoded in a spend script. A "short-range quantum attack" would be one performed on keys in the mempool, which is seen as impractical given transaction throughput and block time. As the value being sent increases, so too should the fee in order to commit the transaction to the chain as soon as possible. This makes useless the public key revealed by spending a UTXO, so long as it is never reused. +Not having public keys exposed on-chain is an important step for quantum security. Otherwise funds would need to be spent to new addresses on a regular basis in order to prevent the possibility of a "long-range CRQC attack" recovering the key behind high value addresses. A long-range quantum attack can be considered one performed with chain data, such as that from a used address or one encoded in a spend script. This is likely to be more common early on, as early quantum computers must be run for longer in order to overcome errors caused by noise. A "short-range quantum attack" would be one performed on keys in the mempool, which is seen as much more difficult given the block time, and so it requires more sophisticated CRQCs. As the value being sent increases, so too should the fee in order to commit the transaction to the chain as soon as possible. Once the transaction is mined, it makes useless the public key revealed by spending a UTXO, so long as it is never reused. -It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) address type that relies on a Post-Quantum Cryptographic (PQC) signature algorithm. This new address type protects transactions submitted to the mempool and helps preserve the free market by reducing the need for private, out-of-band mempool transactions. +It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) address type that relies on a PQC signature algorithm. This new address type protects transactions submitted to the mempool and helps preserve the free market by preventing the need for private, out-of-band mempool transactions. The following table is non-exhaustive but intended to inform the average bitcoin user whether their bitcoin is vulnerable to a long-range quantum attack. @@ -65,11 +65,11 @@ The following table summarizes the scenarios in which public keys are revealed w |- | Early addresses (Satoshi's coins, CPU miners, starts with 04) || Long-range |- -| Reused addresses (any type, except bc1r) || Long-range +| Reused addresses (any type, except P2QRH) || Long-range |- | Taproot addresses (starts with bc1p) || Long-range |- -| Any transaction in the mempool (except for bc1r) || Short-range +| Any transaction in the mempool (except for P2QRH) || Short-range |- | Unhardened BIP-32 HD wallet keys || Both Long-range or Short-range |} @@ -78,13 +78,11 @@ The only time a short-range attack can occur is when the transaction is in the m Should quantum advantage manifest, a convention is proposed in spending the full 65-byte P2PK key used by the coinbase output in Block 1 back to itself. It is proposed to call the address in Block 1 the [https://mempool.space/address/0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee Canary address] since it can only be spent from by others (assuming Satoshi's continued absence) if secp256k1 is broken. Should the Canary coins move, that will signal that reliance on secp256k1 is presently vulnerable. Without the Canary, or an address like it, there may be some doubt as to whether the coins were moved with keys belonging to the original owner. -As an interesting aside, coinbase outputs to P2PK keys go as far as block 200,000, so it's possible there are between 1-2 million coins that are vulnerable from the first epoch. These coins can be considered "Satoshi's Shield." Any addresses with a balance of less than the original block subsidy of 50 coins can be considered incentive incompatible to capture until all of these are mined. +As an interesting aside, coinbase outputs to P2PK keys go as far as block 200,000, so there are 1,723,848 coins that are vulnerable from the first epoch at the time of writing in P2PK outputs alone. Since the majority of these have a block reward of 50 coins each, there are roughly 34,000 distinct P2PK addresses that are vulnerable. These coins can be considered "Satoshi's Shield." Any addresses with a balance of less than the original block subsidy of 50 coins can be considered incentive incompatible to capture until all of these are mined, and these addresses serve to provide time to transition Bitcoin to implement post-quantum security. -It's for the above reason that, for those who wish to be prepared for quantum emergency, it is recommended that no more than 50 bitcoin are kept under a single distinct, unused Native SegWit (P2WPKH, "bc1q") address at a time. This is assuming that the attacker is financially-motivated instead of, for example, a nation state looking to break confidence in Bitcoin. Additionally, this assumes that other vulnerable targets such as central banks have upgraded their cryptography already. +It's for the above reason that, for those who wish to be prepared for quantum emergency, it is recommended that no more than 50 bitcoin are kept under a single, distinct, unused Native SegWit (P2WPKH, "bc1q") address at a time. This is assuming that the attacker is financially-motivated instead of, for example, a nation state looking to break confidence in Bitcoin. Additionally, this assumes that other vulnerable targets such as central banks have upgraded their cryptography by this time. -The Commercial National Security Algorithm Suite (CNSA) 2.0 has a timeline for software and networking equipment to be upgraded by 2030, with browsers and operating systems fully upgraded by 2033. - -Lastly, it is worth noting by way of comparison that [https://ethresear.ch/t/how-to-hard-fork-to-save-most-users-funds-in-a-quantum-emergency/18901 Vitalik Buterin's proposed solution] in an Ethereum quantum emergency is quite different from the approach in this BIP. His plan involves a hard fork of the chain, reverting all blocks after a sufficient amount of theft, and using STARKs based on BIP-32 seeds to act as the authoritative secret when signing. These measures are deemed far too heavy-handed for bitcoin. +The Commercial National Security Algorithm Suite (CNSA) 2.0 has a timeline for software and networking equipment to be upgraded by 2030, with browsers and operating systems fully upgraded by 2033. According to NIST IR 8547, Elliptic Curve Cryptography is planned to be disallowed within the US Federal government after 2035. An exception is made for hybrid cryptography, which is the use of ECC and post-quantum algorithms together. === Rationale === @@ -95,7 +93,7 @@ It is proposed to use SegWit version 3. This results in addresses that start wit The proposal above also leaves a gap in case it makes sense to use version 2, or bc1z, for implementation of other address formats such as those that employ Cross Input Signature Aggregation (CISA). -P2QRH is meant to be implemented on top of P2TR, combining the security of classical Schnorr signatures along with post-quantum cryptography. This is a form of "hybrid cryptography" such that no regression in security is presented should a vulnerability exist in one of the signature algorithms used. One key distinction between P2QRH and P2TR however is that P2QRH will encode a hash of the public key. This is a significant deviation from how Taproot works by itself, but it is necessary to avoid exposing public keys on-chain where they are vulnerable to attack. +P2QRH is meant to be implemented on top of P2TR, combining the security of classical Schnorr signatures along with post-quantum cryptography. This is a form of hybrid cryptography such that no regression in security is presented should a vulnerability exist in one of the signature algorithms used. One key distinction between P2QRH and P2TR however is that P2QRH will encode a hash of the public key. This is a significant deviation from how Taproot works by itself, but it is necessary to avoid exposing public keys on-chain where they are vulnerable to attack. P2QRH uses a 32-byte HASH256 (specifically SHA-256 twice-over, which is similar to that used in [https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#specification BIP-16]) of the public key to reduce the size of new outputs and also to increase security by not having the public key available on-chain. This hash serves as a minimal cryptographic commitment to a public key. It goes into the output spend script, which does not receive the witness discount. @@ -218,11 +216,7 @@ TBD, pending test vectors TBD -=== Default Signing === - -TBD - -=== Alternative Signing === +=== Signing === TBD @@ -230,10 +224,6 @@ TBD TBD -=== Batch Verification === - -TBD - === Usage Considerations === TBD @@ -243,6 +233,11 @@ TBD TBD +== Related Work == + +It is worth noting by way of comparison that [https://ethresear.ch/t/how-to-hard-fork-to-save-most-users-funds-in-a-quantum-emergency/18901 Vitalik Buterin's proposed solution] in an Ethereum quantum emergency is quite different from the approach in this BIP. His plan involves a hard fork of the chain, reverting all blocks after a sufficient amount of theft, and using STARKs based on BIP-32 seeds to act as the authoritative secret when signing. These measures are deemed far too heavy-handed for bitcoin. + + == References == * [https://groups.google.com/g/bitcoindev/c/Aee8xKuIC2s/m/cu6xej1mBQAJ Mailing list discussion] @@ -260,6 +255,7 @@ TBD To help implementors understand updates to this BIP, we keep a list of substantial changes. +* 2024-11-20 - Clarifications based on feedback from Murch. Remove some sections that are not yet ready. * 2024-10-21 - Replace XMSS with CRYSTALS-Dilithium due to NIST approval and size constraints. * 2024-09-30 - Refactor the ECC vs PoW section. Swap quitness for attestation. * 2024-09-29 - Update section on PoW to include partial-preimage. @@ -269,4 +265,6 @@ To help implementors understand updates to this BIP, we keep a list of substanti == Acknowledgements == -Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name "QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as well to those who took the time to review and contribute, including Adam Borcany, Antoine Riard, Pierre-Luc Dallaire-Demers, Ethan Heilman, Jon Atack, and Jameson Lopp. +This document is inspired by [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341], which introduced the design of the P2TR (Taproot) address type using Schnorr signatures. + +Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name "QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as well to those who took the time to review and contribute, including Adam Borcany, Antoine Riard, Pierre-Luc Dallaire-Demers, Ethan Heilman, Jon Atack, Jameson Lopp, and Murchandamus. From e1b7007cd93027409aa99a43ce2e35854771088b Mon Sep 17 00:00:00 2001 From: Hunter Beast Date: Tue, 3 Dec 2024 15:36:38 -0700 Subject: [PATCH 009/131] Add details on attestation structure and parsing. (#14) * Add details on attestation structure and parsing. * bip-p2qrh.mediawiki: Separating discussion about Grovers algorithm into its own section. * Update phrasing and formatting. * Kyle fixes * Add Jeff Bride to acknowledgments * Apply suggestions from code review Co-authored-by: Kyle Crews <92337423+CrewsControlSolutions@users.noreply.github.com> * Updates to clarity. --------- Co-authored-by: jbride Co-authored-by: Kyle Crews <92337423+CrewsControlSolutions@users.noreply.github.com> --- bip-p2qrh.mediawiki | 224 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 192 insertions(+), 32 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index a1e63e59b1..5d715417bb 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -24,9 +24,9 @@ This document is licensed under the 3-clause BSD license. === Motivation === -This proposal aims to improve the quantum resistance of bitcoin's signature security should the Discrete Logarithm Problem (DLP) which secures Elliptic Curve Cryptography (ECC) no longer prove to be computationally hard, likely through quantum advantage by Cryptographically-Relevant Quantum Computers (CRQCs). [https://arxiv.org/pdf/quant-ph/0301141 A variant of Shor's algorithm] is believed to be capable of deriving the private key from a public key exponentially faster than classical means. The application of this variant of Shor's algorithm is herein referred to as quantum key decryption. Note that doubling the public key length, such as with a hypothetical secp512k1 curve, would only make deriving the private key twice as hard. The computational complexity of this is investigated further in the paper, [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault tolerant regime'']. +This proposal aims to improve the quantum resistance of bitcoin's signature security should the Discrete Logarithm Problem (DLP) which secures Elliptic Curve Cryptography (ECC) no longer prove to be computationally hard, likely through quantum advantage by Cryptoanalytically-Relevant Quantum Computers (CRQCs). [https://arxiv.org/pdf/quant-ph/0301141 A variant of Shor's algorithm] is believed to be capable of deriving the private key from a public key exponentially faster than classical means. The application of this variant of Shor's algorithm is herein referred to as quantum key decryption. Note that doubling the public key length, such as with a hypothetical secp512k1 curve, would only make deriving the private key twice as hard. The computational complexity of this is investigated further in the paper, [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault tolerant regime'']. -The primary threat to Bitcoin by CRQCs is [https://en.bitcoin.it/wiki/Quantum_computing_and_Bitcoin#QC_attacks generally considered to be to its breaking of ECC used in signatures and Taproot commitments], hence the focus on a new address format. This is because Shor's algorithm enables a CRQC to break the cryptographic assumptions of ECC in roughly 10^8 quantum operations. While a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a quadratic speed up on brute force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes using Grover's algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques’ post on this]. +The primary threat to Bitcoin by CRQCs is [https://en.bitcoi.it/wiki/Quantum_computing_and_Bitcoin#QC_attacks generally considered to be their potential to break ECC, which is used in signatures and Taproot commitments], hence the focus on a new address format. Shor's algorithm enables a CRQC to break the cryptographic assumptions of ECC in roughly 10^8 quantum operations. The vulnerability of existing bitcoin addresses is investigated in [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the bitcoin supply is held within addresses vulnerable to quantum attack. As of the time of writing, that number is now closer to 20%. Additionally, cryptographer Pieter Wuille [https://x.com/pwuille/status/1108085284862713856 reasons] even more might be vulnerable. @@ -84,12 +84,13 @@ It's for the above reason that, for those who wish to be prepared for quantum em The Commercial National Security Algorithm Suite (CNSA) 2.0 has a timeline for software and networking equipment to be upgraded by 2030, with browsers and operating systems fully upgraded by 2033. According to NIST IR 8547, Elliptic Curve Cryptography is planned to be disallowed within the US Federal government after 2035. An exception is made for hybrid cryptography, which is the use of ECC and post-quantum algorithms together. +Although CRQCs could pose a threat to the signatures used in Bitcoin, a smaller threat is to Bitcoin's hash algorithms. In particular, while a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a quadratic speed up on brute force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes using Grover's algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques’ post on this]. === Rationale === This is the first in a series of BIPs under a QuBit soft fork. A qubit is a fundamental unit of quantum computing, and the capital B refers to bitcoin. The name QuBit also rhymes to some extent with SegWit. -It is proposed to use SegWit version 3. This results in addresses that start with bc1r, which could be a useful way to remember that these are quantum [r]esistant addresses (similar to how bc1q corresponds to Se[q]Wit and bc1p corresponds to Ta[p]root). This is referencing the lookup table under [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. +It is proposed to use SegWit version 3. This results in addresses that start with bc1r, which could be a useful way to remember that these are quantum (r)esistant addresses (similar to how bc1q corresponds to Se(q)Wit and bc1p corresponds to Ta(p)root). This is referencing the lookup table under [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. The proposal above also leaves a gap in case it makes sense to use version 2, or bc1z, for implementation of other address formats such as those that employ Cross Input Signature Aggregation (CISA). @@ -123,9 +124,105 @@ We first build up a definition of the signature scheme by going through the desi === Design === -For P2QRH descriptors, qrh() should be used. +==== Descriptor Format ==== -> Further specific details to be completed later in the draft process as outlined in [https://github.com/bitcoin/bips/blob/master/bip-0002.mediawiki BIP-2] +To integrate P2QRH into existing wallet software and scripts, we introduce a new output descriptor function qrh(). This function represents a P2QRH output, similar to how wpkh() and tr() are used for P2WPKH and P2TR outputs, respectively. + +The qrh() function takes the HASH256 of the concatenated HASH256 of the quantum-resistant public keys as its argument. For example: + + +qrh(HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ...)) + + +The above function allows wallets to manage P2QRH addresses and outputs while accommodating multiple public keys of varying lengths, such as in multisig schemes, while keeping the public keys hidden until the time of spending. + + +==== Address Format ==== + +P2QRH uses SegWit version 3 outputs, resulting in addresses that start with bc1r, following [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. Bech32 encoding maps version 3 to the prefix r. + +Example P2QRH address: + + +bc1r... (32-byte Bech32m-encoded HASH256 of the HASH256 of the public keys) + + +==== ScriptPubKey ==== + +The scriptPubKey for a P2QRH output is: + + +OP_PUSHNUM_3 OP_PUSHBYTES_32 + + +Where: + +* OP_PUSHNUM_3 (0x03) indicates SegWit version 3. +* is the 32-byte HASH256 of the concatenated HASH256 of each public key. + +===== Hash Computation ===== + + +hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN)) + + +This construction creates a cryptographic commitment to multiple public keys. + +==== Transaction Serialization ==== + +Following BIP-141, the transaction serialization is modified to include a new attestation field after the witness field: + + +[nVersion][marker][flag][txins][txouts][witness][attestation][nLockTime] + + +* marker: 0x00 (same as SegWit) +* flag: 0x02 (indicates the presence of both witness and attestation data) +* attestation: Contains the quantum-resistant public keys and signatures. + +==== Attestation Structure ==== + +The attestation field consists of: + +* num_pubkeys: The number of public keys (VarInt encoded). +* For each public key: +** pubkey_length: VarInt encoded length of the public key. +** pubkey: The public key bytes. +* num_signatures: The number of signatures (VarInt encoded). +* For each signature: +** signature_length: VarInt encoded length of the signature. +** signature: The signature bytes. + +This structure repeats for each input, in order, for flexibility in supporting multisig schemes and various quantum-resistant algorithms. + +For each input, a separate attestation field is used. To know how many attestation fields are present, implementations must count the number of inputs present in the transaction. + +The specific algorithm is determined by the size of the public key and signature, as described in the next section. + +==== Signature Algorithm Identification ==== + +The specific quantum-resistant signature algorithm used is inferred from the length of the public key and signature. Implementations must recognize the supported algorithms and validate accordingly. + +Supported algorithms and their NIST Level V parameters: + +* '''SPHINCS+-256f:''' +** Public Key Length: 64 bytes +** Signature Length: 49,856 bytes +* '''CRYSTALS-Dilithium Level 5''': +** Public Key Length: 2,592 bytes +** Signature Length: 4,595 bytes +* '''FALCON-1024''': +** Public Key Length: 1,793 bytes +** Signature Length: 1,280 bytes +* '''SQIsign NIST-V''': +** Public Key Length: 128 bytes +** Signature Length: 335 bytes + +Implementations must reject public keys and signatures that do not match expected lengths for supported algorithms. + +==== Compatibility with BIP-141 ==== + +By adhering to the SegWit transaction structure and versioning, P2QRH outputs are compatible with existing transaction processing rules. Nodes that do not recognize SegWit version 3 will treat these outputs as anyone-can-spend but, per BIP-141, will not relay or mine such transactions. == Security == @@ -159,8 +256,7 @@ For P2QRH descriptors, qrh() should be used. |} - -As shown, supersingular elliptic curve quaternion isogeny signature algorithms represent the state of the art in post-quantum cryptography, beyond lattice cryptography alone, especially when key and signature length are major constraints. This makes inclusion of SQIsign attractive, and support is planned, but it will be some time until it is approved for production use. Meanwhile, FALCON signatures are already approved and have achieved broader community consensus. +As shown, supersingular elliptic curve quaternion isogeny signature algorithms represent the state of the art in post-quantum cryptography, beyond lattice cryptography alone, especially when key and signature length are major constraints. This makes inclusion of SQIsign attractive, and support is planned, but it will be some time until it is approved for production use. Meanwhile, SPHINCS+ and CRYSTALS-Dilithium signatures are already approved and have achieved broader community consensus. FALCON signatures are also NIST approved. In comparison, the size of currently used signature algorithms are: @@ -182,51 +278,114 @@ An additional consideration is security level. Longer signature sizes provide mo How the attestation is differentiated from the witness can be accomplished similar to how [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#user-content-Transaction_ID BIP-141] introduced the marker and flag, with the QuBit flag being set to 0x02. This means all QuBit transactions are also SegWit transactions. The additional data would be included as a second array of byte arrays following the witness stack. -The new transaction serialization format is as follows: +32-byte attestation fields are assumed to be Schnorr public keys for Taproot fields because they are ordinarily included in the spend script, but they cannot be included in P2QRH for security reasons. Public key / signature pairs for Taproot fields come before QuBit public key / signature pairs. - [nVersion][marker][flag][txins][txouts][witness][attestation][nLockTime] +The exact key type is inferred by its size, as provided by the attestation variant pair, which determines whether it's processed as secp256k1 Schnorr, SPHINCS, CRYSTALS-Dilithium, FALCON, or SQIsign. -QuBit spend scripts are as follows: +If the transaction fails to include the public keys needed to match the spend script hash, it is an invalid transaction because the cryptographic commitment for the keys has not been met. Consequently, only valid public keys and signatures can be included within the attestation and no other data. -* OP_PUSHNUM_3 to indicate SegWit version 3 -* OP_PUSHBYTES_32 -* HASH256 of the following bytes concatenated: - * HASH256 of the public key at attestation index 0 - * If there are more public keys: - * All public keys are hashed via HASH256 and concatenated -In short, the new spend script serialization format is as follows: +=== Script Validation === - OP_PUSHNUM_3 HASH256([HASH256(Public Key Bytes at Attestation Index 0)][HASH256(PK Q1)][..]) +To spend a P2QRH output, the following conditions must be met: -Addresses then encode this script using bech32m. +1. The scriptPubKey must be of the form: -32-byte attestation fields are assumed to be Schnorr public keys for Taproot fields because they are ordinarily included in the spend script, but they cannot be included in P2QRH for security reasons. Public key / signature pairs for Taproot fields come before QuBit public key / signature pairs. + +OP_PUSHNUM_3 <32-byte hash> + -The exact key type is inferred by its size, as provided by the attestation variant pair, which determines whether it's processed as secp256k1 Schnorr, SPHINCS, XMSS, FALCON, or SQIsign. +2. The attestation must include: -If the transaction fails to include the public keys needed to match the spend script hash, it is an invalid transaction because the cryptographic commitment for the keys has not been met. Consequently, only valid public keys and signatures can be included within the attestation and no other data. +** The quantum-resistant public key(s) whose HASH256 concatenated and hashed again matches the in the scriptPubKey. +** Valid signatures corresponding to the public key(s) and the transaction data. +3. For multi-signature schemes, all required public keys and signatures must be provided for that input within the attestation. This includes classical Schnorr signatures. -=== Public Key Generation === -TBD, pending test vectors +==== Public Key Hashing ==== -=== Public Key Conversion === +All public keys included in the attestation are hashed using HASH256 (double SHA-256). The concatenation of these hashes is then hashed again using HASH256 before being included in the scriptPubKey. This ensures a fixed-size commitment to potentially multiple public keys of varying lengths. -TBD +'''Hash Computation:''' -=== Signing === + +hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN)) + -TBD -=== Verification === +==== Sighash Calculation ==== -TBD +The sighash for P2QRH outputs follows the same procedure as defined in BIP-0143 for SegWit transactions: + +* '''Hash Prevouts:''' Computed over the previous outputs being spent. +* '''Hash Sequence:''' Computed over the sequence fields. +* '''Hash Outputs:''' Computed over the outputs of the transaction. + +The message to be signed includes these hashes, ensuring transaction malleability is prevented. + +==== Signature Verification ==== + +Signature verification is as follows: + +1. Extract the from the scriptPubKey. +2. For each input: +** Compute hashed_pubkeys by concatenating the HASH256 of each provided public key. + +hashed_pubkeys = HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN) + +** Compute computed_hash + +computed_hash = HASH256(hashed_pubkeys) + +** Compare the resulting hash to . If they do not match, the script fails. +3. Verify each signature against the corresponding public key and the sighash. +4. Ensure that the signature algorithm used matches the expected lengths for NIST Level V security and is supported. + +==== Attestation Parsing Example ==== + +Signing for a single input using both FALCON-1024 and secp256k1 Schnorr: + +* [num_pubkeys]: 0x02 +** '''Pubkey 1:''' +*** [pubkey_length]: 0x0701 (1793 bytes) +*** [pubkey]: public_key_falcon_1024 +** '''Pubkey 2:''' +*** [pubkey_length]: 0x20 (32 bytes) +*** [pubkey]: public_key_secp256k1 +* [num_signatures]: 0x02 +** '''Signature 1:''' +*** [signature_length]: 0x0500 (1280 bytes) +*** [signature]: signature_falcon_1024 +** '''Signature 2:''' +*** [signature_length]: 0x40 (64 bytes) +*** [signature]: signature_secp256k1 + +Note: This contrasts with multisig inputs, where the attestation structure repeats for each public key and signature. === Usage Considerations === -TBD +==== Transaction Size and Fees ==== + +Quantum-resistant signatures are significantly larger than traditional signatures, increasing transaction size and the fees required. Users and wallet developers should be aware of this and plan accordingly. + +For example, for CRYSTALS-Dilithium Level V, a single signature is 4595 bytes, a substantial increase over current ECDSA or Schnorr signatures. + + +==== Performance Impact ==== + +Verification of quantum-resistant signatures will be computationally more intensive, and any attestation discount will also increase storage requirements. Node operators should consider the potential impact on resource usage in the long term. Developers may need to optimize signature verification implementations, especially by implementing caching for key generation. + + +==== Algorithm Selection ==== + +Introducing four quantum-resistant algorithms to the bitcoin ecosystem provides users with the option to select an appropriate algorithm for their use case, generally based on the amount of value they wish to secure. Developers can choose to implement support for multiple algorithms in wallets and on nodes to offer quantum-resistant options. + + +==== Backward Compatibility ==== + +Older wallets and nodes that have not been made compatible with SegWit version 3 and P2QRH will not recognize these outputs. Users should ensure they are using updated wallets and nodes to use P2QRH addresses and validate transactions using P2QRH outputs. + == Test Vectors and Reference Code == @@ -255,6 +414,7 @@ It is worth noting by way of comparison that [https://ethresear.ch/t/how-to-hard To help implementors understand updates to this BIP, we keep a list of substantial changes. +* 2024-12-01 - Add details on attestation structure and parsing. * 2024-11-20 - Clarifications based on feedback from Murch. Remove some sections that are not yet ready. * 2024-10-21 - Replace XMSS with CRYSTALS-Dilithium due to NIST approval and size constraints. * 2024-09-30 - Refactor the ECC vs PoW section. Swap quitness for attestation. @@ -267,4 +427,4 @@ To help implementors understand updates to this BIP, we keep a list of substanti This document is inspired by [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341], which introduced the design of the P2TR (Taproot) address type using Schnorr signatures. -Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name "QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as well to those who took the time to review and contribute, including Adam Borcany, Antoine Riard, Pierre-Luc Dallaire-Demers, Ethan Heilman, Jon Atack, Jameson Lopp, and Murchandamus. +Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name "QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as well to those who took the time to review and contribute, including Jeff Bride, Adam Borcany, Antoine Riard, Pierre-Luc Dallaire-Demers, Ethan Heilman, Jon Atack, Jameson Lopp, and Murchandamus. From 60d72942aa23a760a5c50df48b86f88c71d0915d Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Tue, 3 Dec 2024 16:22:21 -0700 Subject: [PATCH 010/131] MediaWiki formatting fixes --- bip-p2qrh.mediawiki | 59 ++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index 5d715417bb..bfd6043e6e 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -291,27 +291,27 @@ To spend a P2QRH output, the following conditions must be met: 1. The scriptPubKey must be of the form: - +
 OP_PUSHNUM_3 <32-byte hash>
-
+
2. The attestation must include: -** The quantum-resistant public key(s) whose HASH256 concatenated and hashed again matches the in the scriptPubKey. -** Valid signatures corresponding to the public key(s) and the transaction data. +* The quantum-resistant public key(s) whose HASH256 concatenated and hashed again matches the in the scriptPubKey. +* Valid signatures corresponding to the public key(s) and the transaction data. 3. For multi-signature schemes, all required public keys and signatures must be provided for that input within the attestation. This includes classical Schnorr signatures. ==== Public Key Hashing ==== -All public keys included in the attestation are hashed using HASH256 (double SHA-256). The concatenation of these hashes is then hashed again using HASH256 before being included in the scriptPubKey. This ensures a fixed-size commitment to potentially multiple public keys of varying lengths. +All public keys included in the attestation are hashed using HASH256 (double SHA-256). The concatenation of these hashes is then hashed again using HASH256 before being included in the
scriptPubKey
. This ensures a fixed-size commitment to potentially multiple public keys of varying lengths. '''Hash Computation:''' - +
 hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN))
-
+
==== Sighash Calculation ==== @@ -328,38 +328,46 @@ The message to be signed includes these hashes, ensuring transaction malleabilit Signature verification is as follows: -1. Extract the from the scriptPubKey. +1. Extract the
from the
scriptPubKey
. + 2. For each input: -** Compute hashed_pubkeys by concatenating the HASH256 of each provided public key. - + +* Compute
hashed_pubkeys
by concatenating the HASH256 of each provided public key. + +
 hashed_pubkeys = HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN)
-
-** Compute computed_hash
-
+
+ +* Compute
computed_hash
+ +
 computed_hash = HASH256(hashed_pubkeys)
-
-** Compare the resulting hash to . If they do not match, the script fails.
+
+ +* Compare the resulting hash to
. If they do not match, the script fails. + 3. Verify each signature against the corresponding public key and the sighash. + 4. Ensure that the signature algorithm used matches the expected lengths for NIST Level V security and is supported. ==== Attestation Parsing Example ==== Signing for a single input using both FALCON-1024 and secp256k1 Schnorr: -* [num_pubkeys]: 0x02 +*
[num_pubkeys]
:
0x02
** '''Pubkey 1:''' -*** [pubkey_length]: 0x0701 (1793 bytes) -*** [pubkey]: public_key_falcon_1024 +***
[pubkey_length]
:
0x0701
(1793 bytes) +***
[pubkey]
:
public_key_falcon_1024
** '''Pubkey 2:''' -*** [pubkey_length]: 0x20 (32 bytes) -*** [pubkey]: public_key_secp256k1 -* [num_signatures]: 0x02 +***
[pubkey_length]
:
0x20
(32 bytes) +***
[pubkey]
:
public_key_secp256k1
+*
[num_signatures]
:
0x02
** '''Signature 1:''' -*** [signature_length]: 0x0500 (1280 bytes) -*** [signature]: signature_falcon_1024 +***
[signature_length]
:
0x0500
(1280 bytes) +***
[signature]
:
signature_falcon_1024
** '''Signature 2:''' -*** [signature_length]: 0x40 (64 bytes) -*** [signature]: signature_secp256k1 +***
[signature_length]
:
0x40
(64 bytes) +***
[signature]
:
signature_secp256k1
Note: This contrasts with multisig inputs, where the attestation structure repeats for each public key and signature. @@ -414,6 +422,7 @@ It is worth noting by way of comparison that [https://ethresear.ch/t/how-to-hard To help implementors understand updates to this BIP, we keep a list of substantial changes. +* 2024-12-03 - MediaWiki formatting fixes. * 2024-12-01 - Add details on attestation structure and parsing. * 2024-11-20 - Clarifications based on feedback from Murch. Remove some sections that are not yet ready. * 2024-10-21 - Replace XMSS with CRYSTALS-Dilithium due to NIST approval and size constraints. From 2d098d9adf11929234258793e22776a0e2ddb9fa Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Thu, 5 Dec 2024 09:04:28 -0700 Subject: [PATCH 011/131] MediaWiki formatting fixes --- bip-p2qrh.mediawiki | 60 +++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index bfd6043e6e..af2483ec6c 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -162,9 +162,9 @@ Where: ===== Hash Computation ===== - +
 hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN))
-
+
This construction creates a cryptographic commitment to multiple public keys. @@ -305,9 +305,10 @@ OP_PUSHNUM_3 <32-byte hash> ==== Public Key Hashing ==== -All public keys included in the attestation are hashed using HASH256 (double SHA-256). The concatenation of these hashes is then hashed again using HASH256 before being included in the
scriptPubKey
. This ensures a fixed-size commitment to potentially multiple public keys of varying lengths. +All public keys included in the attestation are hashed using HASH256 (double SHA-256). The concatenation of these hashes is then hashed again using HASH256 before being included in the scriptPubKey. This ensures a fixed-size commitment to potentially multiple public keys of varying lengths. -'''Hash Computation:''' + +==== Hash Computation ====
 hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN))
@@ -328,23 +329,23 @@ The message to be signed includes these hashes, ensuring transaction malleabilit
 
 Signature verification is as follows:
 
-1. Extract the 
from the
scriptPubKey
. +1. Extract the from the scriptPubKey. 2. For each input: -* Compute
hashed_pubkeys
by concatenating the HASH256 of each provided public key. + * Compute hashed_pubkeys by concatenating the HASH256 of each provided public key: -
+     
 hashed_pubkeys = HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN)
-
+
-* Compute
computed_hash
+ * Compute computed_hash: -
+     
 computed_hash = HASH256(hashed_pubkeys)
-
+
-* Compare the resulting hash to
. If they do not match, the script fails. + * Compare the resulting hash to . If they do not match, the script fails. 3. Verify each signature against the corresponding public key and the sighash. @@ -354,20 +355,27 @@ computed_hash = HASH256(hashed_pubkeys) Signing for a single input using both FALCON-1024 and secp256k1 Schnorr: -*
[num_pubkeys]
:
0x02
-** '''Pubkey 1:''' -***
[pubkey_length]
:
0x0701
(1793 bytes) -***
[pubkey]
:
public_key_falcon_1024
-** '''Pubkey 2:''' -***
[pubkey_length]
:
0x20
(32 bytes) -***
[pubkey]
:
public_key_secp256k1
-*
[num_signatures]
:
0x02
-** '''Signature 1:''' -***
[signature_length]
:
0x0500
(1280 bytes) -***
[signature]
:
signature_falcon_1024
-** '''Signature 2:''' -***
[signature_length]
:
0x40
(64 bytes) -***
[signature]
:
signature_secp256k1
+
+[num_pubkeys]: 0x02
+
+Pubkey 1:
+  [pubkey_length]: 0x0701 (1793 bytes)
+  [pubkey]: public_key_falcon_1024
+
+Pubkey 2:
+  [pubkey_length]: 0x20 (32 bytes)
+  [pubkey]: public_key_secp256k1
+
+[num_signatures]: 0x02
+
+Signature 1:
+  [signature_length]: 0x0500 (1280 bytes)
+  [signature]: signature_falcon_1024
+
+Signature 2:
+  [signature_length]: 0x40 (64 bytes)
+  [signature]: signature_secp256k1
+
Note: This contrasts with multisig inputs, where the attestation structure repeats for each public key and signature. From ed4e8627e67c8404c297e451fa3620dd8f85e5a6 Mon Sep 17 00:00:00 2001 From: Hunter Beast Date: Fri, 6 Dec 2024 08:29:44 -0700 Subject: [PATCH 012/131] MediaWiki fixes, remove redundant sections. (#16) * MediaWiki fixes, remove redundant sections. * Fix link format check --- bip-p2qrh.mediawiki | 284 ++++++++++++++++++++------------------------ 1 file changed, 126 insertions(+), 158 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index af2483ec6c..f79473c28f 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -16,29 +16,27 @@ This document proposes the introduction of a new output type using signatures based on Post-Quantum Cryptography (PQC). This approach for adding a post-quantum secure output type does not require a hard fork or block size increase. - === Copyright === This document is licensed under the 3-clause BSD license. - === Motivation === -This proposal aims to improve the quantum resistance of bitcoin's signature security should the Discrete Logarithm Problem (DLP) which secures Elliptic Curve Cryptography (ECC) no longer prove to be computationally hard, likely through quantum advantage by Cryptoanalytically-Relevant Quantum Computers (CRQCs). [https://arxiv.org/pdf/quant-ph/0301141 A variant of Shor's algorithm] is believed to be capable of deriving the private key from a public key exponentially faster than classical means. The application of this variant of Shor's algorithm is herein referred to as quantum key decryption. Note that doubling the public key length, such as with a hypothetical secp512k1 curve, would only make deriving the private key twice as hard. The computational complexity of this is investigated further in the paper, [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault tolerant regime'']. +This proposal aims to improve the quantum resistance of Bitcoin's signature security should the Discrete Logarithm Problem (DLP), which secures Elliptic Curve Cryptography (ECC), no longer prove to be computationally hard, likely through quantum advantage by Cryptoanalytically-Relevant Quantum Computers (CRQCs). [https://arxiv.org/pdf/quant-ph/0301141 A variant of Shor's algorithm] is believed to be capable of deriving the private key from a public key exponentially faster than classical means. The application of this variant of Shor's algorithm is herein referred to as quantum key decryption. Note that doubling the public key length, such as with a hypothetical secp512k1 curve, would only make deriving the private key twice as hard. The computational complexity of this is investigated further in the paper, [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault tolerant regime'']. -The primary threat to Bitcoin by CRQCs is [https://en.bitcoi.it/wiki/Quantum_computing_and_Bitcoin#QC_attacks generally considered to be their potential to break ECC, which is used in signatures and Taproot commitments], hence the focus on a new address format. Shor's algorithm enables a CRQC to break the cryptographic assumptions of ECC in roughly 10^8 quantum operations. +The primary threat to Bitcoin by CRQCs is [https://en.bitcoin.it/wiki/Quantum_computing_and_Bitcoin#QC_attacks generally considered to be their potential to break ECC, which is used in signatures and Taproot commitments], hence the focus on a new address format. Shor's algorithm enables a CRQC to break the cryptographic assumptions of ECC in roughly 10^8 quantum operations. -The vulnerability of existing bitcoin addresses is investigated in [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the bitcoin supply is held within addresses vulnerable to quantum attack. As of the time of writing, that number is now closer to 20%. Additionally, cryptographer Pieter Wuille [https://x.com/pwuille/status/1108085284862713856 reasons] even more might be vulnerable. +The vulnerability of existing Bitcoin addresses is investigated in [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the Bitcoin supply is held within addresses vulnerable to quantum attack. As of the time of writing, that number is now closer to 20%. Additionally, cryptographer Pieter Wuille [https://x.com/pwuille/status/1108085284862713856 reasons] even more might be vulnerable. Ordinarily, when a transaction is signed, the public key can be recovered from the signature. This makes a transaction submitted to the mempool vulnerable to quantum attack until it's mined. One way to mitigate this is to submit the transaction directly to a mining pool, which bypasses the mempool. This process is known as an out-of-band transaction. The mining pool must be trusted not to reveal the transaction public key to attackers. The problem with this approach is that it requires a trusted third party, which is what this P2QRH proposal aims to avoid. -Not having public keys exposed on-chain is an important step for quantum security. Otherwise funds would need to be spent to new addresses on a regular basis in order to prevent the possibility of a "long-range CRQC attack" recovering the key behind high value addresses. A long-range quantum attack can be considered one performed with chain data, such as that from a used address or one encoded in a spend script. This is likely to be more common early on, as early quantum computers must be run for longer in order to overcome errors caused by noise. A "short-range quantum attack" would be one performed on keys in the mempool, which is seen as much more difficult given the block time, and so it requires more sophisticated CRQCs. As the value being sent increases, so too should the fee in order to commit the transaction to the chain as soon as possible. Once the transaction is mined, it makes useless the public key revealed by spending a UTXO, so long as it is never reused. +Not having public keys exposed on-chain is an important step for quantum security. Otherwise, funds would need to be spent to new addresses on a regular basis in order to prevent the possibility of a "long-range CRQC attack" recovering the key behind high-value addresses. A long-range quantum attack can be considered one performed with chain data, such as that from a used address or one encoded in a spend script. This is likely to be more common early on, as early quantum computers must be run for longer in order to overcome errors caused by noise. A "short-range quantum attack" would be one performed on keys in the mempool, which is seen as much more difficult given the block time, and so it requires more sophisticated CRQCs. As the value being sent increases, so too should the fee in order to commit the transaction to the chain as soon as possible. Once the transaction is mined, it makes useless the public key revealed by spending a UTXO, so long as it is never reused. It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) address type that relies on a PQC signature algorithm. This new address type protects transactions submitted to the mempool and helps preserve the free market by preventing the need for private, out-of-band mempool transactions. -The following table is non-exhaustive but intended to inform the average bitcoin user whether their bitcoin is vulnerable to a long-range quantum attack. +The following table is non-exhaustive but intended to inform the average Bitcoin user whether their bitcoin is vulnerable to a long-range quantum attack. -{| +{| class="wikitable" |+ Vulnerable address types |- ! Address type !! Vulnerable !! Prefix !! Example @@ -58,7 +56,7 @@ If a key is recovered by a CRQC it can also be trivially checked to see if any c The following table summarizes the scenarios in which public keys are revealed when using Bitcoin and what type of attack the underlying addresses are vulnerable to: -{| +{| class="wikitable" |+ Scenarios for revealed public keys on Bitcoin |- ! Scenario !! Type of attack @@ -80,15 +78,15 @@ Should quantum advantage manifest, a convention is proposed in spending the full As an interesting aside, coinbase outputs to P2PK keys go as far as block 200,000, so there are 1,723,848 coins that are vulnerable from the first epoch at the time of writing in P2PK outputs alone. Since the majority of these have a block reward of 50 coins each, there are roughly 34,000 distinct P2PK addresses that are vulnerable. These coins can be considered "Satoshi's Shield." Any addresses with a balance of less than the original block subsidy of 50 coins can be considered incentive incompatible to capture until all of these are mined, and these addresses serve to provide time to transition Bitcoin to implement post-quantum security. -It's for the above reason that, for those who wish to be prepared for quantum emergency, it is recommended that no more than 50 bitcoin are kept under a single, distinct, unused Native SegWit (P2WPKH, "bc1q") address at a time. This is assuming that the attacker is financially-motivated instead of, for example, a nation state looking to break confidence in Bitcoin. Additionally, this assumes that other vulnerable targets such as central banks have upgraded their cryptography by this time. +It's for the above reason that, for those who wish to be prepared for quantum emergency, it is recommended that no more than 50 bitcoin are kept under a single, distinct, unused Native SegWit (P2WPKH, "bc1q") address at a time. This is assuming that the attacker is financially motivated instead of, for example, a nation state looking to break confidence in Bitcoin. Additionally, this assumes that other vulnerable targets such as central banks have upgraded their cryptography by this time. The Commercial National Security Algorithm Suite (CNSA) 2.0 has a timeline for software and networking equipment to be upgraded by 2030, with browsers and operating systems fully upgraded by 2033. According to NIST IR 8547, Elliptic Curve Cryptography is planned to be disallowed within the US Federal government after 2035. An exception is made for hybrid cryptography, which is the use of ECC and post-quantum algorithms together. -Although CRQCs could pose a threat to the signatures used in Bitcoin, a smaller threat is to Bitcoin's hash algorithms. In particular, while a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a quadratic speed up on brute force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes using Grover's algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques’ post on this]. +Although CRQCs could pose a threat to the signatures used in Bitcoin, a smaller threat is to Bitcoin's hash algorithms. In particular, while a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a quadratic speedup on brute-force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160Used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes. using Grover's algorithm would require at least 1024 quantum operations. As for Grover's application to mining, see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques’ post on this]. === Rationale === -This is the first in a series of BIPs under a QuBit soft fork. A qubit is a fundamental unit of quantum computing, and the capital B refers to bitcoin. The name QuBit also rhymes to some extent with SegWit. +This is the first in a series of BIPs under a QuBit soft fork. A qubit is a fundamental unit of quantum computing, and the capital B refers to Bitcoin. The name QuBit also rhymes to some extent with SegWit. It is proposed to use SegWit version 3. This results in addresses that start with bc1r, which could be a useful way to remember that these are quantum (r)esistant addresses (similar to how bc1q corresponds to Se(q)Wit and bc1p corresponds to Ta(p)root). This is referencing the lookup table under [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. @@ -98,11 +96,11 @@ P2QRH is meant to be implemented on top of P2TR, combining the security of class P2QRH uses a 32-byte HASH256 (specifically SHA-256 twice-over, which is similar to that used in [https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#specification BIP-16]) of the public key to reduce the size of new outputs and also to increase security by not having the public key available on-chain. This hash serves as a minimal cryptographic commitment to a public key. It goes into the output spend script, which does not receive the witness discount. -Post-quantum public keys are generally larger than those used by ECC, depending on the security level. To promote user adoption and general user-friendliness, the most secure variant (NIST V, 256 bit) is proposed, despite the increase in key length and verification time. +Post-quantum public keys are generally larger than those used by ECC, depending on the security level. To promote user adoption and general user-friendliness, the most secure variant (NIST Level V, 256-bit security) is proposed, despite the increase in key length and verification time. Support for FALCON signatures will be introduced first, with the intention of adding SQIsign and other post-quantum algorithms as they are approved. By way of comparison, FALCON signatures are roughly 4x larger than SQIsign signatures and 20x larger than Schnorr signatures. FALCON is a more conservative approach to applied lattice cryptography than SQIsign, and its use has recently been approved by NIST. NIST approval streamlines implementations through establishing consensus in the scientific and developer community. However, even SQIsign signatures are roughly 5x larger than Schnorr signatures. This means, to maintain present transaction throughput, an increase in the witness discount will likely be desired in a QuBit soft fork. That will be specified in a future QuBit BIP. -An increase in the witness discount must not be taken lightly. It must be resistant to applications that might take advantage of this discount (e.g. storage of arbitrary data as seen with "inscriptions") without a corresponding increase in economic activity. An increase in the witness discount would not only impact node runners but those with inscriptions would also have the scarcity of their non-monetary assets affected. The only way to prevent these affects while also increasing the discount is to have a completely separate witness-- a "quantum witness." Because it is meant only for public keys and signatures, we call this section of the transaction the attestation. +An increase in the witness discount must not be taken lightly. It must be resistant to applications that might take advantage of this discount (e.g., storage of arbitrary data as seen with "inscriptions") without a corresponding increase in economic activity. An increase in the witness discount would not only impact node runners but those with inscriptions would also have the scarcity of their non-monetary assets affected. The only way to prevent these effects while also increasing the discount is to have a completely separate witness—a "quantum witness." Because it is meant only for public keys and signatures, we call this section of the transaction the attestation. To address the risk of arbitrary data being stored using P2QRH (QuBit) addresses, very specific rules will be applied to spending from the witness stack in SegWit v3 outputs. A fixed signature size will be necessary for spending the output, and the output must be spendable to be considered valid within node consensus. A fixed signature size will also be helpful to disambiguate between signature types without an additional version byte, as SQIsign signatures are substantially smaller than FALCON signatures. Consequently, the correct signature algorithm can be inferred through byte length. The public key and signature will be pushed separately to the attestation stack. Multiple signatures can be included in order to support multisig applications, and also for spending multiple inputs. @@ -110,57 +108,48 @@ Since only valid signatures can be committed to in a SegWit v3 attestation, arbi Additionally, it should be noted, whether an output with a P2QRH spend script corresponds to a FALCON or SQIsign signature is not known until the output is spent. -While it might be seen as a maintenance burden for bitcoin ecosystem devs to go from a single cryptosystem implementation to four additional distinct PQC cryptosystems-- and it most certainly is-- the ramifications of a chain broken through extrinsic factors should provide sufficient motivation. An increase in software maintenance everywhere signatures are used should be seen as an acceptable compromise for maintained integrity of bitcoin transfers during a regime of quantum advantage. +While it might be seen as a maintenance burden for Bitcoin ecosystem devs to go from a single cryptosystem implementation to four additional distinct PQC cryptosystems—and it most certainly is—the ramifications of a chain broken through extrinsic factors should provide sufficient motivation. An increase in software maintenance everywhere signatures are used should be seen as an acceptable compromise for maintained integrity of Bitcoin transfers during a regime of quantum advantage. -The inclusion of these four cryptosystems: SPHINCS, CRYSTALS-Dilithium, FALCON, and SQIsign have various advocates within the community due to their varying security assumptions. Hash-based cryptosystems are more conservative, time-tested, and well-reviewed. Lattice cryptography is relatively new and introduces novel security assumptions to Bitcoin, but their signatures are smaller and might be considered by some to be an adequate alternative to Hash-based signatures. SQIsign is much smaller, however, it is based on a very novel form of cryptography known as supersingular elliptic curve quaternion isogeny, and at the time of writing, is not yet approved by NIST or the broader PQC community. +The inclusion of these four cryptosystems: SPHINCS+, CRYSTALS-Dilithium, FALCON, and SQIsign have various advocates within the community due to their varying security assumptions. Hash-based cryptosystems are more conservative, time-tested, and well-reviewed. Lattice cryptography is relatively new and introduces novel security assumptions to Bitcoin, but their signatures are smaller and might be considered by some to be an adequate alternative to hash-based signatures. SQIsign is much smaller; however, it is based on a very novel form of cryptography known as supersingular elliptic curve quaternion isogeny, and at the time of writing, is not yet approved by NIST or the broader PQC community. In the distant future, following the implementation of the P2QRH address format in a QuBit soft fork, there will likely be a need for Pay to Quantum Secure (P2QS) addresses. These will require specialized quantum hardware for signing, while still [https://quantum-journal.org/papers/q-2023-01-19-901/ using public keys that are verifiable via classical means]. Additional follow-on BIPs will be needed to implement P2QS. However, until specialized quantum cryptography hardware is widespread, quantum resistant addresses should be an adequate intermediate solution. +== Specification == -== Description == - -We first build up a definition of the signature scheme by going through the design choices. Afterwards, we specify the exact encodings and operations. - - -=== Design === +We define the signature scheme and transaction structure as follows. -==== Descriptor Format ==== +=== Descriptor Format === To integrate P2QRH into existing wallet software and scripts, we introduce a new output descriptor function qrh(). This function represents a P2QRH output, similar to how wpkh() and tr() are used for P2WPKH and P2TR outputs, respectively. The qrh() function takes the HASH256 of the concatenated HASH256 of the quantum-resistant public keys as its argument. For example: - -qrh(HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ...)) - - -The above function allows wallets to manage P2QRH addresses and outputs while accommodating multiple public keys of varying lengths, such as in multisig schemes, while keeping the public keys hidden until the time of spending. +qrh(HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ...)) +This function allows wallets to manage P2QRH addresses and outputs while accommodating multiple public keys of varying lengths, such as in multisig schemes, while keeping the public keys hidden until the time of spending. -==== Address Format ==== +=== Address Format === -P2QRH uses SegWit version 3 outputs, resulting in addresses that start with bc1r, following [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. Bech32 encoding maps version 3 to the prefix r. +P2QRH uses SegWit version 3 outputs, resulting in addresses that start with bc1r, following [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. Bech32 encoding maps version 3 to the prefix r. Example P2QRH address: - -bc1r... (32-byte Bech32m-encoded HASH256 of the HASH256 of the public keys) - +bc1r... (32-byte Bech32m-encoded HASH256 of the HASH256 of the public keys) -==== ScriptPubKey ==== +=== ScriptPubKey === The scriptPubKey for a P2QRH output is: - +
 OP_PUSHNUM_3 OP_PUSHBYTES_32 
-
+
Where: -* OP_PUSHNUM_3 (0x03) indicates SegWit version 3. -* is the 32-byte HASH256 of the concatenated HASH256 of each public key. +- OP_PUSHNUM_3 (0x03) indicates SegWit version 3. +- is the 32-byte HASH256 of the concatenated HASH256 of each public key. -===== Hash Computation ===== +==== Hash Computation ====
 hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN))
@@ -168,128 +157,68 @@ hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN))
 
 This construction creates a cryptographic commitment to multiple public keys.
 
-==== Transaction Serialization ====
+=== Transaction Serialization ===
 
 Following BIP-141, the transaction serialization is modified to include a new attestation field after the witness field:
 
-
+
 [nVersion][marker][flag][txins][txouts][witness][attestation][nLockTime]
-
+
-* marker: 0x00 (same as SegWit) -* flag: 0x02 (indicates the presence of both witness and attestation data) -* attestation: Contains the quantum-resistant public keys and signatures. +- marker: 0x00 (same as SegWit) +- flag: 0x02 (indicates the presence of both witness and attestation data) +- attestation: Contains the quantum-resistant public keys and signatures. -==== Attestation Structure ==== +=== Attestation Structure === The attestation field consists of: * num_pubkeys: The number of public keys (VarInt encoded). -* For each public key: -** pubkey_length: VarInt encoded length of the public key. -** pubkey: The public key bytes. + +For each public key: + +* pubkey_length: VarInt encoded length of the public key. +* pubkey: The public key bytes. + +Then: + * num_signatures: The number of signatures (VarInt encoded). -* For each signature: -** signature_length: VarInt encoded length of the signature. -** signature: The signature bytes. + +For each signature: + +* signature_length: VarInt encoded length of the signature. +* signature: The signature bytes. This structure repeats for each input, in order, for flexibility in supporting multisig schemes and various quantum-resistant algorithms. For each input, a separate attestation field is used. To know how many attestation fields are present, implementations must count the number of inputs present in the transaction. -The specific algorithm is determined by the size of the public key and signature, as described in the next section. - -==== Signature Algorithm Identification ==== +=== Signature Algorithm Identification === The specific quantum-resistant signature algorithm used is inferred from the length of the public key and signature. Implementations must recognize the supported algorithms and validate accordingly. Supported algorithms and their NIST Level V parameters: * '''SPHINCS+-256f:''' -** Public Key Length: 64 bytes -** Signature Length: 49,856 bytes -* '''CRYSTALS-Dilithium Level 5''': -** Public Key Length: 2,592 bytes -** Signature Length: 4,595 bytes -* '''FALCON-1024''': -** Public Key Length: 1,793 bytes -** Signature Length: 1,280 bytes -* '''SQIsign NIST-V''': -** Public Key Length: 128 bytes -** Signature Length: 335 bytes + * Public Key Length: 64 bytes + * Signature Length: 49,856 bytes +* '''CRYSTALS-Dilithium Level 5:''' + * Public Key Length: 2,592 bytes + * Signature Length: 4,595 bytes +* '''FALCON-1024:''' + * Public Key Length: 1,793 bytes + * Signature Length: 1,280 bytes +* '''SQIsign NIST-V:''' + * Public Key Length: 128 bytes + * Signature Length: 335 bytes Implementations must reject public keys and signatures that do not match expected lengths for supported algorithms. -==== Compatibility with BIP-141 ==== - -By adhering to the SegWit transaction structure and versioning, P2QRH outputs are compatible with existing transaction processing rules. Nodes that do not recognize SegWit version 3 will treat these outputs as anyone-can-spend but, per BIP-141, will not relay or mine such transactions. - - -== Security == - -{| -|+ Candidate quantum resistant signature algorithms ordered by largest to smallest NIST V signature size -|- -! Signature Algorithm !! Year First Introduced !! Signature Size !! Public Key Size || Cryptographic Assumptions -|- -| [https://en.wikipedia.org/wiki/Lamport_signature Lamport signature] || 1977 || 8192 bytes || 16384 bytes || Hash-based cryptography -|- -| [https://eprint.iacr.org/2011/191.pdf Winternitz signature] || 1982 || 2368 bytes* || 2368 bytesFootnote: Winternitz signatures are much smaller than Lamport signatures due to efficient chunking, but computation is much higher, especially with high values for w. Winternitz values are for w of 4. || Hash-based cryptography -|- -| [https://sphincs.org/data/sphincs+-r3.1-specification.pdf SPHINCS+ Rd. 3.1 (FIPS 205 - SLH-DSA)] || 2015 || 29792 bytes || 64 bytes || Hash-based cryptography -|- -| [https://eprint.iacr.org/2011/484.pdf XMSS]XMSS, which is based on Winternitz, uses a value of 108 for its most compact signature size, with only a 4.6x (2.34/0.51) increase in verification time. Signing and key generation are not considered a significant factor because they are not distributed throughout the entire Bitcoin network, which take place only inside of wallets one time. || 2011 || 15384 bytes || 13568 bytes || Hash-based cryptography (Winternitz OTS) -|- -| [https://pq-crystals.org/dilithium/ CRYSTALS-Dilithium (FIPS 204 - ML-DSA)] || 2017 || 4595 bytes || 2592 bytes || Lattice cryptography -|- -| [https://eprint.iacr.org/2014/457.pdf pqNTRUsign] || 2016 || 1814 bytes || 1927 bytes || Lattice cryptography (NTRU) -|- -| [https://falcon-sign.info FALCON (FIPS 206 - FN-DSA)] || 2017 || 1280 bytes || 1793 bytes || Lattice cryptography (NTRU) -|- -| [https://eprint.iacr.org/2022/1155.pdf HAWK] || 2022 || 1261 bytes || 2329 bytes || Lattice cryptography -|- -| [https://sqisign.org SQIsign] || 2023 || 335 bytes || 128 bytes || Supersingular Elliptic Curve Isogeny -|- -| [https://eprint.iacr.org/2024/760.pdf SQIsign2D-West] || 2024 || 294 bytes || 130 bytes || Supersingular Elliptic Curve Isogeny -|- -| [https://eprint.iacr.org/2023/436.pdf SQIsignHD] || 2023 || 109 bytes (NIST I) || not provided || Supersingular Elliptic Curve Isogeny -|} - - -As shown, supersingular elliptic curve quaternion isogeny signature algorithms represent the state of the art in post-quantum cryptography, beyond lattice cryptography alone, especially when key and signature length are major constraints. This makes inclusion of SQIsign attractive, and support is planned, but it will be some time until it is approved for production use. Meanwhile, SPHINCS+ and CRYSTALS-Dilithium signatures are already approved and have achieved broader community consensus. FALCON signatures are also NIST approved. - -In comparison, the size of currently used signature algorithms are: - -* ECDSA - 70-72 bytes -* Schnorr - 64 bytes - -In comparison to inception date, secp256k1 [https://www.secg.org/SEC1-Ver-1.0.pdf was originally specified in 2000]. - -One consideration for choosing an algorithm is its maturity. secp256k1 was already 8 years old by the time it was chosen as bitcoin's curve. Isogeny cryptography when it was first introduced was broken over a weekend. - -Ideally SQIsign also proves to be flexible enough to support [https://www.pierrickdartois.fr/homepage/wp-content/uploads/2022/04/Report_OSIDH_DARTOIS.pdf Isogeny Diffie-Hellman] to replace ECDH applications, and also provide methods for the key tweaking necessary to support TapScript for P2QR addresses. Additionally, isogeny-based post-quantum cryptography is based on higher-order elliptic curves, and so it might be possible to implement Isogeny Schnorr signatures. - -Signature verification speed as it compares to Schnorr or ECDSA isn't seen as high a consideration as signature size due to block space being the primary fee constraint. As a P2QRH implementation materializes, a benchmark will be added for performance comparison. Fortunately, SQIsign signatures are substantially faster to verify than it is to generate keys or to sign, which is a major consideration when a transaction need only be signed once, or a handful of times with PSBT, compared to being verified simultaneously on tens of thousands of nodes. Key generation may need to cached in BIP-32 Hierarchical Deterministic wallets. - -An additional consideration is security level. Longer signature sizes provide more security. NIST has standardized five security levels for post-quantum cryptography. NIST security level I provides security equivalent to 128-bit keys, and security level V provides 256-bit security. - - -== Specification == - -How the attestation is differentiated from the witness can be accomplished similar to how [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#user-content-Transaction_ID BIP-141] introduced the marker and flag, with the QuBit flag being set to 0x02. This means all QuBit transactions are also SegWit transactions. The additional data would be included as a second array of byte arrays following the witness stack. - -32-byte attestation fields are assumed to be Schnorr public keys for Taproot fields because they are ordinarily included in the spend script, but they cannot be included in P2QRH for security reasons. Public key / signature pairs for Taproot fields come before QuBit public key / signature pairs. - -The exact key type is inferred by its size, as provided by the attestation variant pair, which determines whether it's processed as secp256k1 Schnorr, SPHINCS, CRYSTALS-Dilithium, FALCON, or SQIsign. - -If the transaction fails to include the public keys needed to match the spend script hash, it is an invalid transaction because the cryptographic commitment for the keys has not been met. Consequently, only valid public keys and signatures can be included within the attestation and no other data. - - === Script Validation === To spend a P2QRH output, the following conditions must be met: -1. The scriptPubKey must be of the form: +1. The scriptPubKey must be of the form:
 OP_PUSHNUM_3 <32-byte hash>
@@ -297,16 +226,14 @@ OP_PUSHNUM_3 <32-byte hash>
 
 2. The attestation must include:
 
-* The quantum-resistant public key(s) whose HASH256 concatenated and hashed again matches the  in the scriptPubKey.
+* The quantum-resistant public key(s) whose HASH256 concatenated and hashed again matches the  in the scriptPubKey.
 * Valid signatures corresponding to the public key(s) and the transaction data.
 
 3. For multi-signature schemes, all required public keys and signatures must be provided for that input within the attestation. This includes classical Schnorr signatures.
 
-
 ==== Public Key Hashing ====
 
-All public keys included in the attestation are hashed using HASH256 (double SHA-256). The concatenation of these hashes is then hashed again using HASH256 before being included in the scriptPubKey. This ensures a fixed-size commitment to potentially multiple public keys of varying lengths.
-
+All public keys included in the attestation are hashed using HASH256 (double SHA-256). The concatenation of these hashes is then hashed again using HASH256 before being included in the scriptPubKey. This ensures a fixed-size commitment to potentially multiple public keys of varying lengths.
 
 ==== Hash Computation ====
 
@@ -314,7 +241,6 @@ All public keys included in the attestation are hashed using HASH256 (double SHA
 hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN))
 
- ==== Sighash Calculation ==== The sighash for P2QRH outputs follows the same procedure as defined in BIP-0143 for SegWit transactions: @@ -333,19 +259,19 @@ Signature verification is as follows: 2. For each input: - * Compute hashed_pubkeys by concatenating the HASH256 of each provided public key: +* Compute hashed_pubkeys by concatenating the HASH256 of each provided public key: -
-hashed_pubkeys = HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN)
-     
+
+  hashed_pubkeys = HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN)
+
- * Compute computed_hash: +* Compute computed_hash: -
-computed_hash = HASH256(hashed_pubkeys)
-     
+
+  computed_hash = HASH256(hashed_pubkeys)
+
- * Compare the resulting hash to . If they do not match, the script fails. +* Compare the resulting hash to . If they do not match, the script fails. 3. Verify each signature against the corresponding public key and the sighash. @@ -379,39 +305,84 @@ Signature 2: Note: This contrasts with multisig inputs, where the attestation structure repeats for each public key and signature. +=== Compatibility with BIP-141 === + +By adhering to the SegWit transaction structure and versioning, P2QRH outputs are compatible with existing transaction processing rules. Nodes that do not recognize SegWit version 3 will treat these outputs as anyone-can-spend but, per BIP-141, will not relay or mine such transactions. + === Usage Considerations === ==== Transaction Size and Fees ==== Quantum-resistant signatures are significantly larger than traditional signatures, increasing transaction size and the fees required. Users and wallet developers should be aware of this and plan accordingly. -For example, for CRYSTALS-Dilithium Level V, a single signature is 4595 bytes, a substantial increase over current ECDSA or Schnorr signatures. - +For example, for CRYSTALS-Dilithium Level V, a single signature is 4,595 bytes, a substantial increase over current ECDSA or Schnorr signatures. ==== Performance Impact ==== Verification of quantum-resistant signatures will be computationally more intensive, and any attestation discount will also increase storage requirements. Node operators should consider the potential impact on resource usage in the long term. Developers may need to optimize signature verification implementations, especially by implementing caching for key generation. - ==== Algorithm Selection ==== -Introducing four quantum-resistant algorithms to the bitcoin ecosystem provides users with the option to select an appropriate algorithm for their use case, generally based on the amount of value they wish to secure. Developers can choose to implement support for multiple algorithms in wallets and on nodes to offer quantum-resistant options. - +Introducing four quantum-resistant algorithms to the Bitcoin ecosystem provides users with the option to select an appropriate algorithm for their use case, generally based on the amount of value they wish to secure. Developers can choose to implement support for multiple algorithms in wallets and on nodes to offer quantum-resistant options. ==== Backward Compatibility ==== Older wallets and nodes that have not been made compatible with SegWit version 3 and P2QRH will not recognize these outputs. Users should ensure they are using updated wallets and nodes to use P2QRH addresses and validate transactions using P2QRH outputs. +== Security == + +{| class="wikitable" +|+ Candidate quantum-resistant signature algorithms ordered by largest to smallest NIST Level V signature size +|- +! Signature Algorithm !! Year First Introduced !! Signature Size !! Public Key Size !! Cryptographic Assumptions +|- +| [https://en.wikipedia.org/wiki/Lamport_signature Lamport signature] || 1977 || 8,192 bytes || 16,384 bytes || Hash-based cryptography +|- +| [https://eprint.iacr.org/2011/191.pdf Winternitz signature] || 1982 || 2,368 bytesWinternitz signatures are much smaller than Lamport signatures due to efficient chunking, but computation is much higher, especially with high values for w. Winternitz values are for w of 4. || 2,368 bytes || Hash-based cryptography +|- +| [https://sphincs.org/data/sphincs+-r3.1-specification.pdf SPHINCS+ Rd. 3.1 (FIPS 205 - SLH-DSA)] || 2015 || 29,792 bytes || 64 bytes || Hash-based cryptography +|- +| [https://eprint.iacr.org/2011/484.pdf XMSS]XMSS, which is based on Winternitz, uses a value of 108 for its most compact signature size, with only a 4.6x (2.34/0.51) increase in verification time. Signing and key generation are not considered a significant factor because they are not distributed throughout the entire Bitcoin network, which take place only inside of wallets one time. || 2011 || 15,384 bytes || 13,568 bytes || Hash-based cryptography (Winternitz OTS) +|- +| [https://pq-crystals.org/dilithium/ CRYSTALS-Dilithium (FIPS 204 - ML-DSA)] || 2017 || 4,595 bytes || 2,592 bytes || Lattice cryptography +|- +| [https://eprint.iacr.org/2014/457.pdf pqNTRUsign] || 2016 || 1,814 bytes || 1,927 bytes || Lattice cryptography (NTRU) +|- +| [https://falcon-sign.info FALCON (FIPS 206 - FN-DSA)] || 2017 || 1,280 bytes || 1,793 bytes || Lattice cryptography (NTRU) +|- +| [https://eprint.iacr.org/2022/1155.pdf HAWK] || 2022 || 1,261 bytes || 2,329 bytes || Lattice cryptography +|- +| [https://sqisign.org SQIsign] || 2023 || 335 bytes || 128 bytes || Supersingular Elliptic Curve Isogeny +|- +| [https://eprint.iacr.org/2024/760.pdf SQIsign2D-West] || 2024 || 294 bytes || 130 bytes || Supersingular Elliptic Curve Isogeny +|- +| [https://eprint.iacr.org/2023/436.pdf SQIsignHD] || 2023 || 109 bytes (NIST Level I) || Not provided || Supersingular Elliptic Curve Isogeny +|} + +As shown, supersingular elliptic curve quaternion isogeny signature algorithms represent the state of the art in post-quantum cryptography, beyond lattice cryptography alone, especially when key and signature length are major constraints. This makes inclusion of SQIsign attractive, and support is planned, but it will be some time until it is approved for production use. Meanwhile, SPHINCS+ and CRYSTALS-Dilithium signatures are already approved and have achieved broader community consensus. FALCON signatures are also NIST approved. + +In comparison, the size of currently used signature algorithms are: + +- ECDSA: 70-72 bytes +- Schnorr: 64 bytes + +In comparison to inception date, secp256k1 [https://www.secg.org/SEC1-Ver-1.0.pdf was originally specified in 2000]. + +One consideration for choosing an algorithm is its maturity. secp256k1 was already 8 years old by the time it was chosen as Bitcoin's curve. Isogeny cryptography when it was first introduced was broken over a weekend. + +Ideally SQIsign also proves to be flexible enough to support [https://www.pierrickdartois.fr/homepage/wp-content/uploads/2022/04/Report_OSIDH_DARTOIS.pdf Isogeny Diffie-Hellman] to replace ECDH applications, and also provide methods for the key tweaking necessary to support TapScript for P2QR addresses. Additionally, isogeny-based post-quantum cryptography is based on higher-order elliptic curves, and so it might be possible to implement Isogeny Schnorr signatures. + +Signature verification speed as it compares to Schnorr or ECDSA isn't seen as high a consideration as signature size due to block space being the primary fee constraint. As a P2QRH implementation materializes, a benchmark will be added for performance comparison. Fortunately, SQIsign signatures are substantially faster to verify than it is to generate keys or to sign, which is a major consideration when a transaction need only be signed once, or a handful of times with PSBT, compared to being verified simultaneously on tens of thousands of nodes. Key generation may need to be cached in BIP-32 Hierarchical Deterministic wallets. + +An additional consideration is security level. Longer signature sizes provide more security. NIST has standardized five security levels for post-quantum cryptography. NIST security level I provides security equivalent to 128-bit keys, and security level V provides 256-bit security. == Test Vectors and Reference Code == TBD - == Related Work == -It is worth noting by way of comparison that [https://ethresear.ch/t/how-to-hard-fork-to-save-most-users-funds-in-a-quantum-emergency/18901 Vitalik Buterin's proposed solution] in an Ethereum quantum emergency is quite different from the approach in this BIP. His plan involves a hard fork of the chain, reverting all blocks after a sufficient amount of theft, and using STARKs based on BIP-32 seeds to act as the authoritative secret when signing. These measures are deemed far too heavy-handed for bitcoin. - +It is worth noting by way of comparison that [https://ethresear.ch/t/how-to-hard-fork-to-save-most-users-funds-in-a-quantum-emergency/18901 Vitalik Buterin's proposed solution] in an Ethereum quantum emergency is quite different from the approach in this BIP. His plan involves a hard fork of the chain, reverting all blocks after a sufficient amount of theft, and using STARKs based on BIP-32 seeds to act as the authoritative secret when signing. These measures are deemed far too heavy-handed for Bitcoin. == References == @@ -420,12 +391,10 @@ It is worth noting by way of comparison that [https://ethresear.ch/t/how-to-hard * [https://bitcoinops.org/en/newsletters/2024/06/14/ Bitcoin OpTech newsletter] * [https://bitcoinops.org/en/podcast/2024/06/18/#draft-bip-for-quantum-safe-address-format Bitcoin OpTech discussion transcript] - == Footnotes == - == Changelog == To help implementors understand updates to this BIP, we keep a list of substantial changes. @@ -436,10 +405,9 @@ To help implementors understand updates to this BIP, we keep a list of substanti * 2024-10-21 - Replace XMSS with CRYSTALS-Dilithium due to NIST approval and size constraints. * 2024-09-30 - Refactor the ECC vs PoW section. Swap quitness for attestation. * 2024-09-29 - Update section on PoW to include partial-preimage. -* 2024-09-28 - Add Winternitz, XMSS signatures, and security assumption types to PQC table. Omit NIST I table. Add spend script specification. Add revealed public key scenario table. +* 2024-09-28 - Add Winternitz, XMSS signatures, and security assumption types to PQC table. Omit NIST Level I table. Add spend script specification. Add revealed public key scenario table. * 2024-09-27 - Initial draft proposal - == Acknowledgements == This document is inspired by [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341], which introduced the design of the P2TR (Taproot) address type using Schnorr signatures. From f2426c66569a93b393da0f9a9d535184306640d1 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Fri, 6 Dec 2024 10:08:27 -0700 Subject: [PATCH 013/131] Update title and formatting. --- bip-p2qrh.mediawiki | 361 +++++++++++++++++++++++++++++++++----------- 1 file changed, 269 insertions(+), 92 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index f79473c28f..45f6427b24 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -1,6 +1,6 @@
   BIP: TBD
-  Title: QuBit - P2QRH spending rules
+  Title: QuBit: SegWit version 3 spending rules (P2QRH)
   Author: Hunter Beast 
   Comments-Summary: No comments yet.
   Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-TBD
@@ -14,7 +14,8 @@
 
 === Abstract ===
 
-This document proposes the introduction of a new output type using signatures based on Post-Quantum Cryptography (PQC). This approach for adding a post-quantum secure output type does not require a hard fork or block size increase.
+This document proposes the introduction of a new output type using signatures based on Post-Quantum Cryptography (PQC).
+This approach for adding a post-quantum secure output type does not require a hard fork or block size increase.
 
 === Copyright ===
 
@@ -22,26 +23,60 @@ This document is licensed under the 3-clause BSD license.
 
 === Motivation ===
 
-This proposal aims to improve the quantum resistance of Bitcoin's signature security should the Discrete Logarithm Problem (DLP), which secures Elliptic Curve Cryptography (ECC), no longer prove to be computationally hard, likely through quantum advantage by Cryptoanalytically-Relevant Quantum Computers (CRQCs). [https://arxiv.org/pdf/quant-ph/0301141 A variant of Shor's algorithm] is believed to be capable of deriving the private key from a public key exponentially faster than classical means. The application of this variant of Shor's algorithm is herein referred to as quantum key decryption. Note that doubling the public key length, such as with a hypothetical secp512k1 curve, would only make deriving the private key twice as hard. The computational complexity of this is investigated further in the paper, [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault tolerant regime''].
-
-The primary threat to Bitcoin by CRQCs is [https://en.bitcoin.it/wiki/Quantum_computing_and_Bitcoin#QC_attacks generally considered to be their potential to break ECC, which is used in signatures and Taproot commitments], hence the focus on a new address format. Shor's algorithm enables a CRQC to break the cryptographic assumptions of ECC in roughly 10^8 quantum operations.
-
-The vulnerability of existing Bitcoin addresses is investigated in [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the Bitcoin supply is held within addresses vulnerable to quantum attack. As of the time of writing, that number is now closer to 20%. Additionally, cryptographer Pieter Wuille [https://x.com/pwuille/status/1108085284862713856 reasons] even more might be vulnerable.
-
-Ordinarily, when a transaction is signed, the public key can be recovered from the signature. This makes a transaction submitted to the mempool vulnerable to quantum attack until it's mined. One way to mitigate this is to submit the transaction directly to a mining pool, which bypasses the mempool. This process is known as an out-of-band transaction. The mining pool must be trusted not to reveal the transaction public key to attackers. The problem with this approach is that it requires a trusted third party, which is what this P2QRH proposal aims to avoid.
-
-Not having public keys exposed on-chain is an important step for quantum security. Otherwise, funds would need to be spent to new addresses on a regular basis in order to prevent the possibility of a "long-range CRQC attack" recovering the key behind high-value addresses. A long-range quantum attack can be considered one performed with chain data, such as that from a used address or one encoded in a spend script. This is likely to be more common early on, as early quantum computers must be run for longer in order to overcome errors caused by noise. A "short-range quantum attack" would be one performed on keys in the mempool, which is seen as much more difficult given the block time, and so it requires more sophisticated CRQCs. As the value being sent increases, so too should the fee in order to commit the transaction to the chain as soon as possible. Once the transaction is mined, it makes useless the public key revealed by spending a UTXO, so long as it is never reused.
-
-It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) address type that relies on a PQC signature algorithm. This new address type protects transactions submitted to the mempool and helps preserve the free market by preventing the need for private, out-of-band mempool transactions.
-
-The following table is non-exhaustive but intended to inform the average Bitcoin user whether their bitcoin is vulnerable to a long-range quantum attack.
+This proposal aims to improve the quantum resistance of Bitcoin's signature security should the Discrete Logarithm
+Problem (DLP), which secures Elliptic Curve Cryptography (ECC), no longer prove to be computationally hard, likely
+through quantum advantage by Cryptoanalytically-Relevant Quantum Computers (CRQCs).
+[https://arxiv.org/pdf/quant-ph/0301141 A variant of Shor's algorithm] is believed to be capable of deriving the
+private key from a public key exponentially faster than classical means. The application of this variant of Shor's
+algorithm is herein referred to as quantum key decryption. Note that doubling the public key length, such as with a
+hypothetical secp512k1 curve, would only make deriving the private key twice as hard. The computational complexity of
+this is investigated further in the paper,
+[https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact
+of hardware specifications on reaching quantum advantage in the fault tolerant regime''].
+
+The primary threat to Bitcoin by CRQCs is [https://en.bitcoin.it/wiki/Quantum_computing_and_Bitcoin#QC_attacks
+generally considered to be their potential to break ECC, which is used in signatures and Taproot commitments], hence
+the focus on a new address format. Shor's algorithm enables a CRQC to break the cryptographic assumptions of ECC in
+roughly 10^8 quantum operations.
+
+The vulnerability of existing Bitcoin addresses is investigated in
+[https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-
+and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the
+Bitcoin supply is held within addresses vulnerable to quantum attack. As of the time of writing, that number is now
+closer to 20%. Additionally, cryptographer Pieter Wuille [https://x.com/pwuille/status/1108085284862713856 reasons]
+even more might be vulnerable.
+
+Ordinarily, when a transaction is signed, the public key can be recovered from the signature. This makes a transaction
+submitted to the mempool vulnerable to quantum attack until it's mined. One way to mitigate this is to submit the
+transaction directly to a mining pool, which bypasses the mempool. This process is known as an out-of-band transaction.
+The mining pool must be trusted not to reveal the transaction public key to attackers. The problem with this approach
+is that it requires a trusted third party, which is what this P2QRH proposal aims to avoid.
+
+Not having public keys exposed on-chain is an important step for quantum security. Otherwise, funds would need to be
+spent to new addresses on a regular basis in order to prevent the possibility of a "long-range CRQC attack" recovering
+the key behind high-value addresses. A long-range quantum attack can be considered one performed with chain data, such
+as that from a used address or one encoded in a spend script. This is likely to be more common early on, as early
+quantum computers must be run for longer in order to overcome errors caused by noise. A "short-range quantum attack"
+would be one performed on keys in the mempool, which is seen as much more difficult given the block time, and so it
+requires more sophisticated CRQCs. As the value being sent increases, so too should the fee in order to commit the
+transaction to the chain as soon as possible. Once the transaction is mined, it makes useless the public key revealed
+by spending a UTXO, so long as it is never reused.
+
+It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) address type that relies on a PQC signature
+algorithm. This new address type protects transactions submitted to the mempool and helps preserve the free market by
+preventing the need for private, out-of-band mempool transactions.
+
+The following table is non-exhaustive but intended to inform the average Bitcoin user whether their bitcoin is
+vulnerable to a long-range quantum attack.
 
 {| class="wikitable"
 |+ Vulnerable address types
 |-
 ! Address type !! Vulnerable !! Prefix !! Example
 |-
-| P2PK || Yes || 04 || 0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee
+| P2PK || Yes || 04 ||
+0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf
+2342c858ee
 |-
 | P2PKH || No || 1 || 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
 |-
@@ -50,11 +85,14 @@ The following table is non-exhaustive but intended to inform the average Bitcoin
 | P2TR || Yes || bc1p || bc1p92aslsnseq786wxfk3ekra90ds9ku47qttupfjsqmmj4z82xdq4q3rr58u
 |}
 
-It should be noted that Taproot addresses are vulnerable in that they encode a 32-byte x-only public key, from which a full public key can be reconstructed.
+It should be noted that Taproot addresses are vulnerable in that they encode a 32-byte x-only public key, from which a
+full public key can be reconstructed.
 
-If a key is recovered by a CRQC it can also be trivially checked to see if any child keys were produced using an unhardened [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32] derivation path.
+If a key is recovered by a CRQC it can also be trivially checked to see if any child keys were produced using an
+unhardened [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32] derivation path.
 
-The following table summarizes the scenarios in which public keys are revealed when using Bitcoin and what type of attack the underlying addresses are vulnerable to:
+The following table summarizes the scenarios in which public keys are revealed when using Bitcoin and what type of
+attack the underlying addresses are vulnerable to:
 
 {| class="wikitable"
 |+ Scenarios for revealed public keys on Bitcoin
@@ -72,47 +110,122 @@ The following table summarizes the scenarios in which public keys are revealed w
 | Unhardened BIP-32 HD wallet keys || Both Long-range or Short-range
 |}
 
-The only time a short-range attack can occur is when the transaction is in the mempool, whereas a long-range attack occurs when the public key is known well in advance. Short-range attacks require much larger, more expensive CRQCs.
-
-Should quantum advantage manifest, a convention is proposed in spending the full 65-byte P2PK key used by the coinbase output in Block 1 back to itself. It is proposed to call the address in Block 1 the [https://mempool.space/address/0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee Canary address] since it can only be spent from by others (assuming Satoshi's continued absence) if secp256k1 is broken. Should the Canary coins move, that will signal that reliance on secp256k1 is presently vulnerable. Without the Canary, or an address like it, there may be some doubt as to whether the coins were moved with keys belonging to the original owner.
-
-As an interesting aside, coinbase outputs to P2PK keys go as far as block 200,000, so there are 1,723,848 coins that are vulnerable from the first epoch at the time of writing in P2PK outputs alone. Since the majority of these have a block reward of 50 coins each, there are roughly 34,000 distinct P2PK addresses that are vulnerable. These coins can be considered "Satoshi's Shield." Any addresses with a balance of less than the original block subsidy of 50 coins can be considered incentive incompatible to capture until all of these are mined, and these addresses serve to provide time to transition Bitcoin to implement post-quantum security.
-
-It's for the above reason that, for those who wish to be prepared for quantum emergency, it is recommended that no more than 50 bitcoin are kept under a single, distinct, unused Native SegWit (P2WPKH, "bc1q") address at a time. This is assuming that the attacker is financially motivated instead of, for example, a nation state looking to break confidence in Bitcoin. Additionally, this assumes that other vulnerable targets such as central banks have upgraded their cryptography by this time.
-
-The Commercial National Security Algorithm Suite (CNSA) 2.0 has a timeline for software and networking equipment to be upgraded by 2030, with browsers and operating systems fully upgraded by 2033. According to NIST IR 8547, Elliptic Curve Cryptography is planned to be disallowed within the US Federal government after 2035. An exception is made for hybrid cryptography, which is the use of ECC and post-quantum algorithms together.
-
-Although CRQCs could pose a threat to the signatures used in Bitcoin, a smaller threat is to Bitcoin's hash algorithms. In particular, while a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a quadratic speedup on brute-force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160Used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes. using Grover's algorithm would require at least 1024 quantum operations. As for Grover's application to mining, see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques’ post on this].
+The only time a short-range attack can occur is when the transaction is in the mempool, whereas a long-range attack
+occurs when the public key is known well in advance. Short-range attacks require much larger, more expensive CRQCs.
+
+Should quantum advantage manifest, a convention is proposed in spending the full 65-byte P2PK key used by the coinbase
+output in Block 1 back to itself. It is proposed to call the address in Block 1 the
+[https://mempool.space/address/0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f81
+41781e62294721166bf621e73a82cbf2342c858ee Canary address] since it can only be spent from by others (assuming Satoshi's
+continued absence) if secp256k1 is broken. Should the Canary coins move, that will signal that reliance on secp256k1 is
+presently vulnerable. Without the Canary, or an address like it, there may be some doubt as to whether the coins were
+moved with keys belonging to the original owner.
+
+As an interesting aside, coinbase outputs to P2PK keys go as far as block 200,000, so there are 1,723,848 coins that
+are vulnerable from the first epoch at the time of writing in P2PK outputs alone. Since the majority of these have a
+block reward of 50 coins each, there are roughly 34,000 distinct P2PK addresses that are vulnerable. These coins can be
+considered "Satoshi's Shield." Any addresses with a balance of less than the original block subsidy of 50 coins can be
+considered incentive incompatible to capture until all of these are mined, and these addresses serve to provide time to
+transition Bitcoin to implement post-quantum security.
+
+It's for the above reason that, for those who wish to be prepared for quantum emergency, it is recommended that no more
+than 50 bitcoin are kept under a single, distinct, unused Native SegWit (P2WPKH, "bc1q") address at a time. This is
+assuming that the attacker is financially motivated instead of, for example, a nation state looking to break confidence
+in Bitcoin. Additionally, this assumes that other vulnerable targets such as central banks have upgraded their
+cryptography by this time.
+
+The Commercial National Security Algorithm Suite (CNSA) 2.0 has a timeline for software and networking equipment to be
+upgraded by 2030, with browsers and operating systems fully upgraded by 2033. According to NIST IR 8547, Elliptic Curve
+Cryptography is planned to be disallowed within the US Federal government after 2035. An exception is made for hybrid
+cryptography, which is the use of ECC and post-quantum algorithms together.
+
+Although CRQCs could pose a threat to the signatures used in Bitcoin, a smaller threat is to Bitcoin's hash algorithms.
+In particular, while a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a
+quadratic speedup on brute-force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is
+needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160Used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes. using
+Grover's algorithm would require at least 1024 quantum operations. As for Grover's application to mining,
+see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques’ post on this].
 
 === Rationale ===
 
-This is the first in a series of BIPs under a QuBit soft fork. A qubit is a fundamental unit of quantum computing, and the capital B refers to Bitcoin. The name QuBit also rhymes to some extent with SegWit.
-
-It is proposed to use SegWit version 3. This results in addresses that start with bc1r, which could be a useful way to remember that these are quantum (r)esistant addresses (similar to how bc1q corresponds to Se(q)Wit and bc1p corresponds to Ta(p)root). This is referencing the lookup table under [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173].
-
-The proposal above also leaves a gap in case it makes sense to use version 2, or bc1z, for implementation of other address formats such as those that employ Cross Input Signature Aggregation (CISA).
-
-P2QRH is meant to be implemented on top of P2TR, combining the security of classical Schnorr signatures along with post-quantum cryptography. This is a form of hybrid cryptography such that no regression in security is presented should a vulnerability exist in one of the signature algorithms used. One key distinction between P2QRH and P2TR however is that P2QRH will encode a hash of the public key. This is a significant deviation from how Taproot works by itself, but it is necessary to avoid exposing public keys on-chain where they are vulnerable to attack.
-
-P2QRH uses a 32-byte HASH256 (specifically SHA-256 twice-over, which is similar to that used in [https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#specification BIP-16]) of the public key to reduce the size of new outputs and also to increase security by not having the public key available on-chain. This hash serves as a minimal cryptographic commitment to a public key. It goes into the output spend script, which does not receive the witness discount.
-
-Post-quantum public keys are generally larger than those used by ECC, depending on the security level. To promote user adoption and general user-friendliness, the most secure variant (NIST Level V, 256-bit security) is proposed, despite the increase in key length and verification time.
-
-Support for FALCON signatures will be introduced first, with the intention of adding SQIsign and other post-quantum algorithms as they are approved. By way of comparison, FALCON signatures are roughly 4x larger than SQIsign signatures and 20x larger than Schnorr signatures. FALCON is a more conservative approach to applied lattice cryptography than SQIsign, and its use has recently been approved by NIST. NIST approval streamlines implementations through establishing consensus in the scientific and developer community. However, even SQIsign signatures are roughly 5x larger than Schnorr signatures. This means, to maintain present transaction throughput, an increase in the witness discount will likely be desired in a QuBit soft fork. That will be specified in a future QuBit BIP.
-
-An increase in the witness discount must not be taken lightly. It must be resistant to applications that might take advantage of this discount (e.g., storage of arbitrary data as seen with "inscriptions") without a corresponding increase in economic activity. An increase in the witness discount would not only impact node runners but those with inscriptions would also have the scarcity of their non-monetary assets affected. The only way to prevent these effects while also increasing the discount is to have a completely separate witness—a "quantum witness." Because it is meant only for public keys and signatures, we call this section of the transaction the attestation.
-
-To address the risk of arbitrary data being stored using P2QRH (QuBit) addresses, very specific rules will be applied to spending from the witness stack in SegWit v3 outputs. A fixed signature size will be necessary for spending the output, and the output must be spendable to be considered valid within node consensus. A fixed signature size will also be helpful to disambiguate between signature types without an additional version byte, as SQIsign signatures are substantially smaller than FALCON signatures. Consequently, the correct signature algorithm can be inferred through byte length. The public key and signature will be pushed separately to the attestation stack. Multiple signatures can be included in order to support multisig applications, and also for spending multiple inputs.
-
-Since only valid signatures can be committed to in a SegWit v3 attestation, arbitrary data cannot be added by miners, as that would affect the consensus of their block. A CRQC operator is economically disincentivized from computing a spendable public key that matched arbitrary signature data due to the cost of that computation. That is because the cost of such a computation could prove quite substantial, rather than simply putting the arbitrary data within a Taproot witness.
-
-Additionally, it should be noted, whether an output with a P2QRH spend script corresponds to a FALCON or SQIsign signature is not known until the output is spent.
-
-While it might be seen as a maintenance burden for Bitcoin ecosystem devs to go from a single cryptosystem implementation to four additional distinct PQC cryptosystems—and it most certainly is—the ramifications of a chain broken through extrinsic factors should provide sufficient motivation. An increase in software maintenance everywhere signatures are used should be seen as an acceptable compromise for maintained integrity of Bitcoin transfers during a regime of quantum advantage.
-
-The inclusion of these four cryptosystems: SPHINCS+, CRYSTALS-Dilithium, FALCON, and SQIsign have various advocates within the community due to their varying security assumptions. Hash-based cryptosystems are more conservative, time-tested, and well-reviewed. Lattice cryptography is relatively new and introduces novel security assumptions to Bitcoin, but their signatures are smaller and might be considered by some to be an adequate alternative to hash-based signatures. SQIsign is much smaller; however, it is based on a very novel form of cryptography known as supersingular elliptic curve quaternion isogeny, and at the time of writing, is not yet approved by NIST or the broader PQC community.
-
-In the distant future, following the implementation of the P2QRH address format in a QuBit soft fork, there will likely be a need for Pay to Quantum Secure (P2QS) addresses. These will require specialized quantum hardware for signing, while still [https://quantum-journal.org/papers/q-2023-01-19-901/ using public keys that are verifiable via classical means]. Additional follow-on BIPs will be needed to implement P2QS. However, until specialized quantum cryptography hardware is widespread, quantum resistant addresses should be an adequate intermediate solution.
+This is the first in a series of BIPs under a QuBit soft fork. A qubit is a fundamental unit of quantum computing, and
+the capital B refers to Bitcoin. The name QuBit also rhymes to some extent with SegWit.
+
+It is proposed to use SegWit version 3. This results in addresses that start with bc1r, which could be a useful way to
+remember that these are quantum (r)esistant addresses (similar to how bc1q corresponds to Se(q)Wit and bc1p corresponds
+to Ta(p)root). This is referencing the lookup table under
+[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173].
+
+The proposal above also leaves a gap in case it makes sense to use version 2, or bc1z, for implementation of other
+address formats such as those that employ Cross Input Signature Aggregation (CISA).
+
+P2QRH is meant to be implemented on top of P2TR, combining the security of classical Schnorr signatures along with
+post-quantum cryptography. This is a form of hybrid cryptography such that no regression in security is presented
+should a vulnerability exist in one of the signature algorithms used. One key distinction between P2QRH and P2TR
+however is that P2QRH will encode a hash of the public key. This is a significant deviation from how Taproot works by
+itself, but it is necessary to avoid exposing public keys on-chain where they are vulnerable to attack.
+
+P2QRH uses a 32-byte HASH256 (specifically SHA-256 twice-over, which is similar to that used in
+[https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#specification BIP-16]) of the public key to reduce the
+size of new outputs and also to increase security by not having the public key available on-chain. This hash serves as
+a minimal cryptographic commitment to a public key. It goes into the output spend script, which does not receive the
+witness discount.
+
+Post-quantum public keys are generally larger than those used by ECC, depending on the security level. To promote user
+adoption and general user-friendliness, the most secure variant (NIST Level V, 256-bit security) is proposed, despite
+the increase in key length and verification time.
+
+Support for FALCON signatures will be introduced first, with the intention of adding SQIsign and other post-quantum
+algorithms as they are approved. By way of comparison, FALCON signatures are roughly 4x larger than SQIsign signatures
+and 20x larger than Schnorr signatures. FALCON is a more conservative approach to applied lattice cryptography than
+SQIsign, and its use has recently been approved by NIST. NIST approval streamlines implementations through establishing
+consensus in the scientific and developer community. However, even SQIsign signatures are roughly 5x larger than
+Schnorr signatures. This means, to maintain present transaction throughput, an increase in the witness discount will
+likely be desired in a QuBit soft fork. That will be specified in a future QuBit BIP.
+
+An increase in the witness discount must not be taken lightly. It must be resistant to applications that might take
+advantage of this discount (e.g., storage of arbitrary data as seen with "inscriptions") without a corresponding
+increase in economic activity. An increase in the witness discount would not only impact node runners but those with
+inscriptions would also have the scarcity of their non-monetary assets affected. The only way to prevent these effects
+while also increasing the discount is to have a completely separate witness—a "quantum witness." Because it is meant
+only for public keys and signatures, we call this section of the transaction the attestation.
+
+To address the risk of arbitrary data being stored using P2QRH (QuBit) addresses, very specific rules will be applied
+to spending from the witness stack in SegWit v3 outputs. A fixed signature size will be necessary for spending the
+output, and the output must be spendable to be considered valid within node consensus. A fixed signature size will also
+be helpful to disambiguate between signature types without an additional version byte, as SQIsign signatures are
+substantially smaller than FALCON signatures. Consequently, the correct signature algorithm can be inferred through
+byte length. The public key and signature will be pushed separately to the attestation stack. Multiple signatures can
+be included in order to support multisig applications, and also for spending multiple inputs.
+
+Since only valid signatures can be committed to in a SegWit v3 attestation, arbitrary data cannot be added by miners,
+as that would affect the consensus of their block. A CRQC operator is economically disincentivized from computing a
+spendable public key that matched arbitrary signature data due to the cost of that computation. That is because the
+cost of such a computation could prove quite substantial, rather than simply putting the arbitrary data within a
+Taproot witness.
+
+Additionally, it should be noted, whether an output with a P2QRH spend script corresponds to a FALCON or SQIsign
+signature is not known until the output is spent.
+
+While it might be seen as a maintenance burden for Bitcoin ecosystem devs to go from a single cryptosystem
+implementation to four additional distinct PQC cryptosystems—and it most certainly is—the ramifications of a chain
+broken through extrinsic factors should provide sufficient motivation. An increase in software maintenance everywhere
+signatures are used should be seen as an acceptable compromise for maintained integrity of Bitcoin transfers during a
+regime of quantum advantage.
+
+The inclusion of these four cryptosystems: SPHINCS+, CRYSTALS-Dilithium, FALCON, and SQIsign have various advocates
+within the community due to their varying security assumptions. Hash-based cryptosystems are more conservative,
+time-tested, and well-reviewed. Lattice cryptography is relatively new and introduces novel security assumptions to
+Bitcoin, but their signatures are smaller and might be considered by some to be an adequate alternative to hash-based
+signatures. SQIsign is much smaller; however, it is based on a very novel form of cryptography known as supersingular
+elliptic curve quaternion isogeny, and at the time of writing, is not yet approved by NIST or the broader PQC community.
+
+In the distant future, following the implementation of the P2QRH address format in a QuBit soft fork, there will likely
+be a need for Pay to Quantum Secure (P2QS) addresses. These will require specialized quantum hardware for signing,
+while still [https://quantum-journal.org/papers/q-2023-01-19-901/ using public keys that are verifiable via classical
+means]. Additional follow-on BIPs will be needed to implement P2QS. However, until specialized quantum cryptography
+hardware is widespread, quantum resistant addresses should be an adequate intermediate solution.
 
 == Specification ==
 
@@ -120,17 +233,23 @@ We define the signature scheme and transaction structure as follows.
 
 === Descriptor Format ===
 
-To integrate P2QRH into existing wallet software and scripts, we introduce a new output descriptor function qrh(). This function represents a P2QRH output, similar to how wpkh() and tr() are used for P2WPKH and P2TR outputs, respectively.
+To integrate P2QRH into existing wallet software and scripts, we introduce a new output descriptor function
+qrh(). This function represents a P2QRH output, similar to how wpkh() and tr()
+are used for P2WPKH and P2TR outputs, respectively.
 
-The qrh() function takes the HASH256 of the concatenated HASH256 of the quantum-resistant public keys as its argument. For example:
+The qrh() function takes the HASH256 of the concatenated HASH256 of the quantum-resistant public keys as
+its argument. For example:
 
 qrh(HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ...))
 
-This function allows wallets to manage P2QRH addresses and outputs while accommodating multiple public keys of varying lengths, such as in multisig schemes, while keeping the public keys hidden until the time of spending.
+This function allows wallets to manage P2QRH addresses and outputs while accommodating multiple public keys of varying
+lengths, such as in multisig schemes, while keeping the public keys hidden until the time of spending.
 
 === Address Format ===
 
-P2QRH uses SegWit version 3 outputs, resulting in addresses that start with bc1r, following [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. Bech32 encoding maps version 3 to the prefix r.
+P2QRH uses SegWit version 3 outputs, resulting in addresses that start with bc1r, following
+[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. Bech32 encoding maps version 3 to the
+prefix r.
 
 Example P2QRH address:
 
@@ -189,13 +308,16 @@ For each signature:
 * signature_length: VarInt encoded length of the signature.
 * signature: The signature bytes.
 
-This structure repeats for each input, in order, for flexibility in supporting multisig schemes and various quantum-resistant algorithms.
+This structure repeats for each input, in order, for flexibility in supporting multisig schemes and various
+quantum-resistant algorithms.
 
-For each input, a separate attestation field is used. To know how many attestation fields are present, implementations must count the number of inputs present in the transaction.
+For each input, a separate attestation field is used. To know how many attestation fields are present, implementations
+must count the number of inputs present in the transaction.
 
 === Signature Algorithm Identification ===
 
-The specific quantum-resistant signature algorithm used is inferred from the length of the public key and signature. Implementations must recognize the supported algorithms and validate accordingly.
+The specific quantum-resistant signature algorithm used is inferred from the length of the public key and signature.
+Implementations must recognize the supported algorithms and validate accordingly.
 
 Supported algorithms and their NIST Level V parameters:
 
@@ -226,14 +348,18 @@ OP_PUSHNUM_3 <32-byte hash>
 
 2. The attestation must include:
 
-* The quantum-resistant public key(s) whose HASH256 concatenated and hashed again matches the  in the scriptPubKey.
+* The quantum-resistant public key(s) whose HASH256 concatenated and hashed again matches the  in
+the scriptPubKey.
 * Valid signatures corresponding to the public key(s) and the transaction data.
 
-3. For multi-signature schemes, all required public keys and signatures must be provided for that input within the attestation. This includes classical Schnorr signatures.
+3. For multi-signature schemes, all required public keys and signatures must be provided for that input within the
+attestation. This includes classical Schnorr signatures.
 
 ==== Public Key Hashing ====
 
-All public keys included in the attestation are hashed using HASH256 (double SHA-256). The concatenation of these hashes is then hashed again using HASH256 before being included in the scriptPubKey. This ensures a fixed-size commitment to potentially multiple public keys of varying lengths.
+All public keys included in the attestation are hashed using HASH256 (double SHA-256). The concatenation of these
+hashes is then hashed again using HASH256 before being included in the scriptPubKey. This ensures a
+fixed-size commitment to potentially multiple public keys of varying lengths.
 
 ==== Hash Computation ====
 
@@ -307,27 +433,38 @@ Note: This contrasts with multisig inputs, where the attestation structure repea
 
 === Compatibility with BIP-141 ===
 
-By adhering to the SegWit transaction structure and versioning, P2QRH outputs are compatible with existing transaction processing rules. Nodes that do not recognize SegWit version 3 will treat these outputs as anyone-can-spend but, per BIP-141, will not relay or mine such transactions.
+By adhering to the SegWit transaction structure and versioning, P2QRH outputs are compatible with existing transaction
+processing rules. Nodes that do not recognize SegWit version 3 will treat these outputs as anyone-can-spend but, per
+BIP-141, will not relay or mine such transactions.
 
 === Usage Considerations ===
 
 ==== Transaction Size and Fees ====
 
-Quantum-resistant signatures are significantly larger than traditional signatures, increasing transaction size and the fees required. Users and wallet developers should be aware of this and plan accordingly.
+Quantum-resistant signatures are significantly larger than traditional signatures, increasing transaction size and the
+fees required. Users and wallet developers should be aware of this and plan accordingly.
 
-For example, for CRYSTALS-Dilithium Level V, a single signature is 4,595 bytes, a substantial increase over current ECDSA or Schnorr signatures.
+For example, for CRYSTALS-Dilithium Level V, a single signature is 4,595 bytes, a substantial increase over current
+ECDSA or Schnorr signatures.
 
 ==== Performance Impact ====
 
-Verification of quantum-resistant signatures will be computationally more intensive, and any attestation discount will also increase storage requirements. Node operators should consider the potential impact on resource usage in the long term. Developers may need to optimize signature verification implementations, especially by implementing caching for key generation.
+Verification of quantum-resistant signatures will be computationally more intensive, and any attestation discount will
+also increase storage requirements. Node operators should consider the potential impact on resource usage in the long
+term. Developers may need to optimize signature verification implementations, especially by implementing caching for
+key generation.
 
 ==== Algorithm Selection ====
 
-Introducing four quantum-resistant algorithms to the Bitcoin ecosystem provides users with the option to select an appropriate algorithm for their use case, generally based on the amount of value they wish to secure. Developers can choose to implement support for multiple algorithms in wallets and on nodes to offer quantum-resistant options.
+Introducing four quantum-resistant algorithms to the Bitcoin ecosystem provides users with the option to select an
+appropriate algorithm for their use case, generally based on the amount of value they wish to secure. Developers can
+choose to implement support for multiple algorithms in wallets and on nodes to offer quantum-resistant options.
 
 ==== Backward Compatibility ====
 
-Older wallets and nodes that have not been made compatible with SegWit version 3 and P2QRH will not recognize these outputs. Users should ensure they are using updated wallets and nodes to use P2QRH addresses and validate transactions using P2QRH outputs.
+Older wallets and nodes that have not been made compatible with SegWit version 3 and P2QRH will not recognize these
+outputs. Users should ensure they are using updated wallets and nodes to use P2QRH addresses and validate transactions
+using P2QRH outputs.
 
 == Security ==
 
@@ -336,30 +473,46 @@ Older wallets and nodes that have not been made compatible with SegWit version 3
 |-
 ! Signature Algorithm !! Year First Introduced !! Signature Size !! Public Key Size !! Cryptographic Assumptions
 |-
-| [https://en.wikipedia.org/wiki/Lamport_signature Lamport signature] || 1977 || 8,192 bytes || 16,384 bytes || Hash-based cryptography
+| [https://en.wikipedia.org/wiki/Lamport_signature Lamport signature] || 1977 || 8,192 bytes || 16,384 bytes ||
+Hash-based cryptography
 |-
-| [https://eprint.iacr.org/2011/191.pdf Winternitz signature] || 1982 || 2,368 bytesWinternitz signatures are much smaller than Lamport signatures due to efficient chunking, but computation is much higher, especially with high values for w. Winternitz values are for w of 4. || 2,368 bytes || Hash-based cryptography
+| [https://eprint.iacr.org/2011/191.pdf Winternitz signature] || 1982 || 2,368 bytesWinternitz
+signatures are much smaller than Lamport signatures due to efficient chunking, but computation is much higher,
+especially with high values for w. Winternitz values are for w of 4. || 2,368 bytes || Hash-based cryptography
 |-
-| [https://sphincs.org/data/sphincs+-r3.1-specification.pdf SPHINCS+ Rd. 3.1 (FIPS 205 - SLH-DSA)] || 2015 || 29,792 bytes || 64 bytes || Hash-based cryptography
+| [https://sphincs.org/data/sphincs+-r3.1-specification.pdf SPHINCS+ Rd. 3.1 (FIPS 205 - SLH-DSA)] || 2015 || 29,792
+bytes || 64 bytes || Hash-based cryptography
 |-
-| [https://eprint.iacr.org/2011/484.pdf XMSS]XMSS, which is based on Winternitz, uses a value of 108 for its most compact signature size, with only a 4.6x (2.34/0.51) increase in verification time. Signing and key generation are not considered a significant factor because they are not distributed throughout the entire Bitcoin network, which take place only inside of wallets one time. || 2011 || 15,384 bytes || 13,568 bytes || Hash-based cryptography (Winternitz OTS)
+| [https://eprint.iacr.org/2011/484.pdf XMSS]XMSS, which is based on Winternitz, uses a value of 108
+for its most compact signature size, with only a 4.6x (2.34/0.51) increase in verification time. Signing and key
+generation are not considered a significant factor because they are not distributed throughout the entire Bitcoin
+network, which take place only inside of wallets one time. || 2011 || 15,384 bytes || 13,568 bytes || Hash-based
+cryptography (Winternitz OTS)
 |-
-| [https://pq-crystals.org/dilithium/ CRYSTALS-Dilithium (FIPS 204 - ML-DSA)] || 2017 || 4,595 bytes || 2,592 bytes || Lattice cryptography
+| [https://pq-crystals.org/dilithium/ CRYSTALS-Dilithium (FIPS 204 - ML-DSA)] || 2017 || 4,595 bytes || 2,592 bytes ||
+Lattice cryptography
 |-
 | [https://eprint.iacr.org/2014/457.pdf pqNTRUsign] || 2016 || 1,814 bytes || 1,927 bytes || Lattice cryptography (NTRU)
 |-
-| [https://falcon-sign.info FALCON (FIPS 206 - FN-DSA)] || 2017 || 1,280 bytes || 1,793 bytes || Lattice cryptography (NTRU)
+| [https://falcon-sign.info FALCON (FIPS 206 - FN-DSA)] || 2017 || 1,280 bytes || 1,793 bytes || Lattice cryptography
+(NTRU)
 |-
 | [https://eprint.iacr.org/2022/1155.pdf HAWK] || 2022 || 1,261 bytes || 2,329 bytes || Lattice cryptography
 |-
 | [https://sqisign.org SQIsign] || 2023 || 335 bytes || 128 bytes || Supersingular Elliptic Curve Isogeny
 |-
-| [https://eprint.iacr.org/2024/760.pdf SQIsign2D-West] || 2024 || 294 bytes || 130 bytes || Supersingular Elliptic Curve Isogeny
+| [https://eprint.iacr.org/2024/760.pdf SQIsign2D-West] || 2024 || 294 bytes || 130 bytes || Supersingular Elliptic
+Curve Isogeny
 |-
-| [https://eprint.iacr.org/2023/436.pdf SQIsignHD] || 2023 || 109 bytes (NIST Level I) || Not provided || Supersingular Elliptic Curve Isogeny
+| [https://eprint.iacr.org/2023/436.pdf SQIsignHD] || 2023 || 109 bytes (NIST Level I) || Not provided || Supersingular
+Elliptic Curve Isogeny
 |}
 
-As shown, supersingular elliptic curve quaternion isogeny signature algorithms represent the state of the art in post-quantum cryptography, beyond lattice cryptography alone, especially when key and signature length are major constraints. This makes inclusion of SQIsign attractive, and support is planned, but it will be some time until it is approved for production use. Meanwhile, SPHINCS+ and CRYSTALS-Dilithium signatures are already approved and have achieved broader community consensus. FALCON signatures are also NIST approved.
+As shown, supersingular elliptic curve quaternion isogeny signature algorithms represent the state of the art in
+post-quantum cryptography, beyond lattice cryptography alone, especially when key and signature length are major
+constraints. This makes inclusion of SQIsign attractive, and support is planned, but it will be some time until it is
+approved for production use. Meanwhile, SPHINCS+ and CRYSTALS-Dilithium signatures are already approved and have
+achieved broader community consensus. FALCON signatures are also NIST approved.
 
 In comparison, the size of currently used signature algorithms are:
 
@@ -368,13 +521,25 @@ In comparison, the size of currently used signature algorithms are:
 
 In comparison to inception date, secp256k1 [https://www.secg.org/SEC1-Ver-1.0.pdf was originally specified in 2000].
 
-One consideration for choosing an algorithm is its maturity. secp256k1 was already 8 years old by the time it was chosen as Bitcoin's curve. Isogeny cryptography when it was first introduced was broken over a weekend.
+One consideration for choosing an algorithm is its maturity. secp256k1 was already 8 years old by the time it was
+chosen as Bitcoin's curve. Isogeny cryptography when it was first introduced was broken over a weekend.
 
-Ideally SQIsign also proves to be flexible enough to support [https://www.pierrickdartois.fr/homepage/wp-content/uploads/2022/04/Report_OSIDH_DARTOIS.pdf Isogeny Diffie-Hellman] to replace ECDH applications, and also provide methods for the key tweaking necessary to support TapScript for P2QR addresses. Additionally, isogeny-based post-quantum cryptography is based on higher-order elliptic curves, and so it might be possible to implement Isogeny Schnorr signatures.
+Ideally SQIsign also proves to be flexible enough to support
+[https://www.pierrickdartois.fr/homepage/wp-content/uploads/2022/04/Report_OSIDH_DARTOIS.pdf Isogeny Diffie-Hellman] to
+replace ECDH applications, and also provide methods for the key tweaking necessary to support TapScript for P2QR
+addresses. Additionally, isogeny-based post-quantum cryptography is based on higher-order elliptic curves, and so it
+might be possible to implement Isogeny Schnorr signatures.
 
-Signature verification speed as it compares to Schnorr or ECDSA isn't seen as high a consideration as signature size due to block space being the primary fee constraint. As a P2QRH implementation materializes, a benchmark will be added for performance comparison. Fortunately, SQIsign signatures are substantially faster to verify than it is to generate keys or to sign, which is a major consideration when a transaction need only be signed once, or a handful of times with PSBT, compared to being verified simultaneously on tens of thousands of nodes. Key generation may need to be cached in BIP-32 Hierarchical Deterministic wallets.
+Signature verification speed as it compares to Schnorr or ECDSA isn't seen as high a consideration as signature size
+due to block space being the primary fee constraint. As a P2QRH implementation materializes, a benchmark will be added
+for performance comparison. Fortunately, SQIsign signatures are substantially faster to verify than it is to generate
+keys or to sign, which is a major consideration when a transaction need only be signed once, or a handful of times with
+PSBT, compared to being verified simultaneously on tens of thousands of nodes. Key generation may need to be cached in
+BIP-32 Hierarchical Deterministic wallets.
 
-An additional consideration is security level. Longer signature sizes provide more security. NIST has standardized five security levels for post-quantum cryptography. NIST security level I provides security equivalent to 128-bit keys, and security level V provides 256-bit security.
+An additional consideration is security level. Longer signature sizes provide more security. NIST has standardized five
+security levels for post-quantum cryptography. NIST security level I provides security equivalent to 128-bit keys, and
+security level V provides 256-bit security.
 
 == Test Vectors and Reference Code ==
 
@@ -382,14 +547,20 @@ TBD
 
 == Related Work ==
 
-It is worth noting by way of comparison that [https://ethresear.ch/t/how-to-hard-fork-to-save-most-users-funds-in-a-quantum-emergency/18901 Vitalik Buterin's proposed solution] in an Ethereum quantum emergency is quite different from the approach in this BIP. His plan involves a hard fork of the chain, reverting all blocks after a sufficient amount of theft, and using STARKs based on BIP-32 seeds to act as the authoritative secret when signing. These measures are deemed far too heavy-handed for Bitcoin.
+It is worth noting by way of comparison that
+[https://ethresear.ch/t/how-to-hard-fork-to-save-most-users-funds-in-a-quantum-emergency/18901 Vitalik Buterin's
+proposed solution] in an Ethereum quantum emergency is quite different from the approach in this BIP. His plan involves
+a hard fork of the chain, reverting all blocks after a sufficient amount of theft, and using STARKs based on BIP-32
+seeds to act as the authoritative secret when signing. These measures are deemed far too heavy-handed for Bitcoin.
 
 == References ==
 
 * [https://groups.google.com/g/bitcoindev/c/Aee8xKuIC2s/m/cu6xej1mBQAJ Mailing list discussion]
-* [https://delvingbitcoin.org/t/proposing-a-p2qrh-bip-towards-a-quantum-resistant-soft-fork/956?u=cryptoquick Delving Bitcoin discussion]
+* [https://delvingbitcoin.org/t/proposing-a-p2qrh-bip-towards-a-quantum-resistant-soft-fork/956?u=cryptoquick Delving
+Bitcoin discussion]
 * [https://bitcoinops.org/en/newsletters/2024/06/14/ Bitcoin OpTech newsletter]
-* [https://bitcoinops.org/en/podcast/2024/06/18/#draft-bip-for-quantum-safe-address-format Bitcoin OpTech discussion transcript]
+* [https://bitcoinops.org/en/podcast/2024/06/18/#draft-bip-for-quantum-safe-address-format Bitcoin OpTech discussion
+transcript]
 
 == Footnotes ==
 
@@ -399,17 +570,23 @@ It is worth noting by way of comparison that [https://ethresear.ch/t/how-to-hard
 
 To help implementors understand updates to this BIP, we keep a list of substantial changes.
 
+* 2024-12-06 - Update title and formatting.
 * 2024-12-03 - MediaWiki formatting fixes.
 * 2024-12-01 - Add details on attestation structure and parsing.
 * 2024-11-20 - Clarifications based on feedback from Murch. Remove some sections that are not yet ready.
 * 2024-10-21 - Replace XMSS with CRYSTALS-Dilithium due to NIST approval and size constraints.
 * 2024-09-30 - Refactor the ECC vs PoW section. Swap quitness for attestation.
 * 2024-09-29 - Update section on PoW to include partial-preimage.
-* 2024-09-28 - Add Winternitz, XMSS signatures, and security assumption types to PQC table. Omit NIST Level I table. Add spend script specification. Add revealed public key scenario table.
+* 2024-09-28 - Add Winternitz, XMSS signatures, and security assumption types to PQC table. Omit NIST Level I table.
+Add spend script specification. Add revealed public key scenario table.
 * 2024-09-27 - Initial draft proposal
 
 == Acknowledgements ==
 
-This document is inspired by [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341], which introduced the design of the P2TR (Taproot) address type using Schnorr signatures.
+This document is inspired by [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341], which introduced
+the design of the P2TR (Taproot) address type using Schnorr signatures.
 
-Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name "QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as well to those who took the time to review and contribute, including Jeff Bride, Adam Borcany, Antoine Riard, Pierre-Luc Dallaire-Demers, Ethan Heilman, Jon Atack, Jameson Lopp, and Murchandamus.
+Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name
+"QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as
+well to those who took the time to review and contribute, including Jeff Bride, Adam Borcany, Antoine Riard, Pierre-Luc
+Dallaire-Demers, Ethan Heilman, Jon Atack, Jameson Lopp, and Murchandamus.

From 2e4ad811cfb048d8399730fde15f3f701969b4e1 Mon Sep 17 00:00:00 2001
From: Hunter Trujillo 
Date: Fri, 6 Dec 2024 10:49:01 -0700
Subject: [PATCH 014/131] More wrestling with MediaWiki formatting...

---
 bip-p2qrh.mediawiki | 47 ++++++++++++++++++++++++++++++---------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki
index 45f6427b24..8b9e0ba46d 100644
--- a/bip-p2qrh.mediawiki
+++ b/bip-p2qrh.mediawiki
@@ -10,6 +10,8 @@
   Created: 2024-06-08
 
+__TOC__ + == Introduction == === Abstract === @@ -116,10 +118,11 @@ occurs when the public key is known well in advance. Short-range attacks require Should quantum advantage manifest, a convention is proposed in spending the full 65-byte P2PK key used by the coinbase output in Block 1 back to itself. It is proposed to call the address in Block 1 the [https://mempool.space/address/0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f81 -41781e62294721166bf621e73a82cbf2342c858ee Canary address] since it can only be spent from by others (assuming Satoshi's -continued absence) if secp256k1 is broken. Should the Canary coins move, that will signal that reliance on secp256k1 is -presently vulnerable. Without the Canary, or an address like it, there may be some doubt as to whether the coins were -moved with keys belonging to the original owner. +41781e62294721166bf621e73a82cbf2342c858ee +Canary address] since it can only be spent from by others (assuming Satoshi's continued absence) if secp256k1 is +broken. Should the Canary coins move, that will signal that reliance on secp256k1 is presently vulnerable. Without the +Canary, or an address like it, there may be some doubt as to whether the coins were moved with keys belonging to the +original owner. As an interesting aside, coinbase outputs to P2PK keys go as far as block 200,000, so there are 1,723,848 coins that are vulnerable from the first epoch at the time of writing in P2PK outputs alone. Since the majority of these have a @@ -143,9 +146,9 @@ Although CRQCs could pose a threat to the signatures used in Bitcoin, a smaller In particular, while a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a quadratic speedup on brute-force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160Used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes. using -Grover's algorithm would require at least 1024 quantum operations. As for Grover's application to mining, -see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques’ post on this]. +name="hash160">Used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes. +using Grover's algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see +[https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques’ post on this]. === Rationale === @@ -240,7 +243,11 @@ are used for P2WPKH and P2TR outputs, respectively. The qrh() function takes the HASH256 of the concatenated HASH256 of the quantum-resistant public keys as its argument. For example: -qrh(HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ...)) + + +qrh(HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ...)) + + This function allows wallets to manage P2QRH addresses and outputs while accommodating multiple public keys of varying lengths, such as in multisig schemes, while keeping the public keys hidden until the time of spending. @@ -260,7 +267,9 @@ Example P2QRH address: The scriptPubKey for a P2QRH output is:
+
 OP_PUSHNUM_3 OP_PUSHBYTES_32 
+
 
Where: @@ -271,7 +280,7 @@ Where: ==== Hash Computation ====
-hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN))
+hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN))
 
This construction creates a cryptographic commitment to multiple public keys. @@ -343,7 +352,9 @@ To spend a P2QRH output, the following conditions must be met: 1. The scriptPubKey must be of the form:
+
 OP_PUSHNUM_3 <32-byte hash>
+
 
2. The attestation must include: @@ -388,13 +399,17 @@ Signature verification is as follows: * Compute hashed_pubkeys by concatenating the HASH256 of each provided public key:
-  hashed_pubkeys = HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN)
+
+  hashed_pubkeys = HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN)
+
 
* Compute computed_hash:
+
   computed_hash = HASH256(hashed_pubkeys)
+
 
* Compare the resulting hash to . If they do not match, the script fails. @@ -408,6 +423,7 @@ Signature verification is as follows: Signing for a single input using both FALCON-1024 and secp256k1 Schnorr:
+
 [num_pubkeys]: 0x02
 
 Pubkey 1:
@@ -427,6 +443,7 @@ Signature 1:
 Signature 2:
   [signature_length]: 0x40 (64 bytes)
   [signature]: signature_secp256k1
+
 
Note: This contrasts with multisig inputs, where the attestation structure repeats for each public key and signature. @@ -486,8 +503,8 @@ bytes || 64 bytes || Hash-based cryptography | [https://eprint.iacr.org/2011/484.pdf XMSS]XMSS, which is based on Winternitz, uses a value of 108 for its most compact signature size, with only a 4.6x (2.34/0.51) increase in verification time. Signing and key generation are not considered a significant factor because they are not distributed throughout the entire Bitcoin -network, which take place only inside of wallets one time. || 2011 || 15,384 bytes || 13,568 bytes || Hash-based -cryptography (Winternitz OTS) +network, which take place only inside of wallets one time. || 2011 || 15,384 bytes || 13,568 bytes || +Hash-based cryptography (Winternitz OTS) |- | [https://pq-crystals.org/dilithium/ CRYSTALS-Dilithium (FIPS 204 - ML-DSA)] || 2017 || 4,595 bytes || 2,592 bytes || Lattice cryptography @@ -504,8 +521,8 @@ Lattice cryptography | [https://eprint.iacr.org/2024/760.pdf SQIsign2D-West] || 2024 || 294 bytes || 130 bytes || Supersingular Elliptic Curve Isogeny |- -| [https://eprint.iacr.org/2023/436.pdf SQIsignHD] || 2023 || 109 bytes (NIST Level I) || Not provided || Supersingular -Elliptic Curve Isogeny +| [https://eprint.iacr.org/2023/436.pdf SQIsignHD] || 2023 || 109 bytes (NIST Level I) || Not provided || +Supersingular Elliptic Curve Isogeny |} As shown, supersingular elliptic curve quaternion isogeny signature algorithms represent the state of the art in @@ -578,7 +595,7 @@ To help implementors understand updates to this BIP, we keep a list of substanti * 2024-09-30 - Refactor the ECC vs PoW section. Swap quitness for attestation. * 2024-09-29 - Update section on PoW to include partial-preimage. * 2024-09-28 - Add Winternitz, XMSS signatures, and security assumption types to PQC table. Omit NIST Level I table. -Add spend script specification. Add revealed public key scenario table. + Add spend script specification. Add revealed public key scenario table. * 2024-09-27 - Initial draft proposal == Acknowledgements == From 9935005efb814b674b3146ea7fb1bb36982c9fb8 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Fri, 6 Dec 2024 11:07:56 -0700 Subject: [PATCH 015/131] I give up. Removing code and pre blocks. --- bip-p2qrh.mediawiki | 42 ++++++------------------------------------ 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index 8b9e0ba46d..456926a74b 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -243,11 +243,7 @@ are used for P2WPKH and P2TR outputs, respectively. The qrh() function takes the HASH256 of the concatenated HASH256 of the quantum-resistant public keys as its argument. For example: - - qrh(HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ...)) - - This function allows wallets to manage P2QRH addresses and outputs while accommodating multiple public keys of varying lengths, such as in multisig schemes, while keeping the public keys hidden until the time of spending. @@ -266,22 +262,16 @@ Example P2QRH address: The scriptPubKey for a P2QRH output is: -
-
 OP_PUSHNUM_3 OP_PUSHBYTES_32 
-
-
Where: - OP_PUSHNUM_3 (0x03) indicates SegWit version 3. -- is the 32-byte HASH256 of the concatenated HASH256 of each public key. +- is the 32-byte HASH256 of the concatenated HASH256 of each public key. ==== Hash Computation ==== -
 hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN))
-
This construction creates a cryptographic commitment to multiple public keys. @@ -289,9 +279,7 @@ This construction creates a cryptographic commitment to multiple public keys. Following BIP-141, the transaction serialization is modified to include a new attestation field after the witness field: -
 [nVersion][marker][flag][txins][txouts][witness][attestation][nLockTime]
-
- marker: 0x00 (same as SegWit) - flag: 0x02 (indicates the presence of both witness and attestation data) @@ -351,15 +339,11 @@ To spend a P2QRH output, the following conditions must be met: 1. The scriptPubKey must be of the form: -
-
 OP_PUSHNUM_3 <32-byte hash>
-
-
2. The attestation must include: -* The quantum-resistant public key(s) whose HASH256 concatenated and hashed again matches the in +* The quantum-resistant public key(s) whose HASH256 concatenated and hashed again matches the in the scriptPubKey. * Valid signatures corresponding to the public key(s) and the transaction data. @@ -374,9 +358,7 @@ fixed-size commitment to potentially multiple public keys of varying lengths. ==== Hash Computation ==== -
 hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN))
-
==== Sighash Calculation ==== @@ -392,27 +374,19 @@ The message to be signed includes these hashes, ensuring transaction malleabilit Signature verification is as follows: -1. Extract the from the scriptPubKey. +1. Extract the from the scriptPubKey. 2. For each input: * Compute hashed_pubkeys by concatenating the HASH256 of each provided public key: -
-
-  hashed_pubkeys = HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN)
-
-
+ hashed_pubkeys = HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN) * Compute computed_hash: -
-
-  computed_hash = HASH256(hashed_pubkeys)
-
-
+computed_hash = HASH256(hashed_pubkeys) -* Compare the resulting hash to . If they do not match, the script fails. +* Compare the resulting hash to . If they do not match, the script fails. 3. Verify each signature against the corresponding public key and the sighash. @@ -422,8 +396,6 @@ Signature verification is as follows: Signing for a single input using both FALCON-1024 and secp256k1 Schnorr: -
-
 [num_pubkeys]: 0x02
 
 Pubkey 1:
@@ -443,8 +415,6 @@ Signature 1:
 Signature 2:
   [signature_length]: 0x40 (64 bytes)
   [signature]: signature_secp256k1
-
-
Note: This contrasts with multisig inputs, where the attestation structure repeats for each public key and signature. From cc47f9e370b3df6eb6ad20592b5d3f738c53d532 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Fri, 6 Dec 2024 11:13:29 -0700 Subject: [PATCH 016/131] More formatting fixes. --- bip-p2qrh.mediawiki | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index 456926a74b..b1c83e68ba 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -145,9 +145,9 @@ cryptography, which is the use of ECC and post-quantum algorithms together. Although CRQCs could pose a threat to the signatures used in Bitcoin, a smaller threat is to Bitcoin's hash algorithms. In particular, while a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a quadratic speedup on brute-force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is -needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160Used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes. -using Grover's algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see +needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160 +Used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes. using Grover's +algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques’ post on this]. === Rationale === @@ -243,7 +243,7 @@ are used for P2WPKH and P2TR outputs, respectively. The qrh() function takes the HASH256 of the concatenated HASH256 of the quantum-resistant public keys as its argument. For example: -qrh(HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ...)) + qrh(HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ...)) This function allows wallets to manage P2QRH addresses and outputs while accommodating multiple public keys of varying lengths, such as in multisig schemes, while keeping the public keys hidden until the time of spending. @@ -262,16 +262,16 @@ Example P2QRH address: The scriptPubKey for a P2QRH output is: -OP_PUSHNUM_3 OP_PUSHBYTES_32 + OP_PUSHNUM_3 OP_PUSHBYTES_32 Where: - OP_PUSHNUM_3 (0x03) indicates SegWit version 3. -- is the 32-byte HASH256 of the concatenated HASH256 of each public key. +- is the 32-byte HASH256 of the concatenated HASH256 of each public key. ==== Hash Computation ==== -hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN)) + hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN)) This construction creates a cryptographic commitment to multiple public keys. @@ -279,10 +279,12 @@ This construction creates a cryptographic commitment to multiple public keys. Following BIP-141, the transaction serialization is modified to include a new attestation field after the witness field: -[nVersion][marker][flag][txins][txouts][witness][attestation][nLockTime] + [nVersion][marker][flag][txins][txouts][witness][attestation][nLockTime] - marker: 0x00 (same as SegWit) + - flag: 0x02 (indicates the presence of both witness and attestation data) + - attestation: Contains the quantum-resistant public keys and signatures. === Attestation Structure === @@ -343,8 +345,9 @@ OP_PUSHNUM_3 <32-byte hash> 2. The attestation must include: -* The quantum-resistant public key(s) whose HASH256 concatenated and hashed again matches the in +* The quantum-resistant public key(s) whose HASH256 concatenated and hashed again matches the in the scriptPubKey. + * Valid signatures corresponding to the public key(s) and the transaction data. 3. For multi-signature schemes, all required public keys and signatures must be provided for that input within the @@ -374,7 +377,7 @@ The message to be signed includes these hashes, ensuring transaction malleabilit Signature verification is as follows: -1. Extract the from the scriptPubKey. +1. Extract the from the scriptPubKey. 2. For each input: @@ -384,9 +387,9 @@ Signature verification is as follows: * Compute computed_hash: -computed_hash = HASH256(hashed_pubkeys) + computed_hash = HASH256(hashed_pubkeys) -* Compare the resulting hash to . If they do not match, the script fails. +* Compare the resulting hash to . If they do not match, the script fails. 3. Verify each signature against the corresponding public key and the sighash. @@ -396,7 +399,9 @@ computed_hash = HASH256(hashed_pubkeys) Signing for a single input using both FALCON-1024 and secp256k1 Schnorr: -[num_pubkeys]: 0x02 +Number of public keys: + + [num_pubkeys]: 0x02 Pubkey 1: [pubkey_length]: 0x0701 (1793 bytes) @@ -406,7 +411,9 @@ Pubkey 2: [pubkey_length]: 0x20 (32 bytes) [pubkey]: public_key_secp256k1 -[num_signatures]: 0x02 +Number of signatures: + + [num_signatures]: 0x02 Signature 1: [signature_length]: 0x0500 (1280 bytes) From ff4d2c28198fb363a91cfca91f456af6f81af049 Mon Sep 17 00:00:00 2001 From: Hunter Beast Date: Fri, 6 Dec 2024 11:27:08 -0700 Subject: [PATCH 017/131] Apply suggestions from code review Co-authored-by: Mark "Murch" Erhardt --- bip-p2qrh.mediawiki | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index b1c83e68ba..b05093aa5b 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -1,16 +1,16 @@
-  BIP: TBD
+  BIP: ?
+  Layer: 
   Comments-Summary: No comments yet.
   Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-TBD
   Status: Draft
   Type: Standards Track
-  License: BSD-3-Clause
   Created: 2024-06-08
+  License: BSD-3-Clause
 
-__TOC__ == Introduction == From f206b9745af582f9d649787ff872ca41a0683c71 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Fri, 6 Dec 2024 11:28:05 -0700 Subject: [PATCH 018/131] Address Murch feedback. --- bip-p2qrh.mediawiki | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index b1c83e68ba..2b8b49f878 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -25,21 +25,20 @@ This document is licensed under the 3-clause BSD license. === Motivation === -This proposal aims to improve the quantum resistance of Bitcoin's signature security should the Discrete Logarithm -Problem (DLP), which secures Elliptic Curve Cryptography (ECC), no longer prove to be computationally hard, likely -through quantum advantage by Cryptoanalytically-Relevant Quantum Computers (CRQCs). -[https://arxiv.org/pdf/quant-ph/0301141 A variant of Shor's algorithm] is believed to be capable of deriving the -private key from a public key exponentially faster than classical means. The application of this variant of Shor's -algorithm is herein referred to as quantum key decryption. Note that doubling the public key length, such as with a -hypothetical secp512k1 curve, would only make deriving the private key twice as hard. The computational complexity of -this is investigated further in the paper, +The primary threat to Bitcoin from Cryptoanalytically-Relevant Quantum Computers (CRQCs) is their potential to break +the cryptographic assumptions of Elliptic Curve Cryptography (ECC), which secures Bitcoin's signatures and Taproot +commitments. Specifically, [https://arxiv.org/pdf/quant-ph/0301141 Shor's algorithm] enables a CRQC to solve the +Discrete Logarithm Problem (DLP) exponentially faster than classical methodsShor's algorithm is +believed to need 10^8 operations to break a 256-bit elliptic curve public key., allowing the derivation of private +keys from public keys—a process referred to as quantum key decryption. Importantly, simply increasing the public key +length (e.g., using a hypothetical secp512k1 curve) would only make deriving the private key twice as hard, offering +insufficient protection. The computational complexity of this attack is further explored in [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact -of hardware specifications on reaching quantum advantage in the fault tolerant regime'']. +of hardware specifications on reaching quantum advantage in the fault-tolerant regime'']. -The primary threat to Bitcoin by CRQCs is [https://en.bitcoin.it/wiki/Quantum_computing_and_Bitcoin#QC_attacks -generally considered to be their potential to break ECC, which is used in signatures and Taproot commitments], hence -the focus on a new address format. Shor's algorithm enables a CRQC to break the cryptographic assumptions of ECC in -roughly 10^8 quantum operations. +This proposal aims to mitigate these risks by introducing a Pay to Quantum Resistant Hash (P2QRH) address type that +relies on post-quantum cryptographic (PQC) signature algorithms. By adopting PQC, Bitcoin can enhance its quantum +resistance without requiring a hard fork or block size increase. The vulnerability of existing Bitcoin addresses is investigated in [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers- @@ -48,11 +47,12 @@ Bitcoin supply is held within addresses vulnerable to quantum attack. As of the closer to 20%. Additionally, cryptographer Pieter Wuille [https://x.com/pwuille/status/1108085284862713856 reasons] even more might be vulnerable. -Ordinarily, when a transaction is signed, the public key can be recovered from the signature. This makes a transaction -submitted to the mempool vulnerable to quantum attack until it's mined. One way to mitigate this is to submit the -transaction directly to a mining pool, which bypasses the mempool. This process is known as an out-of-band transaction. -The mining pool must be trusted not to reveal the transaction public key to attackers. The problem with this approach -is that it requires a trusted third party, which is what this P2QRH proposal aims to avoid. +Ordinarily, when a transaction is signed, the public key is explicitly stated in the input script. This means that the +public key is exposed on the blockchain when the transaction is spent, making it vulnerable to quantum attack until +it's mined. One way to mitigate this is to submit the transaction directly to a mining pool, bypassing the mempool. +This process is known as an out-of-band transaction or a private mempool. In this case, the mining pool must be trusted +not to reveal the transaction public key to attackers. The problem with this approach is that it requires a trusted +third party, which the P2QRH proposal aims to avoid. Not having public keys exposed on-chain is an important step for quantum security. Otherwise, funds would need to be spent to new addresses on a regular basis in order to prevent the possibility of a "long-range CRQC attack" recovering @@ -271,7 +271,8 @@ Where: ==== Hash Computation ==== - hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN)) + hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || +HASH256(pubkeyN)) This construction creates a cryptographic commitment to multiple public keys. From feff8477c0e1016370adfa93d3aecee0e53a2f33 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Fri, 6 Dec 2024 11:30:30 -0700 Subject: [PATCH 019/131] MediaWiki formatting. --- bip-p2qrh.mediawiki | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index 7768f9c887..2441dedb83 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -266,13 +266,13 @@ The scriptPubKey for a P2QRH output is: Where: -- OP_PUSHNUM_3 (0x03) indicates SegWit version 3. -- is the 32-byte HASH256 of the concatenated HASH256 of each public key. +* OP_PUSHNUM_3 (0x03) indicates SegWit version 3. +* is the 32-byte HASH256 of the concatenated HASH256 of each public key. ==== Hash Computation ==== hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || -HASH256(pubkeyN)) + HASH256(pubkeyN)) This construction creates a cryptographic commitment to multiple public keys. @@ -282,11 +282,11 @@ Following BIP-141, the transaction serialization is modified to include a new at [nVersion][marker][flag][txins][txouts][witness][attestation][nLockTime] -- marker: 0x00 (same as SegWit) +* marker: 0x00 (same as SegWit) -- flag: 0x02 (indicates the presence of both witness and attestation data) +* flag: 0x02 (indicates the presence of both witness and attestation data) -- attestation: Contains the quantum-resistant public keys and signatures. +* attestation: Contains the quantum-resistant public keys and signatures. === Attestation Structure === @@ -511,8 +511,8 @@ achieved broader community consensus. FALCON signatures are also NIST approved. In comparison, the size of currently used signature algorithms are: -- ECDSA: 70-72 bytes -- Schnorr: 64 bytes +* ECDSA: 70-72 bytes +* Schnorr: 64 bytes In comparison to inception date, secp256k1 [https://www.secg.org/SEC1-Ver-1.0.pdf was originally specified in 2000]. From e186b52cff5344c789bc5996de86697e62244323 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Mon, 9 Dec 2024 09:57:06 -0700 Subject: [PATCH 020/131] Swap layer and title. --- bip-p2qrh.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki index 2441dedb83..55a86443f3 100644 --- a/bip-p2qrh.mediawiki +++ b/bip-p2qrh.mediawiki @@ -1,7 +1,7 @@
   BIP: ?
-  Layer: 
   Comments-Summary: No comments yet.
   Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-TBD

From d5001241ba049e18a91cd2722b5e614ec939914f Mon Sep 17 00:00:00 2001
From: Hunter Beast 
Date: Fri, 13 Dec 2024 08:35:30 -0700
Subject: [PATCH 021/131] Apply suggestions from code review

Co-authored-by: Ethan Heilman 
---
 bip-p2qrh.mediawiki | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki
index 55a86443f3..701a8307a1 100644
--- a/bip-p2qrh.mediawiki
+++ b/bip-p2qrh.mediawiki
@@ -69,7 +69,7 @@ algorithm. This new address type protects transactions submitted to the mempool
 preventing the need for private, out-of-band mempool transactions.
 
 The following table is non-exhaustive but intended to inform the average Bitcoin user whether their bitcoin is
-vulnerable to a long-range quantum attack.
+vulnerable to a long-range quantum attack:
 
 {| class="wikitable"
 |+ Vulnerable address types
@@ -316,7 +316,7 @@ must count the number of inputs present in the transaction.
 
 === Signature Algorithm Identification ===
 
-The specific quantum-resistant signature algorithm used is inferred from the length of the public key and signature.
+The specific quantum-resistant signature algorithm used is inferred from the length of the public key.
 Implementations must recognize the supported algorithms and validate accordingly.
 
 Supported algorithms and their NIST Level V parameters:

From 85a347b5a236efde76dd76f91768d7820b31e9e0 Mon Sep 17 00:00:00 2001
From: Hunter Trujillo 
Date: Fri, 13 Dec 2024 09:31:51 -0700
Subject: [PATCH 022/131] Update to use merkle tree for attestation commitment.
 Update LR & SR quantum attack scenarios.

---
 bip-p2qrh.mediawiki | 103 ++++++++++++++++++++++++--------------------
 1 file changed, 57 insertions(+), 46 deletions(-)

diff --git a/bip-p2qrh.mediawiki b/bip-p2qrh.mediawiki
index 701a8307a1..10b8c3fb2d 100644
--- a/bip-p2qrh.mediawiki
+++ b/bip-p2qrh.mediawiki
@@ -93,27 +93,25 @@ full public key can be reconstructed.
 If a key is recovered by a CRQC it can also be trivially checked to see if any child keys were produced using an
 unhardened [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32] derivation path.
 
-The following table summarizes the scenarios in which public keys are revealed when using Bitcoin and what type of
-attack the underlying addresses are vulnerable to:
+==== Long Range and Short Range Quantum Attacks ====
 
-{| class="wikitable"
-|+ Scenarios for revealed public keys on Bitcoin
-|-
-! Scenario !! Type of attack
-|-
-| Early addresses (Satoshi's coins, CPU miners, starts with 04) || Long-range
-|-
-| Reused addresses (any type, except P2QRH) || Long-range
-|-
-| Taproot addresses (starts with bc1p) || Long-range
-|-
-| Any transaction in the mempool (except for P2QRH) || Short-range
-|-
-| Unhardened BIP-32 HD wallet keys || Both Long-range or Short-range
-|}
+Long Range Quantum Attack is an attack in which the public key has been exposed on the blockchain for an extended
+period of time, giving an attacker ample opportunity to break the cryptography. This affects:
+
+* Early addresses (Satoshi's coins, CPU miners, starts with 04)
+* Reused addresses (any type, except P2QRH)
+* Taproot addresses (starts with bc1p)
+* Unhardened BIP-32 HD wallet keys
+
+Short Range Quantum Attack is an attack that must be executed quickly while a transaction is still in the mempool,
+before it gets mined into a block. This affects:
 
-The only time a short-range attack can occur is when the transaction is in the mempool, whereas a long-range attack
-occurs when the public key is known well in advance. Short-range attacks require much larger, more expensive CRQCs.
+* Any transaction in the mempool (except for P2QRH)
+* Unhardened BIP-32 HD wallet keys
+
+Short-range attacks require much larger, more expensive CRQCs since they must be executed within the short window
+before a transaction is mined. Long-range attacks can be executed over a longer timeframe since the public key remains
+exposed on the blockchain indefinitely.
 
 Should quantum advantage manifest, a convention is proposed in spending the full 65-byte P2PK key used by the coinbase
 output in Block 1 back to itself. It is proposed to call the address in Block 1 the
@@ -124,11 +122,13 @@ broken. Should the Canary coins move, that will signal that reliance on secp256k
 Canary, or an address like it, there may be some doubt as to whether the coins were moved with keys belonging to the
 original owner.
 
-As an interesting aside, coinbase outputs to P2PK keys go as far as block 200,000, so there are 1,723,848 coins that
-are vulnerable from the first epoch at the time of writing in P2PK outputs alone. Since the majority of these have a
-block reward of 50 coins each, there are roughly 34,000 distinct P2PK addresses that are vulnerable. These coins can be
+Coinbase outputs to P2PK keys go as far as block 200,000, so there are, at the time of writing, 1,723,848 coins that
+are vulnerable from the first epoch at the time of writing in P2PK outputs alone. The majority of these have a
+block reward of 50 coins each, and there are roughly 34,000 distinct P2PK addresses that are vulnerable. These coins
+can be
 considered "Satoshi's Shield." Any addresses with a balance of less than the original block subsidy of 50 coins can be
-considered incentive incompatible to capture until all of these are mined, and these addresses serve to provide time to
+considered cryptoeconomically incentive incompatible to capture until all of these are mined, and these addresses serve
+to provide time to
 transition Bitcoin to implement post-quantum security.
 
 It's for the above reason that, for those who wish to be prepared for quantum emergency, it is recommended that no more
@@ -271,10 +271,34 @@ Where:
 
 ==== Hash Computation ====
 
-  hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... ||
-  HASH256(pubkeyN))
+The hash is computed as a merkle tree of public key hashes:
+
+1. For each public key, compute its HASH256
+2. Pair the hashes and compute HASH256 of their concatenation
+3. Continue pairing and hashing until reaching a single root hash
+4. The final hash is the merkle root
+
+For example with 4 public keys:
 
-This construction creates a cryptographic commitment to multiple public keys.
+  h1 = HASH256(pubkey1)
+  h2 = HASH256(pubkey2)
+  h3 = HASH256(pubkey3)
+  h4 = HASH256(pubkey4)
+
+  h12 = HASH256(h1 || h2)
+  h34 = HASH256(h3 || h4)
+
+  root = HASH256(h12 || h34)
+
+When spending, if a public key hash is provided in the attestation with an empty signature, that hash will be used
+directly in the merkle tree computation rather than hashing the full public key. This allows excluding unused public
+keys from the transaction while still proving they were part of the original commitment.
+
+This merkle tree construction creates an efficient cryptographic commitment to multiple public keys while enabling
+selective disclosure.
+
+This allows for inclusion of a Taproot MAST merkle root in the attestation, which makes P2QRH a quantum-resistant
+version of Taproot.
 
 === Transaction Serialization ===
 
@@ -319,7 +343,7 @@ must count the number of inputs present in the transaction.
 The specific quantum-resistant signature algorithm used is inferred from the length of the public key.
 Implementations must recognize the supported algorithms and validate accordingly.
 
-Supported algorithms and their NIST Level V parameters:
+Supported PQC algorithms and their NIST Level V parameters:
 
 * '''SPHINCS+-256f:'''
   * Public Key Length: 64 bytes
@@ -352,17 +376,8 @@ the scriptPubKey.
 * Valid signatures corresponding to the public key(s) and the transaction data.
 
 3. For multi-signature schemes, all required public keys and signatures must be provided for that input within the
-attestation. This includes classical Schnorr signatures.
-
-==== Public Key Hashing ====
-
-All public keys included in the attestation are hashed using HASH256 (double SHA-256). The concatenation of these
-hashes is then hashed again using HASH256 before being included in the scriptPubKey. This ensures a
-fixed-size commitment to potentially multiple public keys of varying lengths.
-
-==== Hash Computation ====
-
-hash = HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN))
+attestation. Public keys that are not needed can be excluded by including their hash in the attestation accompanied
+with an empty signature. This includes classical Schnorr signatures.
 
 ==== Sighash Calculation ====
 
@@ -382,19 +397,14 @@ Signature verification is as follows:
 
 2. For each input:
 
-* Compute hashed_pubkeys by concatenating the HASH256 of each provided public key:
-
-  hashed_pubkeys = HASH256(pubkey1) || HASH256(pubkey2) || ... || HASH256(pubkeyN)
-
-* Compute computed_hash:
-
-  computed_hash = HASH256(hashed_pubkeys)
+* Compute hashed_pubkeys as specified in the Hash Computation section.
 
 * Compare the resulting hash to . If they do not match, the script fails.
 
 3. Verify each signature against the corresponding public key and the sighash.
 
-4. Ensure that the signature algorithm used matches the expected lengths for NIST Level V security and is supported.
+4. Ensure that the signature algorithm used matches the expected lengths for NIST Level V security, and is supported by
+the implementation.
 
 ==== Attestation Parsing Example ====
 
@@ -565,6 +575,7 @@ transcript]
 
 To help implementors understand updates to this BIP, we keep a list of substantial changes.
 
+* 2024-12-13 - Update to use merkle tree for attestation commitment. Update LR & SR quantum attack scenarios.
 * 2024-12-06 - Update title and formatting.
 * 2024-12-03 - MediaWiki formatting fixes.
 * 2024-12-01 - Add details on attestation structure and parsing.

From 85348c01ff840d77302013db0540897fafbd8e6d Mon Sep 17 00:00:00 2001
From: Hunter Trujillo 
Date: Wed, 18 Dec 2024 14:43:24 -0700
Subject: [PATCH 023/131] P2QRH assigned BIP number 360.

---
 README.mediawiki                          |  7 +++++++
 bip-p2qrh.mediawiki => bip-0360.mediawiki | 20 +++++++++-----------
 2 files changed, 16 insertions(+), 11 deletions(-)
 rename bip-p2qrh.mediawiki => bip-0360.mediawiki (98%)

diff --git a/README.mediawiki b/README.mediawiki
index d92cb78669..a5eeabd778 100644
--- a/README.mediawiki
+++ b/README.mediawiki
@@ -1148,6 +1148,13 @@ Those proposing changes should consider that ultimately consent may rest with th
 | Matt Corallo, Bastien Teinturier
 | Standard
 | Draft
+|-
+| [[bip-0360.mediawiki|360]]
+| Consensus (soft fork)
+| QuBit: SegWit v3 spending rules (P2QRH)
+| Hunter Beast
+| Standard
+| Draft
 |- style="background-color: #cfffcf"
 | [[bip-0370.mediawiki|370]]
 | Applications
diff --git a/bip-p2qrh.mediawiki b/bip-0360.mediawiki
similarity index 98%
rename from bip-p2qrh.mediawiki
rename to bip-0360.mediawiki
index 10b8c3fb2d..7f2aaf910b 100644
--- a/bip-p2qrh.mediawiki
+++ b/bip-0360.mediawiki
@@ -1,13 +1,13 @@
 
-  BIP: ?
-  Title: QuBit: SegWit version 3 spending rules (P2QRH)
-  Layer: 
   Comments-Summary: No comments yet.
-  Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-TBD
+  Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0360
   Status: Draft
   Type: Standards Track
-  Created: 2024-06-08
+  Created: 2024-12-18
   License: BSD-3-Clause
 
@@ -561,11 +561,9 @@ seeds to act as the authoritative secret when signing. These measures are deemed == References == * [https://groups.google.com/g/bitcoindev/c/Aee8xKuIC2s/m/cu6xej1mBQAJ Mailing list discussion] -* [https://delvingbitcoin.org/t/proposing-a-p2qrh-bip-towards-a-quantum-resistant-soft-fork/956?u=cryptoquick Delving -Bitcoin discussion] +* [https://delvingbitcoin.org/t/proposing-a-p2qrh-bip-towards-a-quantum-resistant-soft-fork/956?u=cryptoquick Delving Bitcoin discussion] * [https://bitcoinops.org/en/newsletters/2024/06/14/ Bitcoin OpTech newsletter] -* [https://bitcoinops.org/en/podcast/2024/06/18/#draft-bip-for-quantum-safe-address-format Bitcoin OpTech discussion -transcript] +* [https://bitcoinops.org/en/podcast/2024/06/18/#draft-bip-for-quantum-safe-address-format Bitcoin OpTech discussion transcript] == Footnotes == @@ -575,6 +573,7 @@ transcript] To help implementors understand updates to this BIP, we keep a list of substantial changes. +* 2024-12-18 - Assigned BIP number. * 2024-12-13 - Update to use merkle tree for attestation commitment. Update LR & SR quantum attack scenarios. * 2024-12-06 - Update title and formatting. * 2024-12-03 - MediaWiki formatting fixes. @@ -583,8 +582,7 @@ To help implementors understand updates to this BIP, we keep a list of substanti * 2024-10-21 - Replace XMSS with CRYSTALS-Dilithium due to NIST approval and size constraints. * 2024-09-30 - Refactor the ECC vs PoW section. Swap quitness for attestation. * 2024-09-29 - Update section on PoW to include partial-preimage. -* 2024-09-28 - Add Winternitz, XMSS signatures, and security assumption types to PQC table. Omit NIST Level I table. - Add spend script specification. Add revealed public key scenario table. +* 2024-09-28 - Add Winternitz, XMSS signatures, and security assumption types to PQC table. Omit NIST Level I table. Add spend script specification. Add revealed public key scenario table. * 2024-09-27 - Initial draft proposal == Acknowledgements == From a4f3dc688394a614fb300defe120c3d6a66f68c7 Mon Sep 17 00:00:00 2001 From: Hunter Beast Date: Fri, 20 Dec 2024 10:08:23 -0700 Subject: [PATCH 024/131] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Vojtěch Strnad <43024885+vostrnad@users.noreply.github.com> --- bip-0360.mediawiki | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki index 7f2aaf910b..d7b5febcec 100644 --- a/bip-0360.mediawiki +++ b/bip-0360.mediawiki @@ -36,7 +36,7 @@ insufficient protection. The computational complexity of this attack is further [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault-tolerant regime'']. -This proposal aims to mitigate these risks by introducing a Pay to Quantum Resistant Hash (P2QRH) address type that +This proposal aims to mitigate these risks by introducing a Pay to Quantum Resistant Hash (P2QRH) output type that relies on post-quantum cryptographic (PQC) signature algorithms. By adopting PQC, Bitcoin can enhance its quantum resistance without requiring a hard fork or block size increase. @@ -72,9 +72,9 @@ The following table is non-exhaustive but intended to inform the average Bitcoin vulnerable to a long-range quantum attack: {| class="wikitable" -|+ Vulnerable address types +|+ Vulnerable output types |- -! Address type !! Vulnerable !! Prefix !! Example +! Type !! Vulnerable !! Prefix !! Example |- | P2PK || Yes || 04 || 0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf @@ -87,7 +87,7 @@ vulnerable to a long-range quantum attack: | P2TR || Yes || bc1p || bc1p92aslsnseq786wxfk3ekra90ds9ku47qttupfjsqmmj4z82xdq4q3rr58u |} -It should be noted that Taproot addresses are vulnerable in that they encode a 32-byte x-only public key, from which a +It should be noted that Taproot outputs are vulnerable in that they encode a 32-byte x-only public key, from which a full public key can be reconstructed. If a key is recovered by a CRQC it can also be trivially checked to see if any child keys were produced using an @@ -98,7 +98,7 @@ unhardened [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-3 Long Range Quantum Attack is an attack in which the public key has been exposed on the blockchain for an extended period of time, giving an attacker ample opportunity to break the cryptography. This affects: -* Early addresses (Satoshi's coins, CPU miners, starts with 04) +* P2PK outputs (Satoshi's coins, CPU miners, starts with 04) * Reused addresses (any type, except P2QRH) * Taproot addresses (starts with bc1p) * Unhardened BIP-32 HD wallet keys @@ -124,7 +124,7 @@ original owner. Coinbase outputs to P2PK keys go as far as block 200,000, so there are, at the time of writing, 1,723,848 coins that are vulnerable from the first epoch at the time of writing in P2PK outputs alone. The majority of these have a -block reward of 50 coins each, and there are roughly 34,000 distinct P2PK addresses that are vulnerable. These coins +block reward of 50 coins each, and there are roughly 34,000 distinct P2PK scripts that are vulnerable. These coins can be considered "Satoshi's Shield." Any addresses with a balance of less than the original block subsidy of 50 coins can be considered cryptoeconomically incentive incompatible to capture until all of these are mined, and these addresses serve @@ -139,7 +139,7 @@ cryptography by this time. The Commercial National Security Algorithm Suite (CNSA) 2.0 has a timeline for software and networking equipment to be upgraded by 2030, with browsers and operating systems fully upgraded by 2033. According to NIST IR 8547, Elliptic Curve -Cryptography is planned to be disallowed within the US Federal government after 2035. An exception is made for hybrid +Cryptography is planned to be disallowed within the US federal government after 2035. An exception is made for hybrid cryptography, which is the use of ECC and post-quantum algorithms together. Although CRQCs could pose a threat to the signatures used in Bitcoin, a smaller threat is to Bitcoin's hash algorithms. @@ -194,7 +194,7 @@ inscriptions would also have the scarcity of their non-monetary assets affected. while also increasing the discount is to have a completely separate witness—a "quantum witness." Because it is meant only for public keys and signatures, we call this section of the transaction the attestation. -To address the risk of arbitrary data being stored using P2QRH (QuBit) addresses, very specific rules will be applied +To address the risk of arbitrary data being stored using P2QRH (QuBit) outputs, very specific rules will be applied to spending from the witness stack in SegWit v3 outputs. A fixed signature size will be necessary for spending the output, and the output must be spendable to be considered valid within node consensus. A fixed signature size will also be helpful to disambiguate between signature types without an additional version byte, as SQIsign signatures are @@ -224,7 +224,7 @@ Bitcoin, but their signatures are smaller and might be considered by some to be signatures. SQIsign is much smaller; however, it is based on a very novel form of cryptography known as supersingular elliptic curve quaternion isogeny, and at the time of writing, is not yet approved by NIST or the broader PQC community. -In the distant future, following the implementation of the P2QRH address format in a QuBit soft fork, there will likely +In the distant future, following the implementation of the P2QRH output type in a QuBit soft fork, there will likely be a need for Pay to Quantum Secure (P2QS) addresses. These will require specialized quantum hardware for signing, while still [https://quantum-journal.org/papers/q-2023-01-19-901/ using public keys that are verifiable via classical means]. Additional follow-on BIPs will be needed to implement P2QS. However, until specialized quantum cryptography @@ -302,7 +302,7 @@ version of Taproot. === Transaction Serialization === -Following BIP-141, the transaction serialization is modified to include a new attestation field after the witness field: +Following BIP-141, a new transaction serialization format is introduced to include an attestation field after the witness field: [nVersion][marker][flag][txins][txouts][witness][attestation][nLockTime] @@ -532,7 +532,7 @@ chosen as Bitcoin's curve. Isogeny cryptography when it was first introduced was Ideally SQIsign also proves to be flexible enough to support [https://www.pierrickdartois.fr/homepage/wp-content/uploads/2022/04/Report_OSIDH_DARTOIS.pdf Isogeny Diffie-Hellman] to replace ECDH applications, and also provide methods for the key tweaking necessary to support TapScript for P2QR -addresses. Additionally, isogeny-based post-quantum cryptography is based on higher-order elliptic curves, and so it +outputs. Additionally, isogeny-based post-quantum cryptography is based on higher-order elliptic curves, and so it might be possible to implement Isogeny Schnorr signatures. Signature verification speed as it compares to Schnorr or ECDSA isn't seen as high a consideration as signature size @@ -588,7 +588,7 @@ To help implementors understand updates to this BIP, we keep a list of substanti == Acknowledgements == This document is inspired by [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341], which introduced -the design of the P2TR (Taproot) address type using Schnorr signatures. +the design of the P2TR (Taproot) output type using Schnorr signatures. Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name "QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as From 2b641b899e3d06344a01282cc27460eb09a16d04 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Fri, 20 Dec 2024 11:43:24 -0700 Subject: [PATCH 025/131] Address feedback from vostrnad. --- bip-0360.mediawiki | 66 +++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki index d7b5febcec..aa841f5855 100644 --- a/bip-0360.mediawiki +++ b/bip-0360.mediawiki @@ -60,31 +60,45 @@ the key behind high-value addresses. A long-range quantum attack can be consider as that from a used address or one encoded in a spend script. This is likely to be more common early on, as early quantum computers must be run for longer in order to overcome errors caused by noise. A "short-range quantum attack" would be one performed on keys in the mempool, which is seen as much more difficult given the block time, and so it -requires more sophisticated CRQCs. As the value being sent increases, so too should the fee in order to commit the -transaction to the chain as soon as possible. Once the transaction is mined, it makes useless the public key revealed -by spending a UTXO, so long as it is never reused. +requires more sophisticated CRQCs. +In the paper +[https://arxiv.org/pdf/2306.08585 How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates] +the authors estimate that CRQC with 28 million superconducting physical qubits would take 8.3 seconds to calculate a +256-bit key, while a CRQC with 6.9 million physical qubits would take 58 seconds. This implies that a CRQC with 4x as +many qubits would be roughly 7 times faster. + + +As the value being sent increases, so too should the fee in order to commit the transaction to the chain as soon as +possible. Once the transaction is mined, it makes useless the public key revealed by spending a UTXO, so long as it is +never reused. It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) address type that relies on a PQC signature algorithm. This new address type protects transactions submitted to the mempool and helps preserve the free market by preventing the need for private, out-of-band mempool transactions. -The following table is non-exhaustive but intended to inform the average Bitcoin user whether their bitcoin is -vulnerable to a long-range quantum attack: +The following table is intended to inform the average Bitcoin user whether their bitcoin is vulnerable to a long-range +quantum attack: {| class="wikitable" |+ Vulnerable output types |- ! Type !! Vulnerable !! Prefix !! Example |- -| P2PK || Yes || 04 || -0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf -2342c858ee +| P2PK || Yes || Varies || 2103203b768951584fe9af6d9d9e6ff26a5f76e453212f19ba163774182ab8057f3eac |- | P2PKH || No || 1 || 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa |- +| P2MS || Yes || Varies || 52410496ec45f878b62c46c4be8e336dff7cc58df9b502178cc240e... +|- +| P2SH || No || 5 || 3FkhZo7sGNue153xhgqPBcUaBsYvJW6tTx +|- | P2WPKH || No || bc1q || bc1qsnh5ktku9ztqeqfr89yrqjd05eh58nah884mku |- +| P2WSH || No || bc1q || bc1qvhu3557twysq2ldn6dut6rmaj3qk04p60h9l79wk4lzgy0ca8mfsnffz65 +|- | P2TR || Yes || bc1p || bc1p92aslsnseq786wxfk3ekra90ds9ku47qttupfjsqmmj4z82xdq4q3rr58u +|- +| P2QRH || No || bc1r || bc1r8rt68aze8tek87cnz4ndnvfzk6tk93jv39n4lmpu5a4yw453rcpszsft3z |} It should be noted that Taproot outputs are vulnerable in that they encode a 32-byte x-only public key, from which a @@ -113,14 +127,13 @@ Short-range attacks require much larger, more expensive CRQCs since they must be before a transaction is mined. Long-range attacks can be executed over a longer timeframe since the public key remains exposed on the blockchain indefinitely. -Should quantum advantage manifest, a convention is proposed in spending the full 65-byte P2PK key used by the coinbase -output in Block 1 back to itself. It is proposed to call the address in Block 1 the +Should quantum advantage manifest, a convention is proposed in spending the 65-byte P2PK output used by the coinbase +output in Block 1. It is proposed to call the address in Block 1 the [https://mempool.space/address/0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f81 -41781e62294721166bf621e73a82cbf2342c858ee -Canary address] since it can only be spent from by others (assuming Satoshi's continued absence) if secp256k1 is -broken. Should the Canary coins move, that will signal that reliance on secp256k1 is presently vulnerable. Without the -Canary, or an address like it, there may be some doubt as to whether the coins were moved with keys belonging to the -original owner. +41781e62294721166bf621e73a82cbf2342c858ee Canary address] since it can only be spent from by others (assuming Satoshi's + continued absence) if secp256k1 is broken. Should the Canary coins move, that will signal that reliance on secp256k1 +is presently vulnerable. Without the Canary, or an address like it, there may be some doubt as to whether the coins were +moved with keys belonging to the original owner. Coinbase outputs to P2PK keys go as far as block 200,000, so there are, at the time of writing, 1,723,848 coins that are vulnerable from the first epoch at the time of writing in P2PK outputs alone. The majority of these have a @@ -156,8 +169,7 @@ This is the first in a series of BIPs under a QuBit soft fork. A qubit is a fund the capital B refers to Bitcoin. The name QuBit also rhymes to some extent with SegWit. It is proposed to use SegWit version 3. This results in addresses that start with bc1r, which could be a useful way to -remember that these are quantum (r)esistant addresses (similar to how bc1q corresponds to Se(q)Wit and bc1p corresponds -to Ta(p)root). This is referencing the lookup table under +remember that these are quantum (r)esistant addresses. This is referencing the lookup table under [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. The proposal above also leaves a gap in case it makes sense to use version 2, or bc1z, for implementation of other @@ -169,11 +181,9 @@ should a vulnerability exist in one of the signature algorithms used. One key di however is that P2QRH will encode a hash of the public key. This is a significant deviation from how Taproot works by itself, but it is necessary to avoid exposing public keys on-chain where they are vulnerable to attack. -P2QRH uses a 32-byte HASH256 (specifically SHA-256 twice-over, which is similar to that used in -[https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#specification BIP-16]) of the public key to reduce the -size of new outputs and also to increase security by not having the public key available on-chain. This hash serves as -a minimal cryptographic commitment to a public key. It goes into the output spend script, which does not receive the -witness discount. +P2QRH uses a 32-byte HASH256 (specifically SHA-256 twice-over) of the public key to reduce the size of new outputs and +also to increase security by not having the public key available on-chain. This hash serves as a minimal cryptographic +commitment to a public key. It goes into the scriptPubKey, which does not receive the witness discount. Post-quantum public keys are generally larger than those used by ECC, depending on the security level. To promote user adoption and general user-friendliness, the most secure variant (NIST Level V, 256-bit security) is proposed, despite @@ -316,20 +326,21 @@ Following BIP-141, a new transaction serialization format is introduced to inclu The attestation field consists of: -* num_pubkeys: The number of public keys (VarInt encoded). +* num_pubkeys: The number of public keys +([https://learnmeabitcoin.com/technical/general/compact-size/ compact size]). For each public key: -* pubkey_length: VarInt encoded length of the public key. +* pubkey_length: compact size length of the public key. * pubkey: The public key bytes. Then: -* num_signatures: The number of signatures (VarInt encoded). +* num_signatures: The number of signatures (compact size). For each signature: -* signature_length: VarInt encoded length of the signature. +* signature_length: compact size length of the signature. * signature: The signature bytes. This structure repeats for each input, in order, for flexibility in supporting multisig schemes and various @@ -573,6 +584,7 @@ seeds to act as the authoritative secret when signing. These measures are deemed To help implementors understand updates to this BIP, we keep a list of substantial changes. +* 2024-12-20 - Address feedback from vostrnad. * 2024-12-18 - Assigned BIP number. * 2024-12-13 - Update to use merkle tree for attestation commitment. Update LR & SR quantum attack scenarios. * 2024-12-06 - Update title and formatting. @@ -593,4 +605,4 @@ the design of the P2TR (Taproot) output type using Schnorr signatures. Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name "QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as well to those who took the time to review and contribute, including Jeff Bride, Adam Borcany, Antoine Riard, Pierre-Luc -Dallaire-Demers, Ethan Heilman, Jon Atack, Jameson Lopp, and Murchandamus. +Dallaire-Demers, Ethan Heilman, Jon Atack, Jameson Lopp, Murchandamus, and Vojtěch Strnad. From 4b8b6470e6e46a22a50595b060875f12bc17cb99 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Fri, 20 Dec 2024 11:46:31 -0700 Subject: [PATCH 026/131] Update typos list. --- .typos.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/.typos.toml b/.typos.toml index 4f9fbef9af..8ff6f5309d 100644 --- a/.typos.toml +++ b/.typos.toml @@ -16,6 +16,7 @@ extend-ignore-re = [ "prefix.*", "value: .*", "pqNTRUsign", + "Strnad", ] [default.extend-words] From 990d8a87b5181fd4f0d50a1b65b53fbc02bc6330 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Fri, 20 Dec 2024 13:02:33 -0700 Subject: [PATCH 027/131] Fixes, typos, formatting. --- bip-0360.mediawiki | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki index aa841f5855..6d859cba7e 100644 --- a/bip-0360.mediawiki +++ b/bip-0360.mediawiki @@ -90,7 +90,7 @@ quantum attack: |- | P2MS || Yes || Varies || 52410496ec45f878b62c46c4be8e336dff7cc58df9b502178cc240e... |- -| P2SH || No || 5 || 3FkhZo7sGNue153xhgqPBcUaBsYvJW6tTx +| P2SH || No || 3 || 3FkhZo7sGNue153xhgqPBcUaBsYvJW6tTx |- | P2WPKH || No || bc1q || bc1qsnh5ktku9ztqeqfr89yrqjd05eh58nah884mku |- @@ -131,7 +131,7 @@ Should quantum advantage manifest, a convention is proposed in spending the 65-b output in Block 1. It is proposed to call the address in Block 1 the [https://mempool.space/address/0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f81 41781e62294721166bf621e73a82cbf2342c858ee Canary address] since it can only be spent from by others (assuming Satoshi's - continued absence) if secp256k1 is broken. Should the Canary coins move, that will signal that reliance on secp256k1 +continued absence) if secp256k1 is broken. Should the Canary coins move, that will signal that reliance on secp256k1 is presently vulnerable. Without the Canary, or an address like it, there may be some doubt as to whether the coins were moved with keys belonging to the original owner. @@ -326,8 +326,7 @@ Following BIP-141, a new transaction serialization format is introduced to inclu The attestation field consists of: -* num_pubkeys: The number of public keys -([https://learnmeabitcoin.com/technical/general/compact-size/ compact size]). +* num_pubkeys: The number of public keys ([https://learnmeabitcoin.com/technical/general/compact-size/ compact size]). For each public key: From 0fdd8c3edc9e563bcf5a7cb0cc93e6f428b948d8 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Fri, 20 Dec 2024 16:12:31 -0700 Subject: [PATCH 028/131] Updates based on Murch and vostrnad feedback. --- bip-0360.mediawiki | 119 +++++++++++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 48 deletions(-) diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki index 6d859cba7e..49cd27a2ff 100644 --- a/bip-0360.mediawiki +++ b/bip-0360.mediawiki @@ -1,6 +1,6 @@
   BIP: 360
-  Title: QuBit: SegWit v3 spending rules (P2QRH)
+  Title: Pay to Quantum Resistant Hash
   Layer: Consensus (soft fork)
   Author: Hunter Beast 
   Comments-Summary: No comments yet.
@@ -29,12 +29,11 @@ The primary threat to Bitcoin from Cryptoanalytically-Relevant Quantum Computers
 the cryptographic assumptions of Elliptic Curve Cryptography (ECC), which secures Bitcoin's signatures and Taproot
 commitments. Specifically, [https://arxiv.org/pdf/quant-ph/0301141 Shor's algorithm] enables a CRQC to solve the
 Discrete Logarithm Problem (DLP) exponentially faster than classical methodsShor's algorithm is
-believed to need 10^8 operations to break a 256-bit elliptic curve public key., allowing the derivation of private
-keys from public keys—a process referred to as quantum key decryption. Importantly, simply increasing the public key
-length (e.g., using a hypothetical secp512k1 curve) would only make deriving the private key twice as hard, offering
-insufficient protection. The computational complexity of this attack is further explored in
-[https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact
-of hardware specifications on reaching quantum advantage in the fault-tolerant regime''].
+believed to need 10^8 operations to break a 256-bit elliptic curve public key., allowing the derivation of
+private keys from public keys—a process referred to as quantum key decryption. Importantly, simply doubling the public
+key length (e.g., using a hypothetical secp512k1 curve) would only make deriving the private key twice as hard,
+offering insufficient protection. The computational complexity of this attack is further explored in
+[https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault-tolerant regime''].
 
 This proposal aims to mitigate these risks by introducing a Pay to Quantum Resistant Hash (P2QRH) output type that
 relies on post-quantum cryptographic (PQC) signature algorithms. By adopting PQC, Bitcoin can enhance its quantum
@@ -44,7 +43,7 @@ The vulnerability of existing Bitcoin addresses is investigated in
 [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-
 and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the
 Bitcoin supply is held within addresses vulnerable to quantum attack. As of the time of writing, that number is now
-closer to 20%. Additionally, cryptographer Pieter Wuille [https://x.com/pwuille/status/1108085284862713856 reasons]
+closer to 20%. Independently, Bitcoin developer Pieter Wuille [https://x.com/pwuille/status/1108085284862713856 reasons]
 even more might be vulnerable.
 
 Ordinarily, when a transaction is signed, the public key is explicitly stated in the input script. This means that the
@@ -72,8 +71,8 @@ As the value being sent increases, so too should the fee in order to commit the
 possible. Once the transaction is mined, it makes useless the public key revealed by spending a UTXO, so long as it is
 never reused.
 
-It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) address type that relies on a PQC signature
-algorithm. This new address type protects transactions submitted to the mempool and helps preserve the free market by
+It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) output type that relies on a PQC signature
+algorithm. This new output type protects transactions submitted to the mempool and helps preserve the free market by
 preventing the need for private, out-of-band mempool transactions.
 
 The following table is intended to inform the average Bitcoin user whether their bitcoin is vulnerable to a long-range
@@ -101,11 +100,13 @@ quantum attack:
 | P2QRH || No || bc1r || bc1r8rt68aze8tek87cnz4ndnvfzk6tk93jv39n4lmpu5a4yw453rcpszsft3z
 |}
 
+Note: Funds are only safe in P2PKH, P2SH, P2WPKH, and P2WSH outputs if they haven't used the address before.
+
 It should be noted that Taproot outputs are vulnerable in that they encode a 32-byte x-only public key, from which a
 full public key can be reconstructed.
 
-If a key is recovered by a CRQC it can also be trivially checked to see if any child keys were produced using an
-unhardened [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32] derivation path.
+Derivation of child keys (whether hardened or not) requires the chain code, so this is only a concern if the attacker
+has access to the extended public key (in which case they can just directly convert it to an extended private key).
 
 ==== Long Range and Short Range Quantum Attacks ====
 
@@ -115,13 +116,12 @@ period of time, giving an attacker ample opportunity to break the cryptography.
 * P2PK outputs (Satoshi's coins, CPU miners, starts with 04)
 * Reused addresses (any type, except P2QRH)
 * Taproot addresses (starts with bc1p)
-* Unhardened BIP-32 HD wallet keys
+* Wallet descriptor extended public keys, commonly known as "xpubs"
 
 Short Range Quantum Attack is an attack that must be executed quickly while a transaction is still in the mempool,
 before it gets mined into a block. This affects:
 
 * Any transaction in the mempool (except for P2QRH)
-* Unhardened BIP-32 HD wallet keys
 
 Short-range attacks require much larger, more expensive CRQCs since they must be executed within the short window
 before a transaction is mined. Long-range attacks can be executed over a longer timeframe since the public key remains
@@ -147,7 +147,7 @@ transition Bitcoin to implement post-quantum security.
 It's for the above reason that, for those who wish to be prepared for quantum emergency, it is recommended that no more
 than 50 bitcoin are kept under a single, distinct, unused Native SegWit (P2WPKH, "bc1q") address at a time. This is
 assuming that the attacker is financially motivated instead of, for example, a nation state looking to break confidence
-in Bitcoin. Additionally, this assumes that other vulnerable targets such as central banks have upgraded their
+in Bitcoin. Independently, this assumes that other vulnerable targets such as central banks have upgraded their
 cryptography by this time.
 
 The Commercial National Security Algorithm Suite (CNSA) 2.0 has a timeline for software and networking equipment to be
@@ -172,9 +172,6 @@ It is proposed to use SegWit version 3. This results in addresses that start wit
 remember that these are quantum (r)esistant addresses. This is referencing the lookup table under
 [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173].
 
-The proposal above also leaves a gap in case it makes sense to use version 2, or bc1z, for implementation of other
-address formats such as those that employ Cross Input Signature Aggregation (CISA).
-
 P2QRH is meant to be implemented on top of P2TR, combining the security of classical Schnorr signatures along with
 post-quantum cryptography. This is a form of hybrid cryptography such that no regression in security is presented
 should a vulnerability exist in one of the signature algorithms used. One key distinction between P2QRH and P2TR
@@ -183,7 +180,9 @@ itself, but it is necessary to avoid exposing public keys on-chain where they ar
 
 P2QRH uses a 32-byte HASH256 (specifically SHA-256 twice-over) of the public key to reduce the size of new outputs and
 also to increase security by not having the public key available on-chain. This hash serves as a minimal cryptographic
-commitment to a public key. It goes into the scriptPubKey, which does not receive the witness discount.
+commitment to a public key in the style of a
+[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#user-content-Witness_program BIP-141 witness program].
+Because it goes into the scriptPubKey, it does not receive a witness or attestation discount.
 
 Post-quantum public keys are generally larger than those used by ECC, depending on the security level. To promote user
 adoption and general user-friendliness, the most secure variant (NIST Level V, 256-bit security) is proposed, despite
@@ -204,22 +203,8 @@ inscriptions would also have the scarcity of their non-monetary assets affected.
 while also increasing the discount is to have a completely separate witness—a "quantum witness." Because it is meant
 only for public keys and signatures, we call this section of the transaction the attestation.
 
-To address the risk of arbitrary data being stored using P2QRH (QuBit) outputs, very specific rules will be applied
-to spending from the witness stack in SegWit v3 outputs. A fixed signature size will be necessary for spending the
-output, and the output must be spendable to be considered valid within node consensus. A fixed signature size will also
-be helpful to disambiguate between signature types without an additional version byte, as SQIsign signatures are
-substantially smaller than FALCON signatures. Consequently, the correct signature algorithm can be inferred through
-byte length. The public key and signature will be pushed separately to the attestation stack. Multiple signatures can
-be included in order to support multisig applications, and also for spending multiple inputs.
-
-Since only valid signatures can be committed to in a SegWit v3 attestation, arbitrary data cannot be added by miners,
-as that would affect the consensus of their block. A CRQC operator is economically disincentivized from computing a
-spendable public key that matched arbitrary signature data due to the cost of that computation. That is because the
-cost of such a computation could prove quite substantial, rather than simply putting the arbitrary data within a
-Taproot witness.
-
-Additionally, it should be noted, whether an output with a P2QRH spend script corresponds to a FALCON or SQIsign
-signature is not known until the output is spent.
+Additionally, it should be noted, whether an output with a P2QRH spend script corresponds to a PQC signature is not
+known until the output is spent.
 
 While it might be seen as a maintenance burden for Bitcoin ecosystem devs to go from a single cryptosystem
 implementation to four additional distinct PQC cryptosystems—and it most certainly is—the ramifications of a chain
@@ -234,10 +219,17 @@ Bitcoin, but their signatures are smaller and might be considered by some to be
 signatures. SQIsign is much smaller; however, it is based on a very novel form of cryptography known as supersingular
 elliptic curve quaternion isogeny, and at the time of writing, is not yet approved by NIST or the broader PQC community.
 
+The inclusion of these four PQC cryptosystems is in the interest of supporting hybrid cryptography, especially for
+high value outputs, such as cold wallets used by exchanges. To improve the viability of the activation client, and
+adoption by wallets and libraries, a library akin to libsecp256k1 will be developed to support the new PQC
+cryptosystems.
+
 In the distant future, following the implementation of the P2QRH output type in a QuBit soft fork, there will likely
-be a need for Pay to Quantum Secure (P2QS) addresses. These will require specialized quantum hardware for signing,
-while still [https://quantum-journal.org/papers/q-2023-01-19-901/ using public keys that are verifiable via classical
-means]. Additional follow-on BIPs will be needed to implement P2QS. However, until specialized quantum cryptography
+be a need for Pay to Quantum Secure (P2QS) addresses. A distinction is made between cryptography that's merely resistant
+to quantum attack, and cryptography that's secured by specialized quantum hardware. P2QRH is resistant to quantum
+attack, while P2QS is quantum secure. These will require specialized quantum hardware for signing, while still
+[https://quantum-journal.org/papers/q-2023-01-19-901/ using public keys that are verifiable via classical means].
+Additional follow-on BIPs will be needed to implement P2QS. However, until specialized quantum cryptography
 hardware is widespread, quantum resistant addresses should be an adequate intermediate solution.
 
 == Specification ==
@@ -256,7 +248,9 @@ its argument. For example:
   qrh(HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ...))
 
 This function allows wallets to manage P2QRH addresses and outputs while accommodating multiple public keys of varying
-lengths, such as in multisig schemes, while keeping the public keys hidden until the time of spending.
+lengths, such as in multisig schemes, while keeping the public keys hidden until the time of spending. At a minimum,
+there should be two public keys in a P2QRH output, one that makes use of classical cryptography and one that makes use
+of a PQC algorithm chosen within the wallet.
 
 === Address Format ===
 
@@ -277,11 +271,32 @@ The scriptPubKey for a P2QRH output is:
 Where:
 
 * OP_PUSHNUM_3 (0x03) indicates SegWit version 3.
-*  is the 32-byte HASH256 of the concatenated HASH256 of each public key.
+*  is the 32-byte HASH256 of the merkle root of a tree of public key hashes, as defined in the
+Hash Computation section.
+
+=== Output Mechanics ===
+
+To address the risk of arbitrary data being stored using P2QRH (QuBit) outputs, very specific rules will be applied
+to spending from the witness stack in SegWit v3 outputs. A fixed signature size will be necessary for spending the
+output, and the output must be spendable to be considered valid within node consensus. A fixed signature size will also
+be helpful to disambiguate between signature types without an additional version byte, as SQIsign signatures are
+substantially smaller than FALCON signatures. Consequently, the correct signature algorithm can be inferred through
+byte length. The public key and signature will be pushed separately to the attestation stack. Multiple signatures can
+be included in order to support multisig applications, and also for spending multiple inputs.
+
+Since only valid signatures can be committed to in a SegWit v3 attestation, arbitrary data cannot be added by miners,
+as that would affect the consensus of their block. A CRQC operator is economically disincentivized from computing a
+spendable public key that matched arbitrary signature data due to the cost of that computation. That is because the
+cost of such a computation could prove quite substantial, rather than simply putting the arbitrary data within a
+Taproot witness.
 
 ==== Hash Computation ====
 
-The hash is computed as a merkle tree of public key hashes:
+If there is only a single public key, the hash is computed as the HASH256 of the public key, as if it were a
+merkle root.
+
+In order to support multiple keys, as in the context of multisig or singlesig hybrid cryptography, the hash is
+computed as a merkle tree of multiple public key hashes:
 
 1. For each public key, compute its HASH256
 2. Pair the hashes and compute HASH256 of their concatenation
@@ -318,10 +333,19 @@ Following BIP-141, a new transaction serialization format is introduced to inclu
 
 * marker: 0x00 (same as SegWit)
 
-* flag: 0x02 (indicates the presence of both witness and attestation data)
+* flag:
+
+** 0x02 (indicates the presence of attestation data only)
+** 0x03 (indicates the presence of both witness and attestation data)
 
 * attestation: Contains the quantum-resistant public keys and signatures.
 
+=== Transaction ID ===
+
+The transaction ID is computed as the HASH256 of the serialized transaction, including the attestation and witness
+(if a witness is present). When decoded, this is called the qtxid, which will differ from the txid and wtxid if an
+attestation is present.
+
 === Attestation Structure ===
 
 The attestation field consists of:
@@ -370,6 +394,9 @@ Supported PQC algorithms and their NIST Level V parameters:
 
 Implementations must reject public keys and signatures that do not match expected lengths for supported algorithms.
 
+If there a new algorithm is added, and one of the byte sizes overlaps, then an additional byte should be prepended to the
+new algorithm's public key length that indicates the specific algorithm used.
+
 === Script Validation ===
 
 To spend a P2QRH output, the following conditions must be met:
@@ -572,8 +599,8 @@ seeds to act as the authoritative secret when signing. These measures are deemed
 
 * [https://groups.google.com/g/bitcoindev/c/Aee8xKuIC2s/m/cu6xej1mBQAJ Mailing list discussion]
 * [https://delvingbitcoin.org/t/proposing-a-p2qrh-bip-towards-a-quantum-resistant-soft-fork/956?u=cryptoquick Delving Bitcoin discussion]
-* [https://bitcoinops.org/en/newsletters/2024/06/14/ Bitcoin OpTech newsletter]
-* [https://bitcoinops.org/en/podcast/2024/06/18/#draft-bip-for-quantum-safe-address-format Bitcoin OpTech discussion transcript]
+* [https://bitcoinops.org/en/newsletters/2024/06/14/ Bitcoin Optech newsletter]
+* [https://bitcoinops.org/en/podcast/2024/06/18/#draft-bip-for-quantum-safe-address-format Bitcoin Optech discussion transcript]
 
 == Footnotes ==
 
@@ -583,13 +610,9 @@ seeds to act as the authoritative secret when signing. These measures are deemed
 
 To help implementors understand updates to this BIP, we keep a list of substantial changes.
 
-* 2024-12-20 - Address feedback from vostrnad.
 * 2024-12-18 - Assigned BIP number.
 * 2024-12-13 - Update to use merkle tree for attestation commitment. Update LR & SR quantum attack scenarios.
-* 2024-12-06 - Update title and formatting.
-* 2024-12-03 - MediaWiki formatting fixes.
 * 2024-12-01 - Add details on attestation structure and parsing.
-* 2024-11-20 - Clarifications based on feedback from Murch. Remove some sections that are not yet ready.
 * 2024-10-21 - Replace XMSS with CRYSTALS-Dilithium due to NIST approval and size constraints.
 * 2024-09-30 - Refactor the ECC vs PoW section. Swap quitness for attestation.
 * 2024-09-29 - Update section on PoW to include partial-preimage.

From 208a987f2fbff9be180df7188ccea8ede558ff98 Mon Sep 17 00:00:00 2001
From: Hunter Trujillo 
Date: Fri, 20 Dec 2024 16:18:44 -0700
Subject: [PATCH 029/131] Fix title change in README.

---
 README.mediawiki | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.mediawiki b/README.mediawiki
index a5eeabd778..b8ea337472 100644
--- a/README.mediawiki
+++ b/README.mediawiki
@@ -1151,7 +1151,7 @@ Those proposing changes should consider that ultimately consent may rest with th
 |-
 | [[bip-0360.mediawiki|360]]
 | Consensus (soft fork)
-| QuBit: SegWit v3 spending rules (P2QRH)
+| Pay to Quantum Resistant Hash
 | Hunter Beast
 | Standard
 | Draft

From 8eb35c89a33c3e5e6b44c72cb905778aa3b23a99 Mon Sep 17 00:00:00 2001
From: Hunter Beast 
Date: Mon, 23 Dec 2024 15:22:54 -0700
Subject: [PATCH 030/131] Apply suggestions from code review

Co-authored-by: Mark "Murch" Erhardt 
---
 bip-0360.mediawiki | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index 49cd27a2ff..57c36dace5 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -85,28 +85,28 @@ quantum attack:
 |-
 | P2PK || Yes || Varies || 2103203b768951584fe9af6d9d9e6ff26a5f76e453212f19ba163774182ab8057f3eac
 |-
-| P2PKH || No || 1 || 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
+| P2PKH || No¹ || 1 || 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
 |-
 | P2MS || Yes || Varies || 52410496ec45f878b62c46c4be8e336dff7cc58df9b502178cc240e...
 |-
-| P2SH || No || 3 || 3FkhZo7sGNue153xhgqPBcUaBsYvJW6tTx
+| P2SH || No¹ || 3 || 3FkhZo7sGNue153xhgqPBcUaBsYvJW6tTx
 |-
-| P2WPKH || No || bc1q || bc1qsnh5ktku9ztqeqfr89yrqjd05eh58nah884mku
+| P2WPKH || No¹ || bc1q || bc1qsnh5ktku9ztqeqfr89yrqjd05eh58nah884mku
 |-
-| P2WSH || No || bc1q || bc1qvhu3557twysq2ldn6dut6rmaj3qk04p60h9l79wk4lzgy0ca8mfsnffz65
+| P2WSH || No¹ || bc1q || bc1qvhu3557twysq2ldn6dut6rmaj3qk04p60h9l79wk4lzgy0ca8mfsnffz65
 |-
 | P2TR || Yes || bc1p || bc1p92aslsnseq786wxfk3ekra90ds9ku47qttupfjsqmmj4z82xdq4q3rr58u
 |-
 | P2QRH || No || bc1r || bc1r8rt68aze8tek87cnz4ndnvfzk6tk93jv39n4lmpu5a4yw453rcpszsft3z
 |}
 
-Note: Funds are only safe in P2PKH, P2SH, P2WPKH, and P2WSH outputs if they haven't used the address before.
+¹ Funds in P2PKH, P2SH, P2WPKH, and P2WSH outputs become vulnerable to long-range quantum attacks when their input script is revealed. An address is no longer safe against long-range quantum attacks after funds from it have been spent.
 
 It should be noted that Taproot outputs are vulnerable in that they encode a 32-byte x-only public key, from which a
 full public key can be reconstructed.
 
-Derivation of child keys (whether hardened or not) requires the chain code, so this is only a concern if the attacker
-has access to the extended public key (in which case they can just directly convert it to an extended private key).
+If an extended public key’s (xPub’s) parent private key of is recovered by CRQC, the attacker also recovers
+the entire extended private key, whether it uses hardened or unhardened derivation.
 
 ==== Long Range and Short Range Quantum Attacks ====
 
@@ -116,7 +116,8 @@ period of time, giving an attacker ample opportunity to break the cryptography.
 * P2PK outputs (Satoshi's coins, CPU miners, starts with 04)
 * Reused addresses (any type, except P2QRH)
 * Taproot addresses (starts with bc1p)
-* Wallet descriptor extended public keys, commonly known as "xpubs"
+* Extended public keys, commonly known as "xpubs"
+* Wallet descriptors
 
 Short Range Quantum Attack is an attack that must be executed quickly while a transaction is still in the mempool,
 before it gets mined into a block. This affects:
@@ -276,8 +277,8 @@ Hash Computation section.
 
 === Output Mechanics ===
 
-To address the risk of arbitrary data being stored using P2QRH (QuBit) outputs, very specific rules will be applied
-to spending from the witness stack in SegWit v3 outputs. A fixed signature size will be necessary for spending the
+To prevent storage of arbitrary data using P2QRH (QuBit) outputs,
+the witness stack for inputs spending segwit v3 outputs is limited to the fixed-size signatures necessary for spending the
 output, and the output must be spendable to be considered valid within node consensus. A fixed signature size will also
 be helpful to disambiguate between signature types without an additional version byte, as SQIsign signatures are
 substantially smaller than FALCON signatures. Consequently, the correct signature algorithm can be inferred through

From d9bb0ffef13e0daf603dcd36bc8dbbf7769f58fc Mon Sep 17 00:00:00 2001
From: Hunter Trujillo 
Date: Mon, 23 Dec 2024 15:26:24 -0700
Subject: [PATCH 031/131] Fix broken link.

---
 bip-0360.mediawiki | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index 57c36dace5..c339ebef4e 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -130,8 +130,8 @@ exposed on the blockchain indefinitely.
 
 Should quantum advantage manifest, a convention is proposed in spending the 65-byte P2PK output used by the coinbase
 output in Block 1. It is proposed to call the address in Block 1 the
-[https://mempool.space/address/0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f81
-41781e62294721166bf621e73a82cbf2342c858ee Canary address] since it can only be spent from by others (assuming Satoshi's
+[https://mempool.space/address/0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee Canary address]
+since it can only be spent from by others (assuming Satoshi's
 continued absence) if secp256k1 is broken. Should the Canary coins move, that will signal that reliance on secp256k1
 is presently vulnerable. Without the Canary, or an address like it, there may be some doubt as to whether the coins were
 moved with keys belonging to the original owner.

From 0ae69db70a4a28f202d441b7131cd5b2169e7afe Mon Sep 17 00:00:00 2001
From: Hunter Trujillo 
Date: Mon, 23 Dec 2024 15:47:26 -0700
Subject: [PATCH 032/131] Remove Canary section.

---
 bip-0360.mediawiki | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index c339ebef4e..143dddf857 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -128,14 +128,6 @@ Short-range attacks require much larger, more expensive CRQCs since they must be
 before a transaction is mined. Long-range attacks can be executed over a longer timeframe since the public key remains
 exposed on the blockchain indefinitely.
 
-Should quantum advantage manifest, a convention is proposed in spending the 65-byte P2PK output used by the coinbase
-output in Block 1. It is proposed to call the address in Block 1 the
-[https://mempool.space/address/0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee Canary address]
-since it can only be spent from by others (assuming Satoshi's
-continued absence) if secp256k1 is broken. Should the Canary coins move, that will signal that reliance on secp256k1
-is presently vulnerable. Without the Canary, or an address like it, there may be some doubt as to whether the coins were
-moved with keys belonging to the original owner.
-
 Coinbase outputs to P2PK keys go as far as block 200,000, so there are, at the time of writing, 1,723,848 coins that
 are vulnerable from the first epoch at the time of writing in P2PK outputs alone. The majority of these have a
 block reward of 50 coins each, and there are roughly 34,000 distinct P2PK scripts that are vulnerable. These coins

From 81e1838061ad358ac7703817b1dfbdaca212ce5b Mon Sep 17 00:00:00 2001
From: Hunter Beast 
Date: Tue, 14 Jan 2025 13:39:44 -0700
Subject: [PATCH 033/131] Apply suggestions from code review

Co-authored-by: Jon Atack 
---
 bip-0360.mediawiki | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index 143dddf857..be76c03f49 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -44,7 +44,7 @@ The vulnerability of existing Bitcoin addresses is investigated in
 and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the
 Bitcoin supply is held within addresses vulnerable to quantum attack. As of the time of writing, that number is now
 closer to 20%. Independently, Bitcoin developer Pieter Wuille [https://x.com/pwuille/status/1108085284862713856 reasons]
-even more might be vulnerable.
+even more addresses might be vulnerable, representing 5M to 10M bitcoin.
 
 Ordinarily, when a transaction is signed, the public key is explicitly stated in the input script. This means that the
 public key is exposed on the blockchain when the transaction is spent, making it vulnerable to quantum attack until
@@ -62,7 +62,7 @@ would be one performed on keys in the mempool, which is seen as much more diffic
 requires more sophisticated CRQCs.
 In the paper
 [https://arxiv.org/pdf/2306.08585 How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates]
-the authors estimate that CRQC with 28 million superconducting physical qubits would take 8.3 seconds to calculate a
+the authors estimate that a CRQC with 28 million superconducting physical qubits would take 8.3 seconds to calculate a
 256-bit key, while a CRQC with 6.9 million physical qubits would take 58 seconds. This implies that a CRQC with 4x as
 many qubits would be roughly 7 times faster.
 
@@ -105,12 +105,12 @@ quantum attack:
 It should be noted that Taproot outputs are vulnerable in that they encode a 32-byte x-only public key, from which a
 full public key can be reconstructed.
 
-If an extended public key’s (xPub’s) parent private key of is recovered by CRQC, the attacker also recovers
+If the parent private key of an extended public key (xpub) is recovered by a CRQC, the attacker also recovers
 the entire extended private key, whether it uses hardened or unhardened derivation.
 
 ==== Long Range and Short Range Quantum Attacks ====
 
-Long Range Quantum Attack is an attack in which the public key has been exposed on the blockchain for an extended
+A Long Range Quantum Attack is an attack in which the public key has been exposed on the blockchain for an extended
 period of time, giving an attacker ample opportunity to break the cryptography. This affects:
 
 * P2PK outputs (Satoshi's coins, CPU miners, starts with 04)
@@ -119,8 +119,8 @@ period of time, giving an attacker ample opportunity to break the cryptography.
 * Extended public keys, commonly known as "xpubs"
 * Wallet descriptors
 
-Short Range Quantum Attack is an attack that must be executed quickly while a transaction is still in the mempool,
-before it gets mined into a block. This affects:
+A Short Range Quantum Attack is an attack that must be executed quickly while a transaction is still in the mempool,
+before it is mined into a block. This affects:
 
 * Any transaction in the mempool (except for P2QRH)
 
@@ -148,7 +148,7 @@ upgraded by 2030, with browsers and operating systems fully upgraded by 2033. Ac
 Cryptography is planned to be disallowed within the US federal government after 2035. An exception is made for hybrid
 cryptography, which is the use of ECC and post-quantum algorithms together.
 
-Although CRQCs could pose a threat to the signatures used in Bitcoin, a smaller threat is to Bitcoin's hash algorithms.
+Although the main threat posed by CRQCs is to the signatures used in Bitcoin, a smaller threat is to Bitcoin's hash algorithms.
 In particular, while a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a
 quadratic speedup on brute-force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is
 needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160 
@@ -242,7 +242,7 @@ its argument. For example:
 
 This function allows wallets to manage P2QRH addresses and outputs while accommodating multiple public keys of varying
 lengths, such as in multisig schemes, while keeping the public keys hidden until the time of spending. At a minimum,
-there should be two public keys in a P2QRH output, one that makes use of classical cryptography and one that makes use
+there should be two public keys in a P2QRH output: one key that makes use of classical cryptography, and one that makes use
 of a PQC algorithm chosen within the wallet.
 
 === Address Format ===
@@ -265,12 +265,12 @@ Where:
 
 * OP_PUSHNUM_3 (0x03) indicates SegWit version 3.
 *  is the 32-byte HASH256 of the merkle root of a tree of public key hashes, as defined in the
-Hash Computation section.
+Hash Computation section below.
 
 === Output Mechanics ===
 
 To prevent storage of arbitrary data using P2QRH (QuBit) outputs,
-the witness stack for inputs spending segwit v3 outputs is limited to the fixed-size signatures necessary for spending the
+the witness stack for inputs spending SegWit v3 outputs is limited to the fixed-size signatures necessary for spending the
 output, and the output must be spendable to be considered valid within node consensus. A fixed signature size will also
 be helpful to disambiguate between signature types without an additional version byte, as SQIsign signatures are
 substantially smaller than FALCON signatures. Consequently, the correct signature algorithm can be inferred through
@@ -387,7 +387,7 @@ Supported PQC algorithms and their NIST Level V parameters:
 
 Implementations must reject public keys and signatures that do not match expected lengths for supported algorithms.
 
-If there a new algorithm is added, and one of the byte sizes overlaps, then an additional byte should be prepended to the
+If a new algorithm is added, and one of the byte sizes overlaps, then an additional byte should be prepended to the
 new algorithm's public key length that indicates the specific algorithm used.
 
 === Script Validation ===
@@ -567,7 +567,7 @@ might be possible to implement Isogeny Schnorr signatures.
 
 Signature verification speed as it compares to Schnorr or ECDSA isn't seen as high a consideration as signature size
 due to block space being the primary fee constraint. As a P2QRH implementation materializes, a benchmark will be added
-for performance comparison. Fortunately, SQIsign signatures are substantially faster to verify than it is to generate
+for performance comparison. Fortunately, SQIsign signatures are substantially faster to verify than they are to generate
 keys or to sign, which is a major consideration when a transaction need only be signed once, or a handful of times with
 PSBT, compared to being verified simultaneously on tens of thousands of nodes. Key generation may need to be cached in
 BIP-32 Hierarchical Deterministic wallets.

From c1b90476556d05c76a93e6b2dce41c3cdb973559 Mon Sep 17 00:00:00 2001
From: Hunter Trujillo 
Date: Tue, 14 Jan 2025 13:59:40 -0700
Subject: [PATCH 034/131] Address suggestions from jonatack's review.

---
 bip-0360.mediawiki | 45 +++++++++++++++++++++++----------------------
 1 file changed, 23 insertions(+), 22 deletions(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index be76c03f49..41c0ed16fe 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -40,11 +40,11 @@ relies on post-quantum cryptographic (PQC) signature algorithms. By adopting PQC
 resistance without requiring a hard fork or block size increase.
 
 The vulnerability of existing Bitcoin addresses is investigated in
-[https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-
-and-the-bitcoin-blockchain.html this Deloitte report]. The report estimates that in 2020 approximately 25% of the
-Bitcoin supply is held within addresses vulnerable to quantum attack. As of the time of writing, that number is now
-closer to 20%. Independently, Bitcoin developer Pieter Wuille [https://x.com/pwuille/status/1108085284862713856 reasons]
-even more addresses might be vulnerable, representing 5M to 10M bitcoin.
+[https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-and-the-bitcoin-blockchain.html this Deloitte report].
+The report estimates that in 2020 approximately 25% of the Bitcoin supply is held within addresses vulnerable to
+quantum attack. As of the time of writing, that number is now closer to 20%. Independently, Bitcoin developer Pieter
+Wuille [https://x.com/pwuille/status/1108085284862713856 reasons] even more addresses might be vulnerable, representing
+5M to 10M bitcoin.
 
 Ordinarily, when a transaction is signed, the public key is explicitly stated in the input script. This means that the
 public key is exposed on the blockchain when the transaction is spent, making it vulnerable to quantum attack until
@@ -79,7 +79,7 @@ The following table is intended to inform the average Bitcoin user whether their
 quantum attack:
 
 {| class="wikitable"
-|+ Vulnerable output types
+|+ Output types vulnerable to long-range attacks on unspent addresses
 |-
 ! Type !! Vulnerable !! Prefix !! Example
 |-
@@ -129,13 +129,11 @@ before a transaction is mined. Long-range attacks can be executed over a longer
 exposed on the blockchain indefinitely.
 
 Coinbase outputs to P2PK keys go as far as block 200,000, so there are, at the time of writing, 1,723,848 coins that
-are vulnerable from the first epoch at the time of writing in P2PK outputs alone. The majority of these have a
-block reward of 50 coins each, and there are roughly 34,000 distinct P2PK scripts that are vulnerable. These coins
-can be
-considered "Satoshi's Shield." Any addresses with a balance of less than the original block subsidy of 50 coins can be
-considered cryptoeconomically incentive incompatible to capture until all of these are mined, and these addresses serve
-to provide time to
-transition Bitcoin to implement post-quantum security.
+are vulnerable from the first epoch in P2PK outputs alone. The majority of these have a block reward of 50 coins each,
+and there are roughly 34,000 distinct P2PK scripts that are vulnerable. These coins can be considered
+"Satoshi's Shield." Any addresses with a balance of less than the original block subsidy of 50 coins can be considered
+cryptoeconomically incentive incompatible to capture until all of these are mined, and these addresses serve to provide
+time to transition Bitcoin to implement post-quantum security.
 
 It's for the above reason that, for those who wish to be prepared for quantum emergency, it is recommended that no more
 than 50 bitcoin are kept under a single, distinct, unused Native SegWit (P2WPKH, "bc1q") address at a time. This is
@@ -148,12 +146,12 @@ upgraded by 2030, with browsers and operating systems fully upgraded by 2033. Ac
 Cryptography is planned to be disallowed within the US federal government after 2035. An exception is made for hybrid
 cryptography, which is the use of ECC and post-quantum algorithms together.
 
-Although the main threat posed by CRQCs is to the signatures used in Bitcoin, a smaller threat is to Bitcoin's hash algorithms.
-In particular, while a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm] to gain a
-quadratic speedup on brute-force attacks on the hash functions used in Bitcoin, a significantly more powerful CRQC is
-needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on HASH160 
-Used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes. using Grover's
-algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see
+Although the main threat posed by CRQCs is to the signatures used in Bitcoin, a smaller threat is to Bitcoin's hash
+algorithms. In particular, while a CRQC could use [https://en.wikipedia.org/wiki/Grover's_algorithm Grover's algorithm]
+to gain a quadratic speedup on brute-force attacks on the hash functions used in Bitcoin, a significantly more powerful
+CRQC is needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on
+HASH160 Used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes.
+using Grover's algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see
 [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques’ post on this].
 
 === Rationale ===
@@ -315,8 +313,9 @@ keys from the transaction while still proving they were part of the original com
 This merkle tree construction creates an efficient cryptographic commitment to multiple public keys while enabling
 selective disclosure.
 
-This allows for inclusion of a Taproot MAST merkle root in the attestation, which makes P2QRH a quantum-resistant
-version of Taproot.
+This allows for inclusion of a [https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki BIP-114] Taproot
+Merkelized Abstract Syntax Tree (MAST) merkle root in the attestation, which makes P2QRH a quantum-resistant
+version of Taproot transactions.
 
 === Transaction Serialization ===
 
@@ -513,7 +512,9 @@ Hash-based cryptography
 |-
 | [https://eprint.iacr.org/2011/191.pdf Winternitz signature] || 1982 || 2,368 bytesWinternitz
 signatures are much smaller than Lamport signatures due to efficient chunking, but computation is much higher,
-especially with high values for w. Winternitz values are for w of 4. || 2,368 bytes || Hash-based cryptography
+especially with high values for w. Winternitz values are for w of 4. It's worth noting that Winternitz signatures can
+only safely be used one time per public key. If addresses are reused, private key information might be leaked, allowing
+attackers to spend future outputs assigned to the same address. || 2,368 bytes || Hash-based cryptography
 |-
 | [https://sphincs.org/data/sphincs+-r3.1-specification.pdf SPHINCS+ Rd. 3.1 (FIPS 205 - SLH-DSA)] || 2015 || 29,792
 bytes || 64 bytes || Hash-based cryptography

From b75003e64bca77c200a244378f1d4540d462309a Mon Sep 17 00:00:00 2001
From: Hunter Trujillo 
Date: Mon, 20 Jan 2025 07:39:22 -0700
Subject: [PATCH 035/131] Remove SQIsign from consideration due to significant
 performance concerns. Refactor language from long-range attack to
 long-exposure so as to not be confused with the language around block re-org
 attacks.

---
 bip-0360.mediawiki | 77 +++++++++++++++++++---------------------------
 1 file changed, 32 insertions(+), 45 deletions(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index 41c0ed16fe..a3640a8b39 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -36,7 +36,7 @@ offering insufficient protection. The computational complexity of this attack is
 [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault-tolerant regime''].
 
 This proposal aims to mitigate these risks by introducing a Pay to Quantum Resistant Hash (P2QRH) output type that
-relies on post-quantum cryptographic (PQC) signature algorithms. By adopting PQC, Bitcoin can enhance its quantum
+relies on PQC signature algorithms. By adopting PQC, Bitcoin can enhance its quantum
 resistance without requiring a hard fork or block size increase.
 
 The vulnerability of existing Bitcoin addresses is investigated in
@@ -54,12 +54,12 @@ not to reveal the transaction public key to attackers. The problem with this app
 third party, which the P2QRH proposal aims to avoid.
 
 Not having public keys exposed on-chain is an important step for quantum security. Otherwise, funds would need to be
-spent to new addresses on a regular basis in order to prevent the possibility of a "long-range CRQC attack" recovering
-the key behind high-value addresses. A long-range quantum attack can be considered one performed with chain data, such
+spent to new addresses on a regular basis in order to prevent the possibility of a "long-exposure CRQC attack" recovering
+the key behind high-value addresses. A long-exposure quantum attack can be considered one performed with chain data, such
 as that from a used address or one encoded in a spend script. This is likely to be more common early on, as early
-quantum computers must be run for longer in order to overcome errors caused by noise. A "short-range quantum attack"
+quantum computers must be run for longer in order to overcome errors caused by noise. A "short-exposure quantum attack"
 would be one performed on keys in the mempool, which is seen as much more difficult given the block time, and so it
-requires more sophisticated CRQCs.
+requires more sophisticated CRQCs.
 In the paper
 [https://arxiv.org/pdf/2306.08585 How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates]
 the authors estimate that a CRQC with 28 million superconducting physical qubits would take 8.3 seconds to calculate a
@@ -75,11 +75,11 @@ It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) output type
 algorithm. This new output type protects transactions submitted to the mempool and helps preserve the free market by
 preventing the need for private, out-of-band mempool transactions.
 
-The following table is intended to inform the average Bitcoin user whether their bitcoin is vulnerable to a long-range
+The following table is intended to inform the average Bitcoin user whether their bitcoin is vulnerable to a long-exposure
 quantum attack:
 
 {| class="wikitable"
-|+ Output types vulnerable to long-range attacks on unspent addresses
+|+ Output types vulnerable to long-exposure attacks on unspent addresses
 |-
 ! Type !! Vulnerable !! Prefix !! Example
 |-
@@ -100,7 +100,7 @@ quantum attack:
 | P2QRH || No || bc1r || bc1r8rt68aze8tek87cnz4ndnvfzk6tk93jv39n4lmpu5a4yw453rcpszsft3z
 |}
 
-¹ Funds in P2PKH, P2SH, P2WPKH, and P2WSH outputs become vulnerable to long-range quantum attacks when their input script is revealed. An address is no longer safe against long-range quantum attacks after funds from it have been spent.
+¹ Funds in P2PKH, P2SH, P2WPKH, and P2WSH outputs become vulnerable to long-exposure quantum attacks when their input script is revealed. An address is no longer safe against long-exposure quantum attacks after funds from it have been spent.
 
 It should be noted that Taproot outputs are vulnerable in that they encode a 32-byte x-only public key, from which a
 full public key can be reconstructed.
@@ -108,9 +108,9 @@ full public key can be reconstructed.
 If the parent private key of an extended public key (xpub) is recovered by a CRQC, the attacker also recovers
 the entire extended private key, whether it uses hardened or unhardened derivation.
 
-==== Long Range and Short Range Quantum Attacks ====
+==== Long Exposure and Short Exposure Quantum Attacks ====
 
-A Long Range Quantum Attack is an attack in which the public key has been exposed on the blockchain for an extended
+A Long Exposure Quantum Attack is an attack in which the public key has been exposed on the blockchain for an extended
 period of time, giving an attacker ample opportunity to break the cryptography. This affects:
 
 * P2PK outputs (Satoshi's coins, CPU miners, starts with 04)
@@ -119,13 +119,13 @@ period of time, giving an attacker ample opportunity to break the cryptography.
 * Extended public keys, commonly known as "xpubs"
 * Wallet descriptors
 
-A Short Range Quantum Attack is an attack that must be executed quickly while a transaction is still in the mempool,
+A Short Exposure Quantum Attack is an attack that must be executed quickly while a transaction is still in the mempool,
 before it is mined into a block. This affects:
 
 * Any transaction in the mempool (except for P2QRH)
 
-Short-range attacks require much larger, more expensive CRQCs since they must be executed within the short window
-before a transaction is mined. Long-range attacks can be executed over a longer timeframe since the public key remains
+Short-exposure attacks require much larger, more expensive CRQCs since they must be executed within the short window
+before a transaction is mined. Long-exposure attacks can be executed over a longer timeframe since the public key remains
 exposed on the blockchain indefinitely.
 
 Coinbase outputs to P2PK keys go as far as block 200,000, so there are, at the time of writing, 1,723,848 coins that
@@ -179,13 +179,12 @@ Post-quantum public keys are generally larger than those used by ECC, depending
 adoption and general user-friendliness, the most secure variant (NIST Level V, 256-bit security) is proposed, despite
 the increase in key length and verification time.
 
-Support for FALCON signatures will be introduced first, with the intention of adding SQIsign and other post-quantum
-algorithms as they are approved. By way of comparison, FALCON signatures are roughly 4x larger than SQIsign signatures
-and 20x larger than Schnorr signatures. FALCON is a more conservative approach to applied lattice cryptography than
-SQIsign, and its use has recently been approved by NIST. NIST approval streamlines implementations through establishing
-consensus in the scientific and developer community. However, even SQIsign signatures are roughly 5x larger than
-Schnorr signatures. This means, to maintain present transaction throughput, an increase in the witness discount will
-likely be desired in a QuBit soft fork. That will be specified in a future QuBit BIP.
+Support for FALCON signatures will be introduced first, with the intention of adding other post-quantum
+algorithms as they are approved. By way of comparison, FALCON signatures are roughly 20x larger than Schnorr signatures.
+FALCON has recently been approved by NIST. NIST approval streamlines implementations through establishing
+consensus in the scientific and developer community. This means, to maintain present transaction throughput, an
+increase in the witness discount will likely be desired in a QuBit soft fork. That will be specified in a future QuBit
+BIP.
 
 An increase in the witness discount must not be taken lightly. It must be resistant to applications that might take
 advantage of this discount (e.g., storage of arbitrary data as seen with "inscriptions") without a corresponding
@@ -203,17 +202,16 @@ broken through extrinsic factors should provide sufficient motivation. An increa
 signatures are used should be seen as an acceptable compromise for maintained integrity of Bitcoin transfers during a
 regime of quantum advantage.
 
-The inclusion of these four cryptosystems: SPHINCS+, CRYSTALS-Dilithium, FALCON, and SQIsign have various advocates
+The inclusion of these three cryptosystems: SPHINCS+, CRYSTALS-Dilithium, and FALCON have various advocates
 within the community due to their varying security assumptions. Hash-based cryptosystems are more conservative,
 time-tested, and well-reviewed. Lattice cryptography is relatively new and introduces novel security assumptions to
 Bitcoin, but their signatures are smaller and might be considered by some to be an adequate alternative to hash-based
-signatures. SQIsign is much smaller; however, it is based on a very novel form of cryptography known as supersingular
-elliptic curve quaternion isogeny, and at the time of writing, is not yet approved by NIST or the broader PQC community.
+signatures.
 
-The inclusion of these four PQC cryptosystems is in the interest of supporting hybrid cryptography, especially for
+The reason multiple cryptosystems are included is in the interest of supporting hybrid cryptography, especially for
 high value outputs, such as cold wallets used by exchanges. To improve the viability of the activation client, and
 adoption by wallets and libraries, a library akin to libsecp256k1 will be developed to support the new PQC
-cryptosystems.
+cryptosystems, called libbitcoinpqc.
 
 In the distant future, following the implementation of the P2QRH output type in a QuBit soft fork, there will likely
 be a need for Pay to Quantum Secure (P2QS) addresses. A distinction is made between cryptography that's merely resistant
@@ -270,10 +268,10 @@ Hash Computation section below.
 To prevent storage of arbitrary data using P2QRH (QuBit) outputs,
 the witness stack for inputs spending SegWit v3 outputs is limited to the fixed-size signatures necessary for spending the
 output, and the output must be spendable to be considered valid within node consensus. A fixed signature size will also
-be helpful to disambiguate between signature types without an additional version byte, as SQIsign signatures are
-substantially smaller than FALCON signatures. Consequently, the correct signature algorithm can be inferred through
-byte length. The public key and signature will be pushed separately to the attestation stack. Multiple signatures can
-be included in order to support multisig applications, and also for spending multiple inputs.
+be helpful to disambiguate between signature types without an additional version byte. Consequently, the correct
+signature algorithm can be inferred through byte length. The public key and signature will be pushed separately to the
+attestation stack. Multiple signatures can be included in order to support multisig applications, and also for spending
+multiple inputs.
 
 Since only valid signatures can be committed to in a SegWit v3 attestation, arbitrary data cannot be added by miners,
 as that would affect the consensus of their block. A CRQC operator is economically disincentivized from computing a
@@ -380,9 +378,6 @@ Supported PQC algorithms and their NIST Level V parameters:
 * '''FALCON-1024:'''
   * Public Key Length: 1,793 bytes
   * Signature Length: 1,280 bytes
-* '''SQIsign NIST-V:'''
-  * Public Key Length: 128 bytes
-  * Signature Length: 335 bytes
 
 Implementations must reject public keys and signatures that do not match expected lengths for supported algorithms.
 
@@ -546,9 +541,9 @@ Supersingular Elliptic Curve Isogeny
 
 As shown, supersingular elliptic curve quaternion isogeny signature algorithms represent the state of the art in
 post-quantum cryptography, beyond lattice cryptography alone, especially when key and signature length are major
-constraints. This makes inclusion of SQIsign attractive, and support is planned, but it will be some time until it is
-approved for production use. Meanwhile, SPHINCS+ and CRYSTALS-Dilithium signatures are already approved and have
-achieved broader community consensus. FALCON signatures are also NIST approved.
+constraints. This makes inclusion of SQIsign attractive, however its performance is roughly 100,000 slower than ECC,
+which is prohibitive in blockchain contexts. Meanwhile, SPHINCS+ and CRYSTALS-Dilithium signatures are already approved
+and have achieved broader community consensus. FALCON signatures are also NIST approved.
 
 In comparison, the size of currently used signature algorithms are:
 
@@ -560,18 +555,9 @@ In comparison to inception date, secp256k1 [https://www.secg.org/SEC1-Ver-1.0.pd
 One consideration for choosing an algorithm is its maturity. secp256k1 was already 8 years old by the time it was
 chosen as Bitcoin's curve. Isogeny cryptography when it was first introduced was broken over a weekend.
 
-Ideally SQIsign also proves to be flexible enough to support
-[https://www.pierrickdartois.fr/homepage/wp-content/uploads/2022/04/Report_OSIDH_DARTOIS.pdf Isogeny Diffie-Hellman] to
-replace ECDH applications, and also provide methods for the key tweaking necessary to support TapScript for P2QR
-outputs. Additionally, isogeny-based post-quantum cryptography is based on higher-order elliptic curves, and so it
-might be possible to implement Isogeny Schnorr signatures.
-
 Signature verification speed as it compares to Schnorr or ECDSA isn't seen as high a consideration as signature size
 due to block space being the primary fee constraint. As a P2QRH implementation materializes, a benchmark will be added
-for performance comparison. Fortunately, SQIsign signatures are substantially faster to verify than they are to generate
-keys or to sign, which is a major consideration when a transaction need only be signed once, or a handful of times with
-PSBT, compared to being verified simultaneously on tens of thousands of nodes. Key generation may need to be cached in
-BIP-32 Hierarchical Deterministic wallets.
+for performance comparison.
 
 An additional consideration is security level. Longer signature sizes provide more security. NIST has standardized five
 security levels for post-quantum cryptography. NIST security level I provides security equivalent to 128-bit keys, and
@@ -604,6 +590,7 @@ seeds to act as the authoritative secret when signing. These measures are deemed
 
 To help implementors understand updates to this BIP, we keep a list of substantial changes.
 
+* 2025-01-20 - Remove SQIsign from consideration due to significant performance concerns. Refactor language from long-range attack to long-exposure so as to not be confused with the language around block re-org attacks.
 * 2024-12-18 - Assigned BIP number.
 * 2024-12-13 - Update to use merkle tree for attestation commitment. Update LR & SR quantum attack scenarios.
 * 2024-12-01 - Add details on attestation structure and parsing.

From 5e568e3141b423139518537a30b857125abf417e Mon Sep 17 00:00:00 2001
From: Hunter Trujillo 
Date: Thu, 23 Jan 2025 13:49:14 -0700
Subject: [PATCH 036/131] Fix typo.

---
 bip-0360.mediawiki | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index a3640a8b39..1d84a1c666 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -541,7 +541,7 @@ Supersingular Elliptic Curve Isogeny
 
 As shown, supersingular elliptic curve quaternion isogeny signature algorithms represent the state of the art in
 post-quantum cryptography, beyond lattice cryptography alone, especially when key and signature length are major
-constraints. This makes inclusion of SQIsign attractive, however its performance is roughly 100,000 slower than ECC,
+constraints. This makes inclusion of SQIsign attractive, however its performance is roughly 100,000 times slower than ECC,
 which is prohibitive in blockchain contexts. Meanwhile, SPHINCS+ and CRYSTALS-Dilithium signatures are already approved
 and have achieved broader community consensus. FALCON signatures are also NIST approved.
 

From 8c0f7982932e180a32539120445a629077072b40 Mon Sep 17 00:00:00 2001
From: Hunter Trujillo 
Date: Thu, 23 Jan 2025 14:14:47 -0700
Subject: [PATCH 037/131] Fix typo.

---
 bip-0360.mediawiki | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index 1d84a1c666..29694f6eaa 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -312,7 +312,7 @@ This merkle tree construction creates an efficient cryptographic commitment to m
 selective disclosure.
 
 This allows for inclusion of a [https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki BIP-114] Taproot
-Merkelized Abstract Syntax Tree (MAST) merkle root in the attestation, which makes P2QRH a quantum-resistant
+Merkelized Alternative Script Tree (MAST) merkle root in the attestation, which makes P2QRH a quantum-resistant
 version of Taproot transactions.
 
 === Transaction Serialization ===

From 32c0a3d81645e63e59305f280186bb192869c3e8 Mon Sep 17 00:00:00 2001
From: Hunter Trujillo 
Date: Sun, 23 Feb 2025 14:38:21 -0700
Subject: [PATCH 038/131] Updates based on Antoine Riard's feedback and others.

---
 bip-0360.mediawiki | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index 29694f6eaa..1a818ff79d 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -25,8 +25,9 @@ This document is licensed under the 3-clause BSD license.
 
 === Motivation ===
 
-The primary threat to Bitcoin from Cryptoanalytically-Relevant Quantum Computers (CRQCs) is their potential to break
-the cryptographic assumptions of Elliptic Curve Cryptography (ECC), which secures Bitcoin's signatures and Taproot
+The primary threat to Bitcoin from Cryptoanalytically-Relevant Quantum Computers (CRQCs)
+A Cryptoanalytically-Relevant Quantum Computer is an ''object'' which is only loosely defined by ''characteristics'' in quantum physics as of today. It could be understood in the context of this BIP and in bitcoin that it's a ''hardware-agnostic'' computer supposed to have the architecture to keep ''coherent'' a sufficient number of logical qubits to be able to run the Shor algorithm in an efficient fashion.
+is their potential to break the cryptographic assumptions of Elliptic Curve Cryptography (ECC), which secures Bitcoin's signatures and Taproot
 commitments. Specifically, [https://arxiv.org/pdf/quant-ph/0301141 Shor's algorithm] enables a CRQC to solve the
 Discrete Logarithm Problem (DLP) exponentially faster than classical methodsShor's algorithm is
 believed to need 10^8 operations to break a 256-bit elliptic curve public key., allowing the derivation of
@@ -39,11 +40,14 @@ This proposal aims to mitigate these risks by introducing a Pay to Quantum Resis
 relies on PQC signature algorithms. By adopting PQC, Bitcoin can enhance its quantum
 resistance without requiring a hard fork or block size increase.
 
-The vulnerability of existing Bitcoin addresses is investigated in
+The vulnerability of existing Bitcoin addressesA vulnerable Bitcoin address is any
+''scriptPubKey'' type that exposes an elliptic curve public key as ''raw bytes'' in a ''block'', making it susceptible
+to private key derivation through Shor's algorithm. This includes P2PK outputs and any script that contains an
+unprotected public key. is detailed in
 [https://web.archive.org/web/20240715101040/https://www2.deloitte.com/nl/nl/pages/innovatie/artikelen/quantum-computers-and-the-bitcoin-blockchain.html this Deloitte report].
 The report estimates that in 2020 approximately 25% of the Bitcoin supply is held within addresses vulnerable to
 quantum attack. As of the time of writing, that number is now closer to 20%. Independently, Bitcoin developer Pieter
-Wuille [https://x.com/pwuille/status/1108085284862713856 reasons] even more addresses might be vulnerable, representing
+Wuille [https://web.archive.org/web/20220531184542/https://twitter.com/pwuille/status/1108085284862713856 reasons] even more addresses might be vulnerable, representing
 5M to 10M bitcoin.
 
 Ordinarily, when a transaction is signed, the public key is explicitly stated in the input script. This means that the
@@ -51,7 +55,9 @@ public key is exposed on the blockchain when the transaction is spent, making it
 it's mined. One way to mitigate this is to submit the transaction directly to a mining pool, bypassing the mempool.
 This process is known as an out-of-band transaction or a private mempool. In this case, the mining pool must be trusted
 not to reveal the transaction public key to attackers. The problem with this approach is that it requires a trusted
-third party, which the P2QRH proposal aims to avoid.
+third party, which the P2QRH proposal aims to avoid. It also doesn't account for block reorg attacks, which would
+reveal public keys in blocks that were once mined but are now orphaned and must be mined again. Additionally,
+it depends on the mining pool whether they reveal their block template to either the public or to miners.
 
 Not having public keys exposed on-chain is an important step for quantum security. Otherwise, funds would need to be
 spent to new addresses on a regular basis in order to prevent the possibility of a "long-exposure CRQC attack" recovering
@@ -260,8 +266,7 @@ The scriptPubKey for a P2QRH output is:
 Where:
 
 * OP_PUSHNUM_3 (0x03) indicates SegWit version 3.
-*  is the 32-byte HASH256 of the merkle root of a tree of public key hashes, as defined in the
-Hash Computation section below.
+*  is the 32-byte HASH256 of the merkle root of a tree of public key hashes, as defined in the Hash Computation section below.
 
 === Output Mechanics ===
 
@@ -362,7 +367,7 @@ quantum-resistant algorithms.
 For each input, a separate attestation field is used. To know how many attestation fields are present, implementations
 must count the number of inputs present in the transaction.
 
-=== Signature Algorithm Identification ===
+=== Signature Algorithms ===
 
 The specific quantum-resistant signature algorithm used is inferred from the length of the public key.
 Implementations must recognize the supported algorithms and validate accordingly.
@@ -590,6 +595,7 @@ seeds to act as the authoritative secret when signing. These measures are deemed
 
 To help implementors understand updates to this BIP, we keep a list of substantial changes.
 
+* 2025-02-23 - More points of clarification from review. Update dead link.
 * 2025-01-20 - Remove SQIsign from consideration due to significant performance concerns. Refactor language from long-range attack to long-exposure so as to not be confused with the language around block re-org attacks.
 * 2024-12-18 - Assigned BIP number.
 * 2024-12-13 - Update to use merkle tree for attestation commitment. Update LR & SR quantum attack scenarios.

From 913cf797221a8393bffc4e5bb091381a0daaab63 Mon Sep 17 00:00:00 2001
From: Hunter Beast 
Date: Mon, 24 Feb 2025 09:54:11 -0700
Subject: [PATCH 039/131] Apply suggestions from jonasnick code review

Co-authored-by: Jonas Nick 
---
 bip-0360.mediawiki | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index 1a818ff79d..73b1add9f2 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -203,7 +203,7 @@ Additionally, it should be noted, whether an output with a P2QRH spend script co
 known until the output is spent.
 
 While it might be seen as a maintenance burden for Bitcoin ecosystem devs to go from a single cryptosystem
-implementation to four additional distinct PQC cryptosystems—and it most certainly is—the ramifications of a chain
+implementation to three additional distinct PQC cryptosystems—and it most certainly is—the ramifications of a chain
 broken through extrinsic factors should provide sufficient motivation. An increase in software maintenance everywhere
 signatures are used should be seen as an acceptable compromise for maintained integrity of Bitcoin transfers during a
 regime of quantum advantage.
@@ -490,7 +490,7 @@ key generation.
 
 ==== Algorithm Selection ====
 
-Introducing four quantum-resistant algorithms to the Bitcoin ecosystem provides users with the option to select an
+Introducing three quantum-resistant algorithms to the Bitcoin ecosystem provides users with the option to select an
 appropriate algorithm for their use case, generally based on the amount of value they wish to secure. Developers can
 choose to implement support for multiple algorithms in wallets and on nodes to offer quantum-resistant options.
 

From 5a1459bb179acc259db41fc6d7965f830f22e147 Mon Sep 17 00:00:00 2001
From: Hunter Trujillo 
Date: Mon, 24 Feb 2025 10:40:21 -0700
Subject: [PATCH 040/131] Updates based on Jonas Nick's feedback.

---
 bip-0360.mediawiki | 36 ++++++++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index 73b1add9f2..c3dfe5f2a8 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -31,7 +31,9 @@ is their potential to break the cryptographic assumptions of Elliptic Curve Cryp
 commitments. Specifically, [https://arxiv.org/pdf/quant-ph/0301141 Shor's algorithm] enables a CRQC to solve the
 Discrete Logarithm Problem (DLP) exponentially faster than classical methodsShor's algorithm is
 believed to need 10^8 operations to break a 256-bit elliptic curve public key., allowing the derivation of
-private keys from public keys—a process referred to as quantum key decryption. Importantly, simply doubling the public
+private keys from public keys-- a process referred to here as quantum key decryption.
+Meaning, deriving private keys from public keys via Shor's algorithm
+Importantly, simply doubling the public
 key length (e.g., using a hypothetical secp512k1 curve) would only make deriving the private key twice as hard,
 offering insufficient protection. The computational complexity of this attack is further explored in
 [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault-tolerant regime''].
@@ -111,8 +113,13 @@ quantum attack:
 It should be noted that Taproot outputs are vulnerable in that they encode a 32-byte x-only public key, from which a
 full public key can be reconstructed.
 
-If the parent private key of an extended public key (xpub) is recovered by a CRQC, the attacker also recovers
-the entire extended private key, whether it uses hardened or unhardened derivation.
+If a CRQC recovers an extended public key (xpub), including its chain code, it can derive all non-hardened child public
+keys by guessing or iterating through child indexes, as allowed by BIP-32's non-hardened derivation. With Shor's
+algorithm, the CRQC could then compute the corresponding non-hardened child private keys directly from those public keys,
+without needing the extended private key (xprv) or an exposed child private key. Hardened child keys remain secure since
+they cannot be derived from the xpub alone. However, if the xprv is exposed, then all child private keys--both hardened
+and non-hardened--become vulnerable. Thus, in a quantum context, the xpub alone is sufficient to expose all non-hardened
+child private keys.
 
 ==== Long Exposure and Short Exposure Quantum Attacks ====
 
@@ -176,7 +183,11 @@ however is that P2QRH will encode a hash of the public key. This is a significan
 itself, but it is necessary to avoid exposing public keys on-chain where they are vulnerable to attack.
 
 P2QRH uses a 32-byte HASH256 (specifically SHA-256 twice-over) of the public key to reduce the size of new outputs and
-also to increase security by not having the public key available on-chain. This hash serves as a minimal cryptographic
+also to increase security by not having the public key available on-chain. While HASH256 uses double SHA-256 like
+Bitcoin's Proof of Work, this does not meaningfully increase quantum resistance compared to single SHA-256, as both
+provide approximately 2^128 security against Grover's algorithm. The practical impact of quantum attacks on SHA-256
+remains theoretical since quantum circuits for SHA-256 are still theoretical, but using the same hash function as
+Proof of Work maintains consistency with Bitcoin's existing security model. This hash serves as a minimal cryptographic
 commitment to a public key in the style of a
 [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#user-content-Witness_program BIP-141 witness program].
 Because it goes into the scriptPubKey, it does not receive a witness or attestation discount.
@@ -196,14 +207,14 @@ An increase in the witness discount must not be taken lightly. It must be resist
 advantage of this discount (e.g., storage of arbitrary data as seen with "inscriptions") without a corresponding
 increase in economic activity. An increase in the witness discount would not only impact node runners but those with
 inscriptions would also have the scarcity of their non-monetary assets affected. The only way to prevent these effects
-while also increasing the discount is to have a completely separate witness—a "quantum witness." Because it is meant
+while also increasing the discount is to have a completely separate witness--a "quantum witness." Because it is meant
 only for public keys and signatures, we call this section of the transaction the attestation.
 
 Additionally, it should be noted, whether an output with a P2QRH spend script corresponds to a PQC signature is not
 known until the output is spent.
 
 While it might be seen as a maintenance burden for Bitcoin ecosystem devs to go from a single cryptosystem
-implementation to three additional distinct PQC cryptosystems—and it most certainly is—the ramifications of a chain
+implementation to three additional distinct PQC cryptosystems--and it most certainly is--the ramifications of a chain
 broken through extrinsic factors should provide sufficient motivation. An increase in software maintenance everywhere
 signatures are used should be seen as an acceptable compromise for maintained integrity of Bitcoin transfers during a
 regime of quantum advantage.
@@ -224,8 +235,17 @@ be a need for Pay to Quantum Secure (P2QS) addresses. A distinction is made betw
 to quantum attack, and cryptography that's secured by specialized quantum hardware. P2QRH is resistant to quantum
 attack, while P2QS is quantum secure. These will require specialized quantum hardware for signing, while still
 [https://quantum-journal.org/papers/q-2023-01-19-901/ using public keys that are verifiable via classical means].
-Additional follow-on BIPs will be needed to implement P2QS. However, until specialized quantum cryptography
-hardware is widespread, quantum resistant addresses should be an adequate intermediate solution.
+
+While P2QRH lacks features like signature aggregation for smaller transactions, it offers a pragmatic first step
+toward quantum resistance. Future BIPs can add enhancements like P2QS, signature aggregation, and possibly full
+BIP-32 compatibility once tested and viable. Until quantum cryptography hardware and advanced schemes are widespread,
+P2QRH provides meaningful protection against quantum threats without delaying deployment for a perfect solution.
+
+Additional follow-on BIPs will be needed to implement P2QS, signature aggregation, and full BIP-32 compatibility
+(if possible) BIP-32 relies on elliptic curve operations to derive keys from xpubs to support
+watch-only wallets, which PQC schemes may not support.. However, until specialized quantum cryptography hardware
+is widespread and signature aggregation schemes are thoroughly vetted, P2QRH addresses should be an adequate
+intermediate solution that provides meaningful protection against quantum threats.
 
 == Specification ==
 

From 48eaf8f84a6e6495628021703a07f0c22e0f4c99 Mon Sep 17 00:00:00 2001
From: Hunter Beast 
Date: Thu, 13 Mar 2025 09:55:00 -0600
Subject: [PATCH 041/131] Updates - 2025/03/12 (#19)

- [x] Add verification times
- [x] 256 -> 128 (NIST V -> NIST I)
- [x] Multisig threshold and bitmask bytes
- [x] Bitmask for all four signature types
- [x] Taproot compatibility
---
 bip-0360.mediawiki | 177 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 127 insertions(+), 50 deletions(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index c3dfe5f2a8..554277bd3e 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -165,7 +165,7 @@ to gain a quadratic speedup on brute-force attacks on the hash functions used in
 CRQC is needed for these attacks to meaningfully impact Bitcoin. For instance, a preimage attack on
 HASH160 Used by P2PKH, P2SH, and P2WPKH addresses, though not P2WSH because it uses 256-bit hashes.
 using Grover's algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see
-[https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques’ post on this].
+[https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques' post on this].
 
 === Rationale ===
 
@@ -192,9 +192,10 @@ commitment to a public key in the style of a
 [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#user-content-Witness_program BIP-141 witness program].
 Because it goes into the scriptPubKey, it does not receive a witness or attestation discount.
 
-Post-quantum public keys are generally larger than those used by ECC, depending on the security level. To promote user
-adoption and general user-friendliness, the most secure variant (NIST Level V, 256-bit security) is proposed, despite
-the increase in key length and verification time.
+Post-quantum public keys are generally larger than those used by ECC, depending on the security level.
+Originally BIP-360 proposed NIST Level V, 256-bit security, but this was changed to NIST Level I, 128-bit security
+due to concerns over the size of the public keys, the time it would take to verify signatures, and being generally
+deemed "overkill".
 
 Support for FALCON signatures will be introduced first, with the intention of adding other post-quantum
 algorithms as they are approved. By way of comparison, FALCON signatures are roughly 20x larger than Schnorr signatures.
@@ -226,9 +227,9 @@ Bitcoin, but their signatures are smaller and might be considered by some to be
 signatures.
 
 The reason multiple cryptosystems are included is in the interest of supporting hybrid cryptography, especially for
-high value outputs, such as cold wallets used by exchanges. To improve the viability of the activation client, and
-adoption by wallets and libraries, a library akin to libsecp256k1 will be developed to support the new PQC
-cryptosystems, called libbitcoinpqc.
+high value outputs, such as cold wallets used by exchanges. To improve the viability of the activation client and
+adoption by wallets and libraries, a library akin to libsecp256k1 will be developed. This library, libbitcoinpqc,
+will support the new PQC cryptosystems and can be used as a reference for other language-native implementations.
 
 In the distant future, following the implementation of the P2QRH output type in a QuBit soft fork, there will likely
 be a need for Pay to Quantum Secure (P2QS) addresses. A distinction is made between cryptography that's merely resistant
@@ -304,18 +305,37 @@ spendable public key that matched arbitrary signature data due to the cost of th
 cost of such a computation could prove quite substantial, rather than simply putting the arbitrary data within a
 Taproot witness.
 
-==== Hash Computation ====
+==== Key Type Bitmask ====
 
-If there is only a single public key, the hash is computed as the HASH256 of the public key, as if it were a
-merkle root.
+The key type bitmask is a 1-byte value that indicates the type of key used in the commitment. It is encoded as follows:
+
+* 0x01 - Key type 0 - secp256k1
+* 0x02 - Key type 1 - FALCON-512
+* 0x04 - Key type 2 - CRYSTALS-Dilithium Level I
+* 0x08 - Key type 3 - SPHINCS+-128s
+* 0x10 - Unused
+* 0x20 - Unused
+* 0x40 - Unused
+* 0x80 - Reserved for if additional key types are added in the future
+
+Example key type bitmask using all supported key types:
+
+0x01 | 0x02 | 0x04 | 0x08 = 0x0F
+
+==== Hash Commitment ====
+
+If there is only a single public key, the hash is computed as the HASH256 of the public key, as a commitment to the
+merkle root of a binary tree of public key hashes.
 
 In order to support multiple keys, as in the context of multisig or singlesig hybrid cryptography, the hash is
-computed as a merkle tree of multiple public key hashes:
+computed as a sparse merkle tree of multiple public key hashes:
 
 1. For each public key, compute its HASH256
 2. Pair the hashes and compute HASH256 of their concatenation
 3. Continue pairing and hashing until reaching a single root hash
-4. The final hash is the merkle root
+4. Compute the merkle root
+5. Prepend key type bitmask and threshold to the root hash
+6. Compute the HASH256 of the result
 
 For example with 4 public keys:
 
@@ -329,17 +349,47 @@ For example with 4 public keys:
 
   root = HASH256(h12 || h34)
 
+  commitment = key_type_bitmask || threshold || root
+
+  hash = HASH256(commitment)
+
 When spending, if a public key hash is provided in the attestation with an empty signature, that hash will be used
-directly in the merkle tree computation rather than hashing the full public key. This allows excluding unused public
-keys from the transaction while still proving they were part of the original commitment.
+directly in the merkle tree computation rather than hashing the full public key. This allows unused public keys to be
+excluded from the transaction while still proving they were part of the original commitment.
 
-This merkle tree construction creates an efficient cryptographic commitment to multiple public keys while enabling
+The merkle tree construction creates an efficient cryptographic commitment to multiple public keys while enabling
 selective disclosure.
 
-This allows for inclusion of a [https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki BIP-114] Taproot
+A threshold is provided to indicate the number of signatures required to spend the output. This is used in the
+cryptographic commitment in the merkle tree hash computation and revealed in the attestation when spent.
+
+Only a single 32-byte X-only secp256k1 public key can be provided as key type 0. There are a few reasons for this:
+
+1. It maintains Taproot compatibility by removing ambiguity which key is representative of the Taptree.
+2. It prevents abuse of public keys to store arbitrary data once quantum computing is ubiquitous.
+3. When a secp256k1 key is specified in the key type bitmask, how many keys it commits to is unambiguous.
+4. If multiple keys need to be committed to, they must be aggregated, which saves on transaction size.
+
+This design maintains compatibility for [https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki BIP-114] Taproot
 Merkelized Alternative Script Tree (MAST) merkle root in the attestation, which makes P2QRH a quantum-resistant
 version of Taproot transactions.
 
+In a multisig context, aside from secp256k1 keys, the number of keys provided in the attestation is variable and must
+meet the threshold as committed to in the merkle tree hash computation and revealed in the attestation.
+
+If an implementation for public key or signature aggregation for PQC algorithms is developed, key and signature
+aggregation must become the default behavior for P2QRH.
+
+When the address is generated, all public keys must be known in advance, and they must be sorted, first by key type,
+then by public key value, so as to be deterministic.
+
+The key count does not need to be provided for PQC keys because the key type bitmask and threshold are sufficient to
+validate a multisig transaction.
+
+In a singlesig context, multiple PQC keys can be provided, but the key type bitmask and threshold must still also be
+provided to be consistent with the multisig semantics. The threshold will be set as 0x01, and the key type bitmask will
+indicate how many keys of each type are present.
+
 === Transaction Serialization ===
 
 Following BIP-141, a new transaction serialization format is introduced to include an attestation field after the witness field:
@@ -347,15 +397,12 @@ Following BIP-141, a new transaction serialization format is introduced to inclu
   [nVersion][marker][flag][txins][txouts][witness][attestation][nLockTime]
 
 * marker: 0x00 (same as SegWit)
-
 * flag:
-
 ** 0x02 (indicates the presence of attestation data only)
 ** 0x03 (indicates the presence of both witness and attestation data)
-
 * attestation: Contains the quantum-resistant public keys and signatures.
 
-=== Transaction ID ===
+=== Quantum Transaction ID (qtxid) ===
 
 The transaction ID is computed as the HASH256 of the serialized transaction, including the attestation and witness
 (if a witness is present). When decoded, this is called the qtxid, which will differ from the txid and wtxid if an
@@ -392,23 +439,46 @@ must count the number of inputs present in the transaction.
 The specific quantum-resistant signature algorithm used is inferred from the length of the public key.
 Implementations must recognize the supported algorithms and validate accordingly.
 
-Supported PQC algorithms and their NIST Level V parameters:
-
-* '''SPHINCS+-256f:'''
-  * Public Key Length: 64 bytes
-  * Signature Length: 49,856 bytes
-* '''CRYSTALS-Dilithium Level 5:'''
-  * Public Key Length: 2,592 bytes
-  * Signature Length: 4,595 bytes
-* '''FALCON-1024:'''
-  * Public Key Length: 1,793 bytes
-  * Signature Length: 1,280 bytes
+Supported PQC algorithms and their NIST Level I parameters:
+
+* '''secp256k1 - BIP-340 - Schnorr + X-Only'''
+** Key Type 0
+** Public Key Length: 32 bytes
+** Signature Length: 64 bytes
+** Total Size: 96 bytes
+** Cycles to sign: 42,000 (EdDSA)
+** Cycles to verify: 130,000 (EdDSA)
+* '''FN-DSA-512 - FIPS 206 - FALCON-512:'''
+** Key Type 1
+** Public Key Length: 897 bytes
+** Signature Length: 667 bytes
+** Total Size: 1,564 bytes
+** Cycles to sign: 1,009,764
+** Cycles to verify: 81,036
+* '''ML-DSA-44 - FIPS 204 - CRYSTALS-Dilithium Level I:'''
+** Key Type 2
+** Public Key Length: 1,312 bytes
+** Signature Length: 2,420 bytes
+** Total Size: 3,732 bytes
+** Cycles to sign: 333,013
+** Cycles to verify: 118,412
+* '''SLH-DSA-SHAKE-128s - FIPS 205 - SPHINCS+-128s:'''
+** Key Type 3
+** Public Key Length: 32 bytes
+** Signature Length: 7,856 bytes
+** Total Size: 7,888 bytes
+** Cycles to sign: 4,682,570,992
+** Cycles to verify: 4,764,084
 
 Implementations must reject public keys and signatures that do not match expected lengths for supported algorithms.
 
 If a new algorithm is added, and one of the byte sizes overlaps, then an additional byte should be prepended to the
 new algorithm's public key length that indicates the specific algorithm used.
 
+A bitmask is used to indicate the algorithm used for each public key and signature pair. The bitmask is enumerates based on
+the key type as indicated above. This is used in the cryptographic commitment in the merkle tree hash computation and
+revealed in the attestation when spent.
+
 === Script Validation ===
 
 To spend a P2QRH output, the following conditions must be met:
@@ -425,18 +495,24 @@ the scriptPubKey.
 * Valid signatures corresponding to the public key(s) and the transaction data.
 
 3. For multi-signature schemes, all required public keys and signatures must be provided for that input within the
-attestation. Public keys that are not needed can be excluded by including their hash in the attestation accompanied
-with an empty signature. This includes classical Schnorr signatures.
+attestation. Public keys that are not needed or available can be selectively disclosed by including their hash in the
+attestation accompanied with an empty signature by providing a 0x00 signature length byte.
 
 ==== Sighash Calculation ====
 
-The sighash for P2QRH outputs follows the same procedure as defined in BIP-0143 for SegWit transactions:
+The sighash for P2QRH outputs follows the same procedure as defined in [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341] for Taproot transactions:
+
+* '''Signature Message:''' A single-SHA256 of a tagged hash with the tag "TapSighash", containing transaction data.
+* '''Tagged Hash:''' Computed as H(tag || tag || data) where H is SHA256 and tag is the SHA256 of the tag name.
+* '''Key Data:''' In addition to transaction data, the sighash includes the spent output's scriptPubKey.
+* '''Extension Fields:''' Specific data is included or excluded from the sighash based on the sighash flag.
 
-* '''Hash Prevouts:''' Computed over the previous outputs being spent.
-* '''Hash Sequence:''' Computed over the sequence fields.
-* '''Hash Outputs:''' Computed over the outputs of the transaction.
+This signature hash construction ensures transaction malleability is prevented while providing flexibility through
+different sighash types (DEFAULT, ALL, NONE, SINGLE, and ANYONECANPAY variants). The exact computation follows the
+procedure specified in BIP-341 to maintain compatibility with Taproot signatures.
 
-The message to be signed includes these hashes, ensuring transaction malleability is prevented.
+If a sighash flag other than DEFAULT is needed, it can be placed in the transaction witness. In this case, it will be
+the only field in the witness.
 
 ==== Signature Verification ====
 
@@ -452,44 +528,44 @@ Signature verification is as follows:
 
 3. Verify each signature against the corresponding public key and the sighash.
 
-4. Ensure that the signature algorithm used matches the expected lengths for NIST Level V security, and is supported by
+4. Ensure that the signature algorithm used matches the expected lengths for NIST Level I security, and is supported by
 the implementation.
 
 ==== Attestation Parsing Example ====
 
-Signing for a single input using both FALCON-1024 and secp256k1 Schnorr:
+Signing for a single input using both secp256k1 Schnorr and FALCON-512:
 
 Number of public keys:
 
   [num_pubkeys]: 0x02
 
 Pubkey 1:
-  [pubkey_length]: 0x0701 (1793 bytes)
-  [pubkey]: public_key_falcon_1024
-
-Pubkey 2:
   [pubkey_length]: 0x20 (32 bytes)
   [pubkey]: public_key_secp256k1
 
+Pubkey 2:
+  [pubkey_length]: 0x0701 (1793 bytes)
+  [pubkey]: public_key_falcon_512
+
 Number of signatures:
 
   [num_signatures]: 0x02
 
 Signature 1:
-  [signature_length]: 0x0500 (1280 bytes)
-  [signature]: signature_falcon_1024
-
-Signature 2:
   [signature_length]: 0x40 (64 bytes)
   [signature]: signature_secp256k1
 
+Signature 2:
+  [signature_length]: 0x0500 (1280 bytes)
+  [signature]: signature_falcon_512
+
 Note: This contrasts with multisig inputs, where the attestation structure repeats for each public key and signature.
 
 === Compatibility with BIP-141 ===
 
 By adhering to the SegWit transaction structure and versioning, P2QRH outputs are compatible with existing transaction
 processing rules. Nodes that do not recognize SegWit version 3 will treat these outputs as anyone-can-spend but, per
-BIP-141, will not relay or mine such transactions.
+[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP-141], will not relay or mine such transactions.
 
 === Usage Considerations ===
 
@@ -498,7 +574,7 @@ BIP-141, will not relay or mine such transactions.
 Quantum-resistant signatures are significantly larger than traditional signatures, increasing transaction size and the
 fees required. Users and wallet developers should be aware of this and plan accordingly.
 
-For example, for CRYSTALS-Dilithium Level V, a single signature is 4,595 bytes, a substantial increase over current
+For example, for CRYSTALS-Dilithium Level I, a single public key is 1,312 bytes, and a signature is 2,420 bytes, resulting in a substantial increase over current
 ECDSA or Schnorr signatures.
 
 ==== Performance Impact ====
@@ -615,6 +691,7 @@ seeds to act as the authoritative secret when signing. These measures are deemed
 
 To help implementors understand updates to this BIP, we keep a list of substantial changes.
 
+* 2025-03-12 - Add verification times for each algorithm. 256 -> 128 (NIST V -> NIST I). Add key type bitmask. Clarify multisig semantics.
 * 2025-02-23 - More points of clarification from review. Update dead link.
 * 2025-01-20 - Remove SQIsign from consideration due to significant performance concerns. Refactor language from long-range attack to long-exposure so as to not be confused with the language around block re-org attacks.
 * 2024-12-18 - Assigned BIP number.

From 61faee6cb354ab0d5076375404bd68c43ce328b2 Mon Sep 17 00:00:00 2001
From: Hunter Trujillo 
Date: Tue, 18 Mar 2025 03:50:27 -0600
Subject: [PATCH 042/131] Correct inconsistencies in commitment and attestation
 structure. Switch from merkle tree commitment to sorted vector hash
 commitment.

---
 bip-0360.mediawiki | 186 ++++++++++++++++++++++-----------------------
 1 file changed, 91 insertions(+), 95 deletions(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index 554277bd3e..85463f3bc2 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -287,23 +287,7 @@ The scriptPubKey for a P2QRH output is:
 Where:
 
 * OP_PUSHNUM_3 (0x03) indicates SegWit version 3.
-*  is the 32-byte HASH256 of the merkle root of a tree of public key hashes, as defined in the Hash Computation section below.
-
-=== Output Mechanics ===
-
-To prevent storage of arbitrary data using P2QRH (QuBit) outputs,
-the witness stack for inputs spending SegWit v3 outputs is limited to the fixed-size signatures necessary for spending the
-output, and the output must be spendable to be considered valid within node consensus. A fixed signature size will also
-be helpful to disambiguate between signature types without an additional version byte. Consequently, the correct
-signature algorithm can be inferred through byte length. The public key and signature will be pushed separately to the
-attestation stack. Multiple signatures can be included in order to support multisig applications, and also for spending
-multiple inputs.
-
-Since only valid signatures can be committed to in a SegWit v3 attestation, arbitrary data cannot be added by miners,
-as that would affect the consensus of their block. A CRQC operator is economically disincentivized from computing a
-spendable public key that matched arbitrary signature data due to the cost of that computation. That is because the
-cost of such a computation could prove quite substantial, rather than simply putting the arbitrary data within a
-Taproot witness.
+*  is the 32-byte HASH256 of the commitment, as defined in the Hash Commitment section below.
 
 ==== Key Type Bitmask ====
 
@@ -320,48 +304,53 @@ The key type bitmask is a 1-byte value that indicates the type of key used in th
 
 Example key type bitmask using all supported key types:
 
-0x01 | 0x02 | 0x04 | 0x08 = 0x0F
+  0x01 | 0x02 | 0x04 | 0x08 = 0x0F
 
 ==== Hash Commitment ====
 
-If there is only a single public key, the hash is computed as the HASH256 of the public key, as a commitment to the
-merkle root of a binary tree of public key hashes.
+If there is only a single public key, the hash is computed as the HASH256 of the public key.
 
 In order to support multiple keys, as in the context of multisig or singlesig hybrid cryptography, the hash is
-computed as a sparse merkle tree of multiple public key hashes:
+computed as a commitment to a vector of public key hashes:
 
-1. For each public key, compute its HASH256
-2. Pair the hashes and compute HASH256 of their concatenation
-3. Continue pairing and hashing until reaching a single root hash
-4. Compute the merkle root
-5. Prepend key type bitmask and threshold to the root hash
-6. Compute the HASH256 of the result
+1. Sort the public keys first by key type, then by public key value
+2. For each sorted public key, compute its HASH256
+3. Concatenate all the public key hashes in sorted order
+4. Prepend key type bitmask and threshold to the concatenated hashes
+5. Compute the HASH256 of the result
 
 For example with 4 public keys:
 
-  h1 = HASH256(pubkey1)
-  h2 = HASH256(pubkey2)
-  h3 = HASH256(pubkey3)
-  h4 = HASH256(pubkey4)
+  // First sort the public keys
+  sorted_pubkeys = sort_by_key_type_and_value([pubkey1, pubkey2, pubkey3, pubkey4])
 
-  h12 = HASH256(h1 || h2)
-  h34 = HASH256(h3 || h4)
+  // Then compute hashes of sorted keys
+  h1 = HASH256(sorted_pubkeys[0])
+  h2 = HASH256(sorted_pubkeys[1])
+  h3 = HASH256(sorted_pubkeys[2])
+  h4 = HASH256(sorted_pubkeys[3])
 
-  root = HASH256(h12 || h34)
+  // Concatenate all hashes
+  concatenated = h1 || h2 || h3 || h4
 
-  commitment = key_type_bitmask || threshold || root
+  commitment = key_type_bitmask || threshold || concatenated
 
   hash = HASH256(commitment)
 
+With sort_by_key_type_and_value defined as:
+
+  def sort_by_key_type_and_value(pubkeys):
+      return sorted(pubkeys, key=lambda x: (x.key_type, x.public_key))
+
 When spending, if a public key hash is provided in the attestation with an empty signature, that hash will be used
-directly in the merkle tree computation rather than hashing the full public key. This allows unused public keys to be
+directly in the vector computation rather than hashing the full public key. This allows unused public keys to be
 excluded from the transaction while still proving they were part of the original commitment.
 
-The merkle tree construction creates an efficient cryptographic commitment to multiple public keys while enabling
+The vector construction creates an efficient cryptographic commitment to multiple public keys while enabling
 selective disclosure.
 
 A threshold is provided to indicate the number of signatures required to spend the output. This is used in the
-cryptographic commitment in the merkle tree hash computation and revealed in the attestation when spent.
+cryptographic commitment in the hash computation and revealed in the attestation when spent.
 
 Only a single 32-byte X-only secp256k1 public key can be provided as key type 0. There are a few reasons for this:
 
@@ -370,25 +359,23 @@ Only a single 32-byte X-only secp256k1 public key can be provided as key type 0.
 3. When a secp256k1 key is specified in the key type bitmask, how many keys it commits to is unambiguous.
 4. If multiple keys need to be committed to, they must be aggregated, which saves on transaction size.
 
-This design maintains compatibility for [https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki BIP-114] Taproot
-Merkelized Alternative Script Tree (MAST) merkle root in the attestation, which makes P2QRH a quantum-resistant
-version of Taproot transactions.
+This design maintains compatibility for [https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki BIP-114]
+Taproot Merkelized Alternative Script Tree (MAST) merkle root in the commitment, which makes P2QRH a
+quantum-resistant version of Taproot transactions. The TapScript itself must however be provided in the witness,
+as no script execution is allowed in the attestation.
 
-In a multisig context, aside from secp256k1 keys, the number of keys provided in the attestation is variable and must
-meet the threshold as committed to in the merkle tree hash computation and revealed in the attestation.
+In a multisig context, aside from secp256k1 keys, the number of keys provided in the attestation is variable and
+must meet the threshold as committed to in the hash computation and revealed in the attestation.
 
-If an implementation for public key or signature aggregation for PQC algorithms is developed, key and signature
-aggregation must become the default behavior for P2QRH.
+When the address is generated, all public keys must be known in advance, and they must be sorted, first by key
+type, then by public key value, so as to be deterministic.
 
-When the address is generated, all public keys must be known in advance, and they must be sorted, first by key type,
-then by public key value, so as to be deterministic.
+The key count does not need to be provided for PQC keys because the key type bitmask and threshold are sufficient
+to validate a multisig transaction.
 
-The key count does not need to be provided for PQC keys because the key type bitmask and threshold are sufficient to
-validate a multisig transaction.
-
-In a singlesig context, multiple PQC keys can be provided, but the key type bitmask and threshold must still also be
-provided to be consistent with the multisig semantics. The threshold will be set as 0x01, and the key type bitmask will
-indicate how many keys of each type are present.
+In a singlesig context, multiple PQC keys can be provided, but the key type bitmask and threshold must still also
+be provided to be consistent with the multisig semantics. The threshold will be set as 0x01, and the key type
+bitmask will indicate how many keys of each type are present.
 
 === Transaction Serialization ===
 
@@ -412,11 +399,14 @@ attestation is present.
 
 The attestation field consists of:
 
-* num_pubkeys: The number of public keys ([https://learnmeabitcoin.com/technical/general/compact-size/ compact size]).
+* key_type_bitmask: A [https://learnmeabitcoin.com/technical/general/compact-size/ compact size] value indicating which key types are present.
+* threshold: A compact size value indicating the number of signatures required to spend the output.
+* num_pubkeys: The number of public keys (compact size).
 
 For each public key:
 
-* pubkey_length: compact size length of the public key.
+* key_type: The key type (compact size). Only one bit is used to indicate the key type.
+* pubkey_length: compact size length of the public key (compact size).
 * pubkey: The public key bytes.
 
 Then:
@@ -434,10 +424,45 @@ quantum-resistant algorithms.
 For each input, a separate attestation field is used. To know how many attestation fields are present, implementations
 must count the number of inputs present in the transaction.
 
+==== Attestation Parsing Example ====
+
+Signing for a single input using both secp256k1 Schnorr and FALCON-512:
+
+Number of public keys:
+
+  [key_type_bitmask]: 0x03
+  [threshold]: 0x01
+  [num_pubkeys]: 0x02
+
+Pubkey 1:
+  [key_type]: 0x01
+  [pubkey_length]: 0x20 (32 bytes)
+  [pubkey]: public_key_secp256k1
+
+Pubkey 2:
+  [key_type]: 0x02
+  [pubkey_length]: 0x0701 (1793 bytes)
+  [pubkey]: public_key_falcon_512
+
+Number of signatures:
+
+  [num_signatures]: 0x02
+
+Signature 1:
+  [signature_length]: 0x40 (64 bytes)
+  [signature]: signature_secp256k1
+
+Signature 2:
+  [signature_length]: 0x0500 (1280 bytes)
+  [signature]: signature_falcon_512
+
+Note: This contrasts with multisig inputs, where the attestation structure repeats for each public key and signature.
+
 === Signature Algorithms ===
 
-The specific quantum-resistant signature algorithm used is inferred from the length of the public key.
-Implementations must recognize the supported algorithms and validate accordingly.
+The specific quantum-resistant signature algorithm used cannot be inferred from the length of the public key due to
+collisions in length between algorithms. Instead, when each key is revealed in the attestation, the key type bitmask
+indicates which algorithm was used.
 
 Supported PQC algorithms and their NIST Level I parameters:
 
@@ -470,14 +495,11 @@ Supported PQC algorithms and their NIST Level I parameters:
 ** Cycles to sign: 4,682,570,992
 ** Cycles to verify: 4,764,084
 
-Implementations must reject public keys and signatures that do not match expected lengths for supported algorithms.
-
-If a new algorithm is added, and one of the byte sizes overlaps, then an additional byte should be prepended to the
-new algorithm's public key length that indicates the specific algorithm used.
+Implementations must recognize the supported algorithms and validate accordingly.
 
-A bitmask is used to indicate the algorithm used for each public key and signature pair. The bitmask is enumerates based on
-the key type as indicated above. This is used in the cryptographic commitment in the merkle tree hash computation and
-revealed in the attestation when spent.
+A bitmask is used to indicate the algorithm used for each public key and signature pair. The bitmask enumerates based on
+the key type as indicated above. This is used in the cryptographic commitment in the hash computation and
+revealed in the attestation for each public key when spent.
 
 === Script Validation ===
 
@@ -494,9 +516,12 @@ the scriptPubKey.
 
 * Valid signatures corresponding to the public key(s) and the transaction data.
 
+* The key type bitmask and threshold must match the commitment in the scriptPubKey.
+
 3. For multi-signature schemes, all required public keys and signatures must be provided for that input within the
 attestation. Public keys that are not needed or available can be selectively disclosed by including their hash in the
-attestation accompanied with an empty signature by providing a 0x00 signature length byte.
+attestation accompanied with an empty signature by providing a 0x00 signature length byte. This works so long as
+enough keys to meet the threshold are provided.
 
 ==== Sighash Calculation ====
 
@@ -531,36 +556,6 @@ Signature verification is as follows:
 4. Ensure that the signature algorithm used matches the expected lengths for NIST Level I security, and is supported by
 the implementation.
 
-==== Attestation Parsing Example ====
-
-Signing for a single input using both secp256k1 Schnorr and FALCON-512:
-
-Number of public keys:
-
-  [num_pubkeys]: 0x02
-
-Pubkey 1:
-  [pubkey_length]: 0x20 (32 bytes)
-  [pubkey]: public_key_secp256k1
-
-Pubkey 2:
-  [pubkey_length]: 0x0701 (1793 bytes)
-  [pubkey]: public_key_falcon_512
-
-Number of signatures:
-
-  [num_signatures]: 0x02
-
-Signature 1:
-  [signature_length]: 0x40 (64 bytes)
-  [signature]: signature_secp256k1
-
-Signature 2:
-  [signature_length]: 0x0500 (1280 bytes)
-  [signature]: signature_falcon_512
-
-Note: This contrasts with multisig inputs, where the attestation structure repeats for each public key and signature.
-
 === Compatibility with BIP-141 ===
 
 By adhering to the SegWit transaction structure and versioning, P2QRH outputs are compatible with existing transaction
@@ -691,6 +686,7 @@ seeds to act as the authoritative secret when signing. These measures are deemed
 
 To help implementors understand updates to this BIP, we keep a list of substantial changes.
 
+* 2025-03-18 - Correct inconsistencies in commitment and attestation structure. Switch from merkle tree commitment to sorted vector hash commitment.
 * 2025-03-12 - Add verification times for each algorithm. 256 -> 128 (NIST V -> NIST I). Add key type bitmask. Clarify multisig semantics.
 * 2025-02-23 - More points of clarification from review. Update dead link.
 * 2025-01-20 - Remove SQIsign from consideration due to significant performance concerns. Refactor language from long-range attack to long-exposure so as to not be confused with the language around block re-org attacks.

From e6e72078084271cbba50d54c2d2a2b180daf8356 Mon Sep 17 00:00:00 2001
From: Hunter Trujillo 
Date: Tue, 18 Mar 2025 09:46:10 -0600
Subject: [PATCH 043/131] Update descriptor format.

---
 bip-0360.mediawiki | 44 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 36 insertions(+), 8 deletions(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index 85463f3bc2..001664ffb3 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -258,15 +258,43 @@ To integrate P2QRH into existing wallet software and scripts, we introduce a new
 qrh(). This function represents a P2QRH output, similar to how wpkh() and tr()
 are used for P2WPKH and P2TR outputs, respectively.
 
-The qrh() function takes the HASH256 of the concatenated HASH256 of the quantum-resistant public keys as
-its argument. For example:
+The qrh() function takes a threshold value and multiple key specifications grouped by key type. The format is:
 
-  qrh(HASH256(HASH256(pubkey1) || HASH256(pubkey2) || ...))
+  qrh(threshold, keytype(0x01, [hash1, hash2, ...]), keytype(0x02, [hash1, hash2, ...]), ...)
 
-This function allows wallets to manage P2QRH addresses and outputs while accommodating multiple public keys of varying
-lengths, such as in multisig schemes, while keeping the public keys hidden until the time of spending. At a minimum,
-there should be two public keys in a P2QRH output: one key that makes use of classical cryptography, and one that makes use
-of a PQC algorithm chosen within the wallet.
+Where:
+
+* threshold is an integer specifying the minimum number of signatures required
+* keytype is the hex value representing the key type (0x01 for secp256k1, 0x02 for FALCON-512, 0x04 for CRYSTALS-Dilithium Level I, 0x08 for SPHINCS+-128s)
+* [hash1, hash2, ...] is an array of HASH256 hashes of public keys for the corresponding algorithm type
+
+For example:
+
+  qrh(3, keytype(0x01, hash256(secp256k1_pubkey1), hash256(secp256k1_pubkey2), hash256(secp256k1_pubkey3), secp256k1_pubkey4_hash, secp256k1_pubkey5_hash),
+      keytype(0x02, hash256(falcon_pubkey1), hash256(falcon_pubkey2), hash256(falcon_pubkey3), falcon_pubkey4_hash, falcon_pubkey5_hash),
+      keytype(0x04, hash256(dilithium_pubkey1), hash256(dilithium_pubkey2), hash256(dilithium_pubkey3), dilithium_pubkey4_hash, dilithium_pubkey5_hash),
+      keytype(0x08, hash256(sphincs_pubkey1), hash256(sphincs_pubkey2), hash256(sphincs_pubkey3), sphincs_pubkey4_hash, sphincs_pubkey5_hash))
+
+This represents a 3-of-5 multisig for each key type, with a total of 20 keys: 5 keys per type (3 full public keys and 2
+hashes) across 4 different key types.
+
+Internally, the descriptor computes the HASH256 of the concatenated HASH256 of all the quantum-resistant public keys,
+with the threshold and key type bitmask prepended. For each key in the descriptor:
+
+- If it is already a hash (indicated in the descriptor), it is used directly
+- If it is a public key, HASH256 is applied to it first
+
+This approach ensures that all items in the vector are HASH256 values, whether they originated from raw public keys or
+were provided as hashes. During spending, this allows for selective disclosure of public keys, where some keys can
+remain hidden (represented only by their hashes) while others are fully revealed with their corresponding public keys.
+This flexibility is particularly valuable in multisig schemes where not all keys need to be revealed to satisfy the
+threshold requirement. At a minimum, there should be two different key types in a P2QRH output: one key that makes use
+of classical cryptography, and one that makes use of a PQC algorithm chosen within the wallet.
+
+Also, it's important to note that order of keys and hashes in the descriptor matters and is based on the original
+public key values, in addition to the key type. Additionally, qrh() does not compile to script, but instead, describes
+what's needed to compute the scriptPubKey hash commitment and also to reveal the attestation needed to spend the
+output.
 
 === Address Format ===
 
@@ -686,7 +714,7 @@ seeds to act as the authoritative secret when signing. These measures are deemed
 
 To help implementors understand updates to this BIP, we keep a list of substantial changes.
 
-* 2025-03-18 - Correct inconsistencies in commitment and attestation structure. Switch from merkle tree commitment to sorted vector hash commitment.
+* 2025-03-18 - Correct inconsistencies in commitment and attestation structure. Switch from merkle tree commitment to sorted vector hash commitment. Update descriptor format.
 * 2025-03-12 - Add verification times for each algorithm. 256 -> 128 (NIST V -> NIST I). Add key type bitmask. Clarify multisig semantics.
 * 2025-02-23 - More points of clarification from review. Update dead link.
 * 2025-01-20 - Remove SQIsign from consideration due to significant performance concerns. Refactor language from long-range attack to long-exposure so as to not be confused with the language around block re-org attacks.

From c43487dba4321696c0eeffc1e638e586dce3c1e0 Mon Sep 17 00:00:00 2001
From: jbride 
Date: Wed, 4 Jun 2025 11:48:43 -0600
Subject: [PATCH 044/131] bip-0360:  test vectors

---
 bip-0360/ref-impl/.gitignore                  |   3 +
 bip-0360/ref-impl/Cargo.lock                  | 520 ++++++++++++++++++
 bip-0360/ref-impl/Cargo.toml                  |  33 ++
 bip-0360/ref-impl/README.md                   |  26 +
 bip-0360/ref-impl/src/data_structures.rs      | 291 ++++++++++
 bip-0360/ref-impl/src/error.rs                |  11 +
 bip-0360/ref-impl/src/lib.rs                  |   2 +
 .../tests/data/bip-0360/descriptors.json      | 231 ++++++++
 .../tests/data/bip-0360/test_vectors.json     | 193 +++++++
 bip-0360/ref-impl/tests/descriptor_tests.rs   |  35 ++
 bip-0360/ref-impl/tests/p2qrh_tests.rs        | 263 +++++++++
 11 files changed, 1608 insertions(+)
 create mode 100644 bip-0360/ref-impl/.gitignore
 create mode 100644 bip-0360/ref-impl/Cargo.lock
 create mode 100644 bip-0360/ref-impl/Cargo.toml
 create mode 100644 bip-0360/ref-impl/README.md
 create mode 100644 bip-0360/ref-impl/src/data_structures.rs
 create mode 100644 bip-0360/ref-impl/src/error.rs
 create mode 100644 bip-0360/ref-impl/src/lib.rs
 create mode 100644 bip-0360/ref-impl/tests/data/bip-0360/descriptors.json
 create mode 100644 bip-0360/ref-impl/tests/data/bip-0360/test_vectors.json
 create mode 100644 bip-0360/ref-impl/tests/descriptor_tests.rs
 create mode 100644 bip-0360/ref-impl/tests/p2qrh_tests.rs

diff --git a/bip-0360/ref-impl/.gitignore b/bip-0360/ref-impl/.gitignore
new file mode 100644
index 0000000000..ec700b5f90
--- /dev/null
+++ b/bip-0360/ref-impl/.gitignore
@@ -0,0 +1,3 @@
+rust-bitcoin
+rust-miniscript
+target
diff --git a/bip-0360/ref-impl/Cargo.lock b/bip-0360/ref-impl/Cargo.lock
new file mode 100644
index 0000000000..e0ca886de3
--- /dev/null
+++ b/bip-0360/ref-impl/Cargo.lock
@@ -0,0 +1,520 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anstream"
+version = "0.6.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
+
+[[package]]
+name = "base58ck"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f"
+dependencies = [
+ "bitcoin-internals",
+ "bitcoin_hashes",
+]
+
+[[package]]
+name = "bech32"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d"
+
+[[package]]
+name = "bitcoin"
+version = "0.32.6"
+dependencies = [
+ "base58ck",
+ "bech32",
+ "bitcoin-internals",
+ "bitcoin-io",
+ "bitcoin-units",
+ "bitcoin_hashes",
+ "hex-conservative",
+ "hex_lit",
+ "secp256k1",
+]
+
+[[package]]
+name = "bitcoin-internals"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2"
+
+[[package]]
+name = "bitcoin-io"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf"
+
+[[package]]
+name = "bitcoin-units"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2"
+dependencies = [
+ "bitcoin-internals",
+]
+
+[[package]]
+name = "bitcoin_hashes"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16"
+dependencies = [
+ "bitcoin-io",
+ "hex-conservative",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "colorchoice"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
+
+[[package]]
+name = "env_filter"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
+dependencies = [
+ "log",
+ "regex",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.11.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "env_filter",
+ "jiff",
+ "log",
+]
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "hex-conservative"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd"
+dependencies = [
+ "arrayvec",
+]
+
+[[package]]
+name = "hex_lit"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd"
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "jiff"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
+dependencies = [
+ "jiff-static",
+ "log",
+ "portable-atomic",
+ "portable-atomic-util",
+ "serde",
+]
+
+[[package]]
+name = "jiff-static"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "log"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "miniscript"
+version = "13.0.0"
+dependencies = [
+ "bech32",
+ "bitcoin",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
+
+[[package]]
+name = "p2qrh-ref"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "bitcoin",
+ "env_logger",
+ "hex",
+ "log",
+ "miniscript",
+ "once_cell",
+ "serde",
+ "serde_json",
+ "thiserror",
+]
+
+[[package]]
+name = "portable-atomic"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
+
+[[package]]
+name = "portable-atomic-util"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
+dependencies = [
+ "portable-atomic",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "secp256k1"
+version = "0.29.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113"
+dependencies = [
+ "bitcoin_hashes",
+ "secp256k1-sys",
+]
+
+[[package]]
+name = "secp256k1-sys"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.140"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "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.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/bip-0360/ref-impl/Cargo.toml b/bip-0360/ref-impl/Cargo.toml
new file mode 100644
index 0000000000..ea24ec1b00
--- /dev/null
+++ b/bip-0360/ref-impl/Cargo.toml
@@ -0,0 +1,33 @@
+[package]
+name = "p2qrh-ref"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+
+# Dev version of miniscript crate re-exports bitcoin 0.32.6
+miniscript = "13.0.0"
+
+# During local dev, ensure version used here matches the version of the forked local library (referenced in:  patch.crates-io)
+bitcoin = "0.32.6"
+
+env_logger = "0.11.5"
+log = "0.4.22"
+serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0"
+once_cell = "1.19"
+hex = "0.4.3"
+anyhow = "1.0.98"
+thiserror = "2.0.12"
+
+[patch.crates-io]
+
+#bitcoin = { git = "https://github.com/jbride/rust-bitcoin.git", branch = "p2qrh" }
+
+# Verify:
+#  cargo update
+#  cargo tree -p bitcoin | more
+bitcoin = { path = "./rust-bitcoin/bitcoin" }
+
+#  cargo tree -p miniscript | more
+miniscript = { path = "./rust-miniscript" }
diff --git a/bip-0360/ref-impl/README.md b/bip-0360/ref-impl/README.md
new file mode 100644
index 0000000000..6ac9487fdf
--- /dev/null
+++ b/bip-0360/ref-impl/README.md
@@ -0,0 +1,26 @@
+
+# p2qrh test vectors
+
+This rust project contains the test vectors for BIP-360
+
+
+## Local Development
+
+These test vectors are being developed in conjunction with forks of [rust-bitcoin](https://github.com/jbride/rust-bitcoin/tree/p2qrh) and [rust-miniscript](https://github.com/jbride/rust-miniscript/tree/p2qrh) customized with p2qrh functionality.
+As such, these test vectors assume the presence of these customized forks cloned to your local environment. 
+
+1. create soft-link to your `rust-bitcoin` clone: 
+   ```
+   $ ln -s /path/to/git/clone/of/rust-bitcoin
+   ```
+
+1. create soft-link to your `rust-miniscript` clone: 
+   ```
+   $ ln -s /path/to/git/clone/of/rust-miniscript
+   ```
+
+1. run a specific test:
+   ```
+   $ cargo test test_p2qrh_single_leaf_script_tree -- --nocapture
+   ```
+
diff --git a/bip-0360/ref-impl/src/data_structures.rs b/bip-0360/ref-impl/src/data_structures.rs
new file mode 100644
index 0000000000..fcd6403940
--- /dev/null
+++ b/bip-0360/ref-impl/src/data_structures.rs
@@ -0,0 +1,291 @@
+use std::collections::HashMap;
+use serde::{Deserialize, Serialize};
+use log::debug;
+
+#[derive(Debug, Serialize)]
+pub struct TestVectors {
+    pub version: u32,
+    #[serde(rename = "test_vectors")]
+    pub test_vectors: Vec,
+    #[serde(skip, default = "HashMap::new")]
+    pub test_vector_map: HashMap,
+}
+
+impl TestVectors {
+    fn new() -> Self {
+        Self {
+            version: 0,
+            test_vectors: Vec::new(),
+            test_vector_map: HashMap::new(),
+        }
+    }
+}
+
+impl<'de> Deserialize<'de> for TestVectors {
+    fn deserialize(deserializer: D) -> Result
+    where
+        D: serde::Deserializer<'de>,
+    {
+        #[derive(Deserialize)]
+        struct Helper {
+            version: u32,
+            #[serde(rename = "test_vectors")]
+            test_vectors: Vec,
+        }
+
+        let helper = Helper::deserialize(deserializer)?;
+        
+        let mut test_vector_map = HashMap::new();
+        for test in helper.test_vectors.iter() {
+            test_vector_map.insert(test.id.clone(), test.clone());
+        }
+
+        Ok(TestVectors {
+            version: helper.version,
+            test_vectors: helper.test_vectors,
+            test_vector_map,
+        })
+    }
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct TestVector {
+    pub id: String,
+    pub objective: String,
+    pub given: TestVectorGiven,
+    pub intermediary: TestVectorIntermediary,
+    pub expected: TestVectorExpected,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct TestVectorGiven {
+    #[serde(rename = "internalPubkey")]
+    pub internal_pubkey: Option,
+    #[serde(rename = "scriptTree")]
+    pub script_tree: Option,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct TestVectorIntermediary {
+
+    #[serde(default)]
+    #[serde(rename = "leafHashes")]
+    pub leaf_hashes: Vec,
+    #[serde(rename = "merkleRoot")]
+    pub merkle_root: Option
+}
+
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct TestVectorExpected {
+    #[serde(rename = "scriptPubKey")]
+    pub script_pubkey: Option,
+    #[serde(rename = "bip350Address")]
+    pub bip350_address: Option,
+    #[serde(default)]
+    #[serde(rename = "scriptPathControlBlocks")]
+    pub script_path_control_blocks: Option>,
+    #[serde(rename = "error")]
+    pub error: Option,
+    #[serde(rename = "address")]
+    pub address: Option,
+}
+
+// Taproot script trees are binary trees, so each branch should have exactly two children.
+#[derive(Debug, Serialize, Clone)]
+pub enum TVScriptTree {
+    Leaf(TVScriptLeaf),
+    Branch {
+
+        // Box is used because Rust needs to know the exact size of types at compile time.
+        // Without it, we'd have an infinitely size recursive type.
+        // The enum itself is on the stack, but the Box fields within the Branch variant store pointers to heap-allocated ScriptTree values.
+        left: Box,
+        right: Box,
+    },
+}
+
+// Add custom deserialize implementation
+impl<'de> Deserialize<'de> for TVScriptTree {
+    fn deserialize(deserializer: D) -> Result
+    where
+        D: serde::Deserializer<'de>,
+    {
+        #[derive(Deserialize)]
+        #[serde(untagged)]
+        enum Helper {
+            Leaf(TVScriptLeaf),
+            Branch(Vec),
+        }
+
+        match Helper::deserialize(deserializer)? {
+            Helper::Leaf(leaf) => Ok(TVScriptTree::Leaf(leaf)),
+            Helper::Branch(v) => {
+                assert!(v.len() == 2, "Branch must have exactly two children");
+                let mut iter = v.into_iter();
+                Ok(TVScriptTree::Branch {
+                    left: Box::new(iter.next().unwrap()),
+                    right: Box::new(iter.next().unwrap()),
+                })
+            }
+        }
+    }
+}
+
+// Add this enum before the TVScriptTree implementation
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum Direction {
+    Left,
+    Right,
+    Root,
+}
+
+impl TVScriptTree {
+    /// Implements a "post-order" traversal as follows: left, right, branch
+    pub fn traverse_with_depth(&self, depth: u8, direction: Direction, f: &mut F) {
+        match self {
+            TVScriptTree::Branch { left, right } => {
+
+                right.traverse_with_depth(depth, Direction::Right, f); // Pass Right for right subtree
+                left.traverse_with_depth(depth, Direction::Left, f);   // Pass Left for left subtree
+                f(self, depth, direction);  // Pass the current node's direction
+            }
+            TVScriptTree::Leaf { .. } => {
+                f(self, depth, direction);
+            }
+        }
+    }
+
+    /// Traverses the tree visiting right subtree leaves first, then left subtree leaves.
+    /// Depth increases by 1 at each branch level.
+    /*
+             root (depth 0)
+            /            \
+        L0 (depth 1)    (subtree) (depth 1)
+                            /          \
+                    L1 (depth 2)    L2 (depth 2)
+
+        The new traversal will visit:
+            L1 at depth 2 -> L2 at depth 2 -> L0 at depth 1
+     */
+    pub fn traverse_with_right_subtree_first(&self, depth: u8, direction: Direction, f: &mut F) {
+        match self {
+            TVScriptTree::Branch { left, right } => {
+                let next_depth = depth + 1;
+                // Visit right subtree first
+                right.traverse_with_right_subtree_first(next_depth, Direction::Right, f);
+                // Then visit left subtree
+                left.traverse_with_right_subtree_first(next_depth, Direction::Left, f);
+            }
+            TVScriptTree::Leaf { .. } => {
+                f(self, depth, direction);
+            }
+        }
+    }
+}
+
+impl std::fmt::Display for Direction {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        match self {
+            Direction::Left => write!(f, "L"),
+            Direction::Right => write!(f, "R"),
+            Direction::Root => write!(f, "Root"),
+        }
+    }
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct TVScriptLeaf {
+    pub id: u8,
+    pub script: String,
+    #[serde(rename = "leafVersion")]
+    pub leaf_version: u8,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct TVScriptPubKeyIntermediary {
+    #[serde(default)]
+    #[serde(rename = "leafHashes")]
+    pub leaf_hashes: Vec,
+    #[serde(rename = "merkleRoot")]
+    pub merkle_root: Option
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct TVScriptPubKeyExpected {
+    #[serde(rename = "scriptPubKey")]
+    pub script_pubkey: String,
+    #[serde(rename = "bip350Address")]
+    pub bip350_address: String,
+    #[serde(default)]
+    #[serde(rename = "scriptPathControlBlocks")]
+    pub script_path_control_blocks: Vec,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct TVUtxoSpent {
+    #[serde(rename = "scriptPubKey")]
+    pub script_pubkey: String,
+    #[serde(rename = "amountSats")]
+    pub amount_sats: u64,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct TVInputSpending {
+    pub given: TVInputSpendingGiven,
+    pub intermediary: TVInputSpendingIntermediary,
+    pub expected: TVInputSpendingExpected,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct TVInputSpendingGiven {
+    #[serde(rename = "txinIndex")]
+    pub txin_index: u32,
+    #[serde(rename = "internalPrivkey")]
+    pub internal_privkey: String,
+    #[serde(rename = "merkleRoot")]
+    pub merkle_root: Option,
+    #[serde(rename = "hashType")]
+    pub hash_type: u8,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct TVInputSpendingIntermediary {
+    #[serde(rename = "internalPubkey")]
+    pub internal_pubkey: String,
+    #[serde(rename = "sigMsg")]
+    pub sig_msg: String,
+    #[serde(rename = "precomputedUsed")]
+    pub precomputed_used: Vec,
+    #[serde(rename = "sigHash")]
+    pub sig_hash: String,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct TVInputSpendingExpected {
+    pub witness: Vec,
+}
+
+pub struct ScriptTreeHashCache {
+    pub leaf_hashes: HashMap,
+    pub branch_hashes: HashMap,
+}
+
+impl ScriptTreeHashCache {
+    pub fn new() -> Self {
+        Self {
+            leaf_hashes: HashMap::new(),
+            branch_hashes: HashMap::new(),
+        }
+    }
+
+    pub fn set_leaf_hash(&mut self, branch_id: u8, direction: Direction, hash: String) {
+        let key = format!("{branch_id}_{direction}");
+        debug!("set_leaf_hash: key: {}, hash: {}", key, hash);
+        self.leaf_hashes.insert(key, hash);
+    }
+
+    pub fn set_branch_hash(&mut self, branch_id: u8, hash: String) {
+        self.branch_hashes.insert(branch_id, hash);
+    }
+}
\ No newline at end of file
diff --git a/bip-0360/ref-impl/src/error.rs b/bip-0360/ref-impl/src/error.rs
new file mode 100644
index 0000000000..c8dd8d71c4
--- /dev/null
+++ b/bip-0360/ref-impl/src/error.rs
@@ -0,0 +1,11 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum P2QRHError {
+    #[error("P2QRH requires a script tree with at least one leaf")]
+    MissingScriptTreeLeaf,
+    
+    // We can add more specific error variants here as needed
+    #[error("Invalid script tree structure: {0}")]
+    InvalidScriptTree(String),
+} 
\ No newline at end of file
diff --git a/bip-0360/ref-impl/src/lib.rs b/bip-0360/ref-impl/src/lib.rs
new file mode 100644
index 0000000000..e9333844cb
--- /dev/null
+++ b/bip-0360/ref-impl/src/lib.rs
@@ -0,0 +1,2 @@
+pub mod data_structures;
+pub mod error;
\ No newline at end of file
diff --git a/bip-0360/ref-impl/tests/data/bip-0360/descriptors.json b/bip-0360/ref-impl/tests/data/bip-0360/descriptors.json
new file mode 100644
index 0000000000..327fdffa4c
--- /dev/null
+++ b/bip-0360/ref-impl/tests/data/bip-0360/descriptors.json
@@ -0,0 +1,231 @@
+{
+    "version": 1,
+    "test_vectors": [
+        {
+            "id": "p2qrh_single_key_commitment",
+            "objective": "Tests P2QRH with single SECP256K1-SCHNORR public key only.  Expect error",
+            "description": "At a minimum, there should be two different key types in a P2QRH output: one key that makes use of classical cryptography, and one that makes use of a PQC algorithm chosen within the wallet",
+            "given": {
+                "threshold": 2,
+                "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074"
+            },
+            "intermediary": {
+            },
+            "expected": {
+                "error": "P2QRH addresses expect at least one PQC public key of type ML-DSA-44 and/or SLH_DSA_128S"
+            }
+        },
+        {
+            "id": "p2qrh_mixed_single_key_commitment",
+            "objective": "Tests P2QRH with single mix of SECP256K1-SCHNORR and ML-DSA-44 public keys",
+            "given": {
+                "threshold": 2,
+                "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074",
+                "publicKey": "6fe991c97f0094b2fb636ab4951878f239e2871c3cfdc2936230dac5dde8441d3ff41704025260c25b7e44416142778452694110793465d38ff66244a87aaacaf38103adde0dcf2f6056d48fcc43da9483ce6cfdd96ba2159b2f9653d24fe1f280c924db81830abe6d1070e5b32d2cf373c67dade4bd7c02bb6f5e76ff934316a774cc965fd9e921efbb81053260a07b84dd696d3eb012f9989cab684ce3c104bf926c7fd51a305a79ac2e825d6b5ea51618412b9076ca8f836342fb2412bcd525a9b435de5b0e1643dc2c49aa16a0ae710694657325bc86221ad6f9b5bb6195dee7d7f282c3046ae79f49c3d6339fe52b547ab06af76c12ae1812fa4d87f27700885e35ed91fac93388a4a5c0e37a65eb39f516122e264d716cc120500dc883eee64b22d944bc8061361629e27fc9105b28ff0723330793d6aa62dd6736d7cb157fe7e7545ed6be95d25d795eb24bff5e5b0445b18aa1081bbf99dc9eefb5e04984ca2d340278e2033e40d47824ff5e7c32343c3ffd7b209a49f88046fc52f3e145725aa5aff7cfa785a70accaaec63602f1e92f9a40c9aab89866b8ceab649dc58c4ae338297f8a9a419b70fe23229fd9bf264f403b5fee4e51651a7c5f21d82a3b5871436e85d84a2a036b117502d92e91cbef77ba75891eafcd8054dccd2b6c7201d1abc0dc2a5709a4897bafd88e673184c783ba5eed4f687df619280b532fd9e1b3c87028bc13bff6a71249825391e9b1790a5678ed021cd2820da1245dfda436d32394cbea6b5803b49e7234a538ddfbbd1a70051ee7357906660f71aac0728348230b66158ce6d6e061f2003cb3523fe5878b858c6c1aa94a4380a6cbe3012ec21a78a5fc94ab6697d64277fb5a3de6d7a9950aef094531303832dc77a334fabfcc4f9140fd8d420acf1f66e5a44e21c468dca0dee61913536d0bdf296618b73e43ecdc8a77b24644f0dfba4d009b552557d81a3203f9d434801925296763a2901360469547b3bc921217d1dbeb2f76e0dfaef9f91fc4a15baa57aca815b92d67615dee4c75b35df324246854f72a15109311ec2b5358446f48c1f925299bf701819c86be5aeafde4f616cd6c5db2762634a3387cb4b7eb317c569a50824fdce1bb858852550207144fc7ef6f3957c3417bcc6a7fb317441f87da106303a7da85b05dfacdcbc36910311669bb4f580d5282502c6797517521def3fd5d8bc04e5b55ba840a4cf193b8cc3e275bbd96632912ac5c4d26816c411ff4820401eceaffe1e32cfc6963565854b44a96585397cbb3aa3cd42ce8466748a8e769593fdd57a6f85dbdcf2705434302da89bd825196ae3ab3a2b3bd54864c41f0ba9dfccf0c2b508ef5e95b30e2706fc709f1261ca47fa236906c6d75e44ad388b8dc587ae98cd7442e279542e9bd776f20eefd24e701dab038a409f1ca25e7a8003519f3a7daf98e8ac2e9c11287a8bb4fa4219216387023418e9525c61e96440b48404fb8fbba19c469fe9e0291c2e4b61425cd69cfdd17826ce1652385316b461e6433a61185d13c548a16942403c75fceedb7823824b69986e6ce364784de01624429a149f9adb40c3274aa3ab2c13ac8769cc8f0a9e385c72410f08743a55f77066405af9fc9d036042788fc806eb1575c81cc3fbcc9f6a493ca54ee25eb202395f299bbc36f9e111edccc2e0020123b63b9ae53440bcdab7f7902f4acbee8b41f9b46551dc2185cfe3bffe4d2cd2e8abafbe01aed638cf9f1768466a74b055edb98002bc812fb6fb7d82abe53e4c94bc5e63d5836a931cec902044770a9406e4539145d5c8a5c699df243520c9c710de92582f180297ea0422e4196bf205"
+            },
+            "intermediary": {
+                "concatenated": "xxxx",
+                "commitment": "yyyy"
+            },
+            "expected": {
+                "hash": "zzzz",
+                "address": "bc1r8rt68aze8tek87cnz4ndnvfzk6tk93jv39n4lmpu5a4yw453rcpszsft3z"
+            }
+        },
+        {
+            "id": "p2qrh_mixed_multiple_key_commitment",
+            "objective": "Tests P2QRH with multiple mix of SECP256K1_SCHNORR, ML_DSA_44 and SLH_DSA_128S public keys",
+            "given": {
+                "threshold": 3,
+                "publicKey": "9d46fdd36eac78059fa4d146a654c1221ae878f54690a9646a600674222f33ca",
+                "publicKey": "0b16be67d10c2d49adaadc17c2f566c67e95adfd529047bc6b65c3a5f47f738789e2d2768bc5bec3fcaba3efc717063a48957a0f562a49683ec2852696eda7f7b72c84665b7459409f58bad095dfc122912fce3d62306c7787b3a587745be34b579eeaabb574ce66b7139bff491c6e4c5eb65cccea321da3412a10eaca3528d4fac4a2147abb2104d830e29b32a8e6052fd3b9ac338fe51b9a6e0f893a8acdf93d55deebb7f4226d6cd4e02b0723081701121740d3ae7d11cbab82f23b14ddfd9032a434ad972c047aa3b577590605b7dc8b2c75fcbd490d504f2edffaae249a78fd554932d3bf3008b609171420216bd9d8c4607a60c953bc4512cf0c5cca73aa51de9185519768846f6c1f1b19a96748d44b80a8b8acd551a1902c967ab138f64ec6c9f662d5903aa0324d9b50fb52e262ae6676ed602ca622b705a2878e29db4e4134e81fa4cacbcf9ac8825a2d24e573acb6ad2b6323741630ae247c626bd82f1e460457f883c84f7708180ce66f4ea65ff90b7d604806d4fb5a3a27d6890d32f6266ffa6d06399e740c95d30b03777b9a90ec9e7e9aeb7492bd6a2c8574617a3bc55df2679ee50707876d095809c75b2b0cd526d0c2d2c232686f4f712606b87a648438b731823dc4cd7dc7ac6eeca2a19506f738152a828d9d953cc5a729a70b1c68643c39081e543488261e73fc5ddac2c5ec8303985eab64916b174f9c9cac01316795465968e68a78cea4accd7ba8530472f856930fb97cbd8130827cee5a5537abfaaa1d9fd88e8eefdf5dea3a92a502c53962d08a2ccda3b00608f02fc26165538a0ed90876d780986b4b551ce7fb68783e301735add0810bb16904bbe8c217ee8ca40aafab17f3ba535acdb87508140bdf01d550719a7d29a26a4b494956c84e2025d73741e4f5c30a17f47428d6af8c1145a1d67b4c76bddbd546c42004ccf3533e6630d8531891ffe7800a27f249b0af7cee08c6599546ea4c73721eabbda08bff659ce69bc9ab8224aa59b0566413e6cb6ff1f98dd1cb37d45c2e297cee9cc0d1fd28ad26171b54c67848cec24faaa5698427d53fa297f8f4ba741c794064cd195fb2a1602cba52f5232dc066405d6b5687b4948b8d0884c9be46a3660858c7684488c463d2c155c06282b7ddd93eff0ab52aa93998485a0225040499de4e7a0381defa63a1e8539929a2a2d433c84818de17db1528926d00fae6a836b48d44caab624ac8891dd9356e41680f551d81b4dac2f1d52d540c2b36c49909ac3d87a24c7eae849496af33c7bfcae36546cfd46936ec1bf90b6cd394d2a8fd0c236af4fd00789e05f738247cf35562f967c3f9b939adf613ab79cbfa0e06b07a09a55cf2e677a08d6c727f802bf0855be7153713d5633071d4ebb00ddda676c1578cfaf74a715935d094cfa9f7b97d2b5d440801cec996f1fde42c64cafbe348fa619521dcfd5b8d2cb3ca2c9d6cd276d0af1e2fa8fc2e5531868b6daad393eed8c7197d40779ff7df88fea2a769653b5f616af3f4a1eecfd1c5bac89f6c56d46a733826d0ffec129fc3cb1187aebc087c53bfe9a973cb145915ca140cb30a020609401a018fcb1c1b882c6cf95fd06eb9c70ac6de5ec98666dc10534eba017d36ea45d28e73d50202fa06f7e9cc29afd0e15548a15a841afbe793027e653b6993471280cbb3c7f4174053881242f0759c8f40ca2d7fdbabd0d180e99b02c08bfcd7201ed589e3afafefebac6365a5436b113a47f75587e03413752fd103fa0d868f0c4ec13812e6e3e13c5356a371b838d94a9aa8c858aa827c5a6e11302d9b35aa7faa11e0ddac2a2e697442ee9963623dce52989de3ccc20e81",
+                "publicKey": "768a54113541212e258a8d24f912f61fcb3f40e6967570ba0ea35d8023e965d2"
+            },
+            "intermediary": {
+                "concatenated": "xxxx",
+                "commitment": "yyyy"
+            },
+            "expected": {
+                "hash": "zzzz"
+            }
+        },
+        {
+            "id": "valid_p2qrh_address_generation",
+            "objective": "Verify the correct generation of a P2QRH address from a given public key using the specified quantum-resistant hash function",
+            "given": {
+                "threshold": 2,
+                "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074",
+                "publicKey": "xxx"
+            },
+            "intermediary": {
+            },
+            "expected": {
+                "error": "P2QRH addresses expect at least one PQC public key of type ML-DSA-44 and/or SLH_DSA_128S"
+            }
+        },
+        {
+            "id": "invalid_public_key_handling",
+            "objective": "Ensure the system correctly identifies and rejects invalid or malformed public keys during address generation",
+            "given": {
+                "threshold": 2,
+                "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074",
+                "publicKey": "xxx"
+            },
+            "intermediary": {
+            },
+            "expected": {
+                "error": "P2QRH addresses expect at least one PQC public key of type ML-DSA-44 and/or SLH_DSA_128S"
+            }
+        },
+        {
+            "id": "quantum_resistant_sig_verification",
+            "objective": "Test the verification process of a transaction signed with a quantum-resistant signature algorithm",
+            "given": {
+                "threshold": 2,
+                "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074",
+                "publicKey": "6fe991c97f0094b2fb636ab4951878f239e2871c3cfdc2936230dac5dde8441d3ff41704025260c25b7e44416142778452694110793465d38ff66244a87aaacaf38103adde0dcf2f6056d48fcc43da9483ce6cfdd96ba2159b2f9653d24fe1f280c924db81830abe6d1070e5b32d2cf373c67dade4bd7c02bb6f5e76ff934316"
+            },
+            "intermediary": {
+                "concatenated": "xxxx",
+                "commitment": "yyyy"
+            },
+            "expected": {
+                "hash": "zzzz"
+            }
+        },
+        {
+            "id": "p2qrh_unsupported_signature_algorithm_rejection",
+            "objective": "Ensure that signatures using unsupported algorithms are correctly rejected",
+            "given": {
+                "threshold": 2,
+                "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074",
+                "publicKey": "invalid_quantum_key_type_12345"
+            },
+            "intermediary": {
+            },
+            "expected": {
+                "error": "Unsupported quantum-resistant signature algorithm"
+            }
+        },
+        {
+            "id": "p2qrh_scriptpubkey_construction",
+            "objective": "Validate the correct construction of the scriptPubKey for P2QRH addresses",
+            "given": {
+                "threshold": 2,
+                "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074",
+                "publicKey": "6fe991c97f0094b2fb636ab4951878f239e2871c3cfdc2936230dac5dde8441d3ff41704025260c25b7e44416142778452694110793465d38ff66244a87aaacaf38103adde0dcf2f6056d48fcc43da9483ce6cfdd96ba2159b2f9653d24fe1f280c924db81830abe6d1070e5b32d2cf373c67dade4bd7c02bb6f5e76ff934316"
+            },
+            "intermediary": {
+                "concatenated": "xxxx",
+                "commitment": "yyyy",
+                "scriptPubKey": "OP_2  OP_EQUAL"
+            },
+            "expected": {
+                "valid": true,
+                "scriptPubKeyHex": "5220zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz87"
+            }
+        },
+        {
+            "id": "p2qrh_scriptsig_validation",
+            "objective": "Ensure that the scriptSig correctly unlocks the P2QRH scriptPubKey",
+            "given": {
+                "threshold": 2,
+                "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074",
+                "publicKey": "6fe991c97f0094b2fb636ab4951878f239e2871c3cfdc2936230dac5dde8441d3ff41704025260c25b7e44416142778452694110793465d38ff66244a87aaacaf38103adde0dcf2f6056d48fcc43da9483ce6cfdd96ba2159b2f9653d24fe1f280c924db81830abe6d1070e5b32d2cf373c67dade4bd7c02bb6f5e76ff934316",
+                "message": "0000000000000000000000000000000000000000000000000000000000000000"
+            },
+            "intermediary": {
+                "scriptSig": "  ",
+                "scriptPubKey": "OP_2  OP_EQUAL"
+            },
+            "expected": {
+                "valid": true,
+                "stack_result": true
+            }
+        },
+        {
+            "id": "p2qrh_multisig_address_handling",
+            "objective": "Test the creation and validation of multisig P2QRH addresses",
+            "given": {
+                "threshold": 3,
+                "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074",
+                "publicKey": "6fe991c97f0094b2fb636ab4951878f239e2871c3cfdc2936230dac5dde8441d3ff41704025260c25b7e44416142778452694110793465d38ff66244a87aaacaf38103adde0dcf2f6056d48fcc43da9483ce6cfdd96ba2159b2f9653d24fe1f280c924db81830abe6d1070e5b32d2cf373c67dade4bd7c02bb6f5e76ff934316",
+                "publicKey": "768a54113541212e258a8d24f912f61fcb3f40e6967570ba0ea35d8023e965d2"
+            },
+            "intermediary": {
+                "concatenated": "xxxx",
+                "commitment": "yyyy",
+                "scriptPubKey": "OP_3  OP_EQUAL"
+            },
+            "expected": {
+                "valid": true,
+                "address": "qrh1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"
+            }
+        },
+        {
+            "id": "p2qrh_encoding_and_decoding_integrtiy",
+            "objective": "Verify that encoding and decoding processes for P2QRH addresses are lossless and accurate",
+            "given": {
+                "threshold": 2,
+                "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074",
+                "publicKey": "6fe991c97f0094b2fb636ab4951878f239e2871c3cfdc2936230dac5dde8441d3ff41704025260c25b7e44416142778452694110793465d38ff66244a87aaacaf38103adde0dcf2f6056d48fcc43da9483ce6cfdd96ba2159b2f9653d24fe1f280c924db81830abe6d1070e5b32d2cf373c67dade4bd7c02bb6f5e76ff934316",
+                "address": "qrh1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"
+            },
+            "intermediary": {
+                "decoded_data": "xxxx",
+                "reencoded_address": "qrh1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"
+            },
+            "expected": {
+                "valid": true,
+                "matches_original": true
+            }
+        },
+        {
+            "id": "p2qrh_checksum_validation",
+            "objective": "confirm that the checksum mechanism detects errors in p2qrh addresses",
+            "given": {
+                "valid_address": "qrh1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",
+                "corrupted_addresses": [
+                    "qrh1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5",
+                    "qrh1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t3",
+                    "qrh2qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"
+                ]
+            },
+            "intermediary": {
+                "checksum_calculations": ["xxxx", "yyyy", "zzzz"]
+            },
+            "expected": {
+                "valid_address_check": true,
+                "corrupted_addresses_check": [false, false, false],
+                "error": "Invalid checksum"
+            }
+        },
+        {
+            "id": "p2qrh_utxo_serialization_compatibility",
+            "objective": "ensure (de)serializer functionality supports p2qrh utxos",
+            "given": {
+                "utxo": {
+                    "txid": "0000000000000000000000000000000000000000000000000000000000000000",
+                    "vout": 0,
+                    "amount": 100000000,
+                    "height": 1000000,
+                    "scriptPubKey": "5220zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz87"
+                }
+            },
+            "intermediary": {
+                "serialized": "xxxx",
+                "deserialized": {
+                    "txid": "0000000000000000000000000000000000000000000000000000000000000000",
+                    "vout": 0,
+                    "amount": 100000000,
+                    "height": 1000000,
+                    "scriptPubKey": "5220zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz87"
+                }
+            },
+            "expected": {
+                "valid": true,
+                "matches_original": true
+            }
+        }
+    ]
+}
diff --git a/bip-0360/ref-impl/tests/data/bip-0360/test_vectors.json b/bip-0360/ref-impl/tests/data/bip-0360/test_vectors.json
new file mode 100644
index 0000000000..1dbc86484a
--- /dev/null
+++ b/bip-0360/ref-impl/tests/data/bip-0360/test_vectors.json
@@ -0,0 +1,193 @@
+{
+    "version": 1,
+    "test_vectors": [
+        {
+            "id": "p2qrh_missing_leaf_script_tree_error",
+            "objective": "Tests P2QRH with missing leaf script tree",
+            "given": {
+                "script_tree": ""
+            },
+            "intermediary": {
+            },
+            "expected": {
+                "error": "P2QRH requires a script tree with at least one leaf"
+            }
+        },
+        {
+            "id": "p2qrh_single_leaf_script_tree",
+            "objective": "Tests P2QRH with single leaf script tree",
+            "given": {
+                "scriptTree": {
+                    "id": 0,
+                    "script": "20b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007ac",
+                    "leafVersion": 192
+                }
+            },
+            "intermediary": {
+                "leafHashes": [
+                    "c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b"
+                ],
+                "merkleRoot": "c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b"
+            },
+            "expected": {
+                "scriptPubKey": "532020c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b",
+                "bip350Address": "bc1rc5jhzjnlf8pg4mdmhfuvqpvnr2quyd9j7mye5uly6psg9twghu4s0glfcg",
+                "scriptPathControlBlocks": [
+                    "c0"
+                ]
+            }
+        },
+        {
+            "id": "p2qrh_different_version_leaves",
+            "objective": "Tests P2QRH with two script leaves of different versions",
+            "given": {
+                "scriptTree": [
+                    {
+                        "id": 0,
+                        "script": "20387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48ac",
+                        "leafVersion": 192
+                    },
+                    {
+                        "id": 1,
+                        "script": "06424950333431",
+                        "leafVersion": 250
+                    }
+                ]
+            },
+            "intermediary": {
+                "leafHashes": [
+                    "8ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7",
+                    "f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a"
+                ],
+                "merkleRoot": "6c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef"
+            },
+            "expected": {
+                "scriptPubKey": "5320206c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef",
+                "bip350Address": "bc1rdskuzp4ts94h87ws0c7drmev3sf9dagewj8qsylyahfyqhf800hszs9g88",
+                "scriptPathControlBlocks": [
+                    "c0f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a",
+                    "fa8ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7"
+                ]
+            }
+        },
+        {
+            "id": "p2qrh_two_leaf_same_version",
+            "objective": "Tests P2QRH with two script leaves of same version",
+            "given": {
+                "scriptTree": [
+                    {
+                        "id": 0,
+                        "script": "2044b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fdac",
+                        "leafVersion": 192
+                    },
+                    {
+                        "id": 1,
+                        "script": "07546170726f6f74",
+                        "leafVersion": 192
+                    }
+                ]
+            },
+            "intermediary": {
+                "leafHashes": [
+                    "64512fecdb5afa04f98839b50e6f0cb7b1e539bf6f205f67934083cdcc3c8d89",
+                    "2cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb"
+                ],
+                "merkleRoot": "ab179431c28d3b68fb798957faf5497d69c883c6fb1e1cd9f81483d87bac90cc"
+            },
+            "expected": {
+                "scriptPubKey": "532020ab179431c28d3b68fb798957faf5497d69c883c6fb1e1cd9f81483d87bac90cc",
+                "bip350Address": "bc1r4vtegvwz35ak37me39tl4a2f045u3q7xlv0pek0czjpas7avjrxqapldh6",
+                "scriptPathControlBlocks": [
+                    "c02cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb",
+                    "c064512fecdb5afa04f98839b50e6f0cb7b1e539bf6f205f67934083cdcc3c8d89"
+                ]
+            }
+        },
+        {
+            "id": "p2qrh_three_leaf_complex",
+            "objective": "Tests P2QRH with a complex three-leaf script tree structure, demonstrating nested script paths and multiple verification options",
+            "given": {
+                "internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f",
+                "scriptTree": [
+                    {
+                        "id": 0,
+                        "script": "2072ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69ac",
+                        "leafVersion": 192
+                    },
+                    [
+                        {
+                            "id": 1,
+                            "script": "202352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8ac",
+                            "leafVersion": 192
+                        },
+                        {
+                            "id": 2,
+                            "script": "207337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186aac",
+                            "leafVersion": 192
+                        }
+                    ]
+                ]
+            },
+            "intermediary": {
+                "leafHashes": [
+                    "2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817",
+                    "ba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c",
+                    "9e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf6"
+                ],
+                "merkleRoot": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2"
+            },
+            "expected": {
+                "scriptPubKey": "532020ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2",
+                "bip350Address": "bc1rej7kd3hhar76k3an5jr0t8fgyc47s4lnp4rh8uk4afrlwasuur3qarfta7",
+                "scriptPathControlBlocks": [
+                    "c0ffe578e9ea769027e4f5a3de40732f75a88a6353a09d767ddeb66accef85e553",
+                    "c0ba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817",
+                    "c09e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf62645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817"
+                ]
+            }
+        },
+        {
+            "id": "p2qrh_three_leaf_alternative",
+            "objective": "Tests another variant of P2QRH with three leaves arranged in a different tree structure, showing alternative script path spending options",
+            "given": {
+                "internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d",
+                "scriptTree": [
+                    {
+                        "id": 0,
+                        "script": "2071981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2ac",
+                        "leafVersion": 192
+                    },
+                    [
+                        {
+                            "id": 1,
+                            "script": "20d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748ac",
+                            "leafVersion": 192
+                        },
+                        {
+                            "id": 2,
+                            "script": "20c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4cac",
+                            "leafVersion": 192
+                        }
+                    ]
+                ]
+            },
+            "intermediary": {
+                "leafHashes": [
+                    "f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d",
+                    "737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711",
+                    "d7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7"
+                ],
+                "merkleRoot": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def"
+            },
+            "expected": {
+                "scriptPubKey": "5320202f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def",
+                "bip350Address": "bc1r9a4jc5uhkmtgegvwpx3lq5tpv68layaf3pvz64wx7paatvejnhhsnl669j",
+                "scriptPathControlBlocks": [
+                    "c03cd369a528b326bc9d2133cbd2ac21451acb31681a410434672c8e34fe757e91",
+                    "c0737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d",
+                    "c0d7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d"
+                ]
+            }
+        }
+    ]
+}
diff --git a/bip-0360/ref-impl/tests/descriptor_tests.rs b/bip-0360/ref-impl/tests/descriptor_tests.rs
new file mode 100644
index 0000000000..71d2b885e1
--- /dev/null
+++ b/bip-0360/ref-impl/tests/descriptor_tests.rs
@@ -0,0 +1,35 @@
+use miniscript::descriptor::{Descriptor, DescriptorPublicKey};
+use miniscript::Miniscript;
+use bitcoin::secp256k1::{Secp256k1, PublicKey, XOnlyPublicKey};
+use bitcoin::address::Address;
+use bitcoin::Network;
+use log::{debug, info, error};
+use once_cell::sync::Lazy;
+use anyhow::{anyhow, Result};
+
+use p2qrh_ref::data_structures::{TestVector, TestVectors};
+
+static TEST_VECTORS: Lazy = Lazy::new(|| {
+    let bip360_test_vectors = include_str!("../tests/data/bip-0360/test_vectors.json");
+    let test_vectors: TestVectors = serde_json::from_str(bip360_test_vectors).unwrap();
+    assert_eq!(test_vectors.version, 1);
+    test_vectors
+});
+
+#[test]
+fn test_descriptor_p2qrh() -> anyhow::Result<()> {
+    let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
+
+    let test_vectors = &*TEST_VECTORS;
+
+    let secp = Secp256k1::new();
+    
+    let xonly_pubkey = XOnlyPublicKey::from_slice(&hex::decode("03cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115").unwrap())?;
+
+    // P2TR
+    let p2tr = Descriptor::new_tr(xonly_pubkey, None)?;
+    let p2tr_addr = Address::from_script(&p2tr.script_pubkey(), Network::Bitcoin)?;
+    println!("P2TR: {} (Address: {})", p2tr, p2tr_addr);
+
+    Ok(())
+}
\ No newline at end of file
diff --git a/bip-0360/ref-impl/tests/p2qrh_tests.rs b/bip-0360/ref-impl/tests/p2qrh_tests.rs
new file mode 100644
index 0000000000..c242ffa517
--- /dev/null
+++ b/bip-0360/ref-impl/tests/p2qrh_tests.rs
@@ -0,0 +1,263 @@
+use std::io::Write;
+use std::collections::HashSet;
+use bitcoin::{Address, Network, ScriptBuf, Script};
+use bitcoin::taproot::{LeafVersion, TapTree, ScriptLeaves, TapLeafHash, TaprootMerkleBranch};
+use bitcoin::p2qrh::{P2qrhBuilder, P2qrhScriptBuf, P2qrhControlBlock, P2qrhSpendInfo };
+use bitcoin::hashes::{sha256, Hash};
+use hex;
+use log::debug;
+use once_cell::sync::Lazy;
+
+use p2qrh_ref::data_structures::{TVScriptTree, TestVector, Direction, TestVectors};
+use p2qrh_ref::error::P2QRHError;
+
+//  This file contains tests that execute against the BIP360 script-path-only test vectors.
+
+static TEST_VECTORS: Lazy = Lazy::new(|| {
+    let bip360_test_vectors = include_str!("../tests/data/bip-0360/test_vectors.json");
+    let test_vectors: TestVectors = serde_json::from_str(bip360_test_vectors).unwrap();
+    assert_eq!(test_vectors.version, 1);
+    test_vectors
+});
+
+static P2QRH_MISSING_LEAF_SCRIPT_TREE_ERROR_TEST: &str = "p2qrh_missing_leaf_script_tree_error";
+static P2QRH_SINGLE_LEAF_SCRIPT_TREE_TEST: &str = "p2qrh_single_leaf_script_tree";
+static P2QRH_DIFFERENT_VERSION_LEAVES_TEST: &str = "p2qrh_different_version_leaves";
+static P2QRH_TWO_LEAF_SAME_VERSION_TEST: &str = "p2qrh_two_leaf_same_version";
+static P2QRH_THREE_LEAF_COMPLEX_TEST: &str = "p2qrh_three_leaf_complex";
+static P2QRH_THREE_LEAF_ALTERNATIVE_TEST: &str = "p2qrh_three_leaf_alternative";
+
+// https://learnmeabitcoin.com/technical/upgrades/taproot/#example-2-script-path-spend-simple
+#[test]
+fn test_p2qrh_missing_leaf_script_tree_error() {
+
+    let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
+
+    let test_vectors = &*TEST_VECTORS;
+    let test_vector = test_vectors.test_vector_map.get(P2QRH_MISSING_LEAF_SCRIPT_TREE_ERROR_TEST).unwrap();
+    let test_result: anyhow::Result<()> = process_test_vector_p2qrh(test_vector);
+    assert!(matches!(test_result.unwrap_err().downcast_ref::(),
+        Some(P2QRHError::MissingScriptTreeLeaf)));
+}
+
+// https://learnmeabitcoin.com/technical/upgrades/taproot/#example-2-script-path-spend-simple
+#[test]
+fn test_p2qrh_single_leaf_script_tree() {
+    let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
+
+    let test_vectors = &*TEST_VECTORS;
+    let test_vector = test_vectors.test_vector_map.get(P2QRH_SINGLE_LEAF_SCRIPT_TREE_TEST).unwrap();
+    process_test_vector_p2qrh(test_vector).unwrap();
+}
+
+#[test]
+fn test_p2qrh_different_version_leaves() {
+
+    let test_vectors = &*TEST_VECTORS;
+    let test_vector = test_vectors.test_vector_map.get(P2QRH_DIFFERENT_VERSION_LEAVES_TEST).unwrap();
+    process_test_vector_p2qrh(test_vector).unwrap();
+}
+
+#[test]
+fn test_p2qrh_two_leaf_same_version() {
+
+    let test_vectors = &*TEST_VECTORS;
+    let test_vector = test_vectors.test_vector_map.get(P2QRH_TWO_LEAF_SAME_VERSION_TEST).unwrap();
+    process_test_vector_p2qrh(test_vector).unwrap();
+}
+
+#[test]
+fn test_p2qrh_three_leaf_complex() {
+
+    let test_vectors = &*TEST_VECTORS;
+    let test_vector = test_vectors.test_vector_map.get(P2QRH_THREE_LEAF_COMPLEX_TEST).unwrap();
+    process_test_vector_p2qrh(test_vector).unwrap();
+}
+
+#[test]
+fn test_p2qrh_three_leaf_alternative() {
+
+    let test_vectors = &*TEST_VECTORS;
+    let test_vector = test_vectors.test_vector_map.get(P2QRH_THREE_LEAF_ALTERNATIVE_TEST).unwrap();
+    process_test_vector_p2qrh(test_vector).unwrap();
+}
+
+fn process_test_vector_p2qrh(test_vector: &TestVector) -> anyhow::Result<()> {
+
+    let tv_script_tree: Option<&TVScriptTree> = test_vector.given.script_tree.as_ref();
+
+    let mut tv_leaf_count: u8 = 0;
+    let mut current_branch_id: u8 = 0;
+
+    // TaprootBuilder expects the addition of each leaf script with its associated depth
+    // It then constructs the binary tree in DFS order, sorting siblings lexicographically & combining them via BIP341's tapbranch_hash
+    // Use of TaprootBuilder avoids user error in constructing branches manually and ensures Merkle tree correctness and determinism
+    let mut p2qrh_builder: P2qrhBuilder = P2qrhBuilder::new();
+
+    let mut control_block_data: Vec<(ScriptBuf, LeafVersion)> = Vec::new();
+
+    // 1)  traverse test vector script tree and add leaves to P2QRH builder
+    if let Some(script_tree) = tv_script_tree {
+
+        script_tree.traverse_with_right_subtree_first(0, Direction::Root,&mut |node, depth, direction| {
+
+            if let TVScriptTree::Leaf(tv_leaf) = node {
+                
+                let tv_leaf_script_bytes = hex::decode(&tv_leaf.script).unwrap();
+    
+                // NOTE:  IOT to execute script_info.control_block(..), will add these to a vector
+                let tv_leaf_script_buf = ScriptBuf::from_bytes(tv_leaf_script_bytes.clone());
+                let tv_leaf_version = LeafVersion::from_consensus(tv_leaf.leaf_version).unwrap();
+                control_block_data.push((tv_leaf_script_buf.clone(), tv_leaf_version));
+                
+                let mut modified_depth = depth + 1;
+                if direction == Direction::Root {
+                    modified_depth = depth;
+                }
+                debug!("traverse_with_depth: leaf_count: {}, depth: {}, modified_depth: {}, direction: {}, tv_leaf_script: {}", 
+                    tv_leaf_count, depth, modified_depth, direction, tv_leaf.script);
+                
+                // NOTE: Some of the the test vectors in this project specify leaves with non-standardversions (ie: 250 / 0xfa)
+                p2qrh_builder = p2qrh_builder.clone().add_leaf_with_ver(depth, tv_leaf_script_buf.clone(), tv_leaf_version)
+                    .unwrap_or_else(|e| {
+                        panic!("Failed to add leaf: {:?}", e);
+                    });
+    
+                tv_leaf_count += 1;
+            } else if let TVScriptTree::Branch { left, right } = node {
+                // No need to calculate branch hash.
+                // TaprootBuilder does this for us.
+                debug!("branch_count: {}, depth: {}, direction: {}", current_branch_id, depth, direction);
+                current_branch_id += 1;
+            }
+        });
+    }else {
+        return Err(P2QRHError::MissingScriptTreeLeaf.into());
+    }
+
+    let spend_info: P2qrhSpendInfo = p2qrh_builder.clone()
+        .finalize()
+        .unwrap_or_else(|e| {
+            panic!("finalize failed: {:?}", e);
+        });
+
+    let derived_merkle_root = spend_info.merkle_root.unwrap();
+
+    // 2)  verify derived merkle root against test vector
+    let test_vector_merkle_root = test_vector.intermediary.merkle_root.as_ref().unwrap();
+    assert_eq!( 
+        derived_merkle_root.to_string(),
+        *test_vector_merkle_root, 
+        "Merkle root mismatch"
+    );
+    debug!("just passed merkle root validation: {}", test_vector_merkle_root);
+
+    let test_vector_leaf_hashes_vec: Vec = test_vector.intermediary.leaf_hashes.clone();
+    let test_vector_leaf_hash_set: HashSet = test_vector_leaf_hashes_vec.iter().cloned().collect();
+    let test_vector_control_blocks_vec = &test_vector.expected.script_path_control_blocks;
+    let test_vector_control_blocks_set: HashSet = test_vector_control_blocks_vec.as_ref().unwrap().iter().cloned().collect();
+    let tap_tree: TapTree = p2qrh_builder.clone().into_inner().try_into_taptree().unwrap();
+    let script_leaves: ScriptLeaves = tap_tree.script_leaves();
+
+    // TO-DO:  Investigate why the ordering of script leaves seems to be reverse of test vectors.
+    // 3) Iterate through leaves of derived script tree and verify both script leaf hashes and control blocks
+    for (i, derived_leaf) in script_leaves.enumerate() {
+
+        let version = derived_leaf.version();
+        let script = derived_leaf.script();
+        let merkle_branch: &TaprootMerkleBranch = derived_leaf.merkle_branch();
+
+        let derived_leaf_hash: TapLeafHash = TapLeafHash::from_script(script, version);
+        let leaf_hash = hex::encode(derived_leaf_hash.as_raw_hash().to_byte_array());
+        assert!(
+            test_vector_leaf_hash_set.contains(&leaf_hash),
+            "Leaf hash not found in expected set for {}", leaf_hash
+        );
+        debug!("just passed leaf_hash validation: {}", leaf_hash);
+    
+        // Each leaf in the script tree has a corresponding control block.
+        // The 3 sections of the control block (control byte, public key & merkle path) are highlighted here:
+        //    https://learnmeabitcoin.com/technical/upgrades/taproot/#script-path-spend-control-block
+        // The control block, which includes the Merkle path, must be 33 + 32 * n bytes, where n is the number of Merkle path hashes (n ≥ 0).
+        // There is no consensus limit on n, but large Merkle trees increase the witness size, impacting block weight.
+        // NOTE:  Control blocks could have also been obtained from spend_info.control_block(..) using the data in control_block_data
+        debug!("merkle_branch nodes: {:?}", merkle_branch);
+        let derived_control_block: P2qrhControlBlock = P2qrhControlBlock{
+            leaf_version: derived_leaf.version(),
+            merkle_branch: merkle_branch.clone(),
+        };
+        let serialized_control_block = derived_control_block.serialize();
+        debug!("derived_control_block: {:?}, merkle_branch size: {}, control_block size: {}, serialized size: {}", 
+            derived_control_block,
+            merkle_branch.len(),
+            derived_control_block.size(),
+            serialized_control_block.len());
+        let derived_serialized_control_block = hex::encode(serialized_control_block);
+        assert!(
+            test_vector_control_blocks_set.contains(&derived_serialized_control_block),
+            "Control block mismatch: {}, expected: {:?}", derived_serialized_control_block, test_vector_control_blocks_set
+        );
+        debug!("leaf_hash: {}, derived_serialized_control_block: {}", leaf_hash, derived_serialized_control_block);
+
+    }
+
+    /* commit (in scriptPubKey) to the merkle root of all the script path leaves. ie:
+        This output key is what gets committed to in the final Taproot address (ie: scriptPubKey)
+    */
+    let script_buf: P2qrhScriptBuf = P2qrhScriptBuf::new_p2qrh(derived_merkle_root);
+    let script: &Script = script_buf.as_script();
+    let script_pubkey = script.to_hex_string();
+    assert_eq!(script_pubkey, *test_vector.expected.script_pubkey.as_ref().unwrap());
+
+    // 4)  derive bech32m address and verify against test vector
+    let bech32m_address = Address::p2qrh(Some(derived_merkle_root), Network::Bitcoin);
+    assert_eq!(bech32m_address.to_string(), *test_vector.expected.bip350_address.as_ref().unwrap(), "Bech32m address mismatch.");
+
+    Ok(())
+}
+
+// https://learnmeabitcoin.com/technical/upgrades/taproot/#examples
+fn tagged_hash(tag: &str, data: &[u8]) -> String {
+
+    // Create a hash of the tag first
+    let tag_hash = sha256::Hash::hash(tag.as_bytes());
+
+    // Create preimage:  tag_hash || tag_hash || message
+    // tag_hash is prefixed twice so that the prefix is 64 bytes in total
+    let mut preimage = sha256::Hash::engine();
+    preimage.write_all(&tag_hash.to_byte_array());  // First tag hash
+    preimage.write_all(&tag_hash.to_byte_array());  // Second tag hash
+    preimage.write_all(data);       // Message data
+    let hash = sha256::Hash::from_engine(preimage).to_byte_array();
+    hex::encode(hash)
+}
+
+fn serialize_script(script: &Vec) -> Vec {
+    // get length of script as number of bytes
+    let length = script.len();
+
+    // return script with compact size prepended
+    let mut result = compact_size(length as u64);
+    result.extend_from_slice(&script);
+    result
+}
+
+/// Encodes an integer into Bitcoin's compact size format
+/// Returns a Vec containing the encoded bytes
+fn compact_size(n: u64) -> Vec {
+    if n <= 252 {
+        vec![n as u8]
+    } else if n <= 0xffff {
+        let mut result = vec![0xfd];
+        result.extend_from_slice(&(n as u16).to_le_bytes());
+        result
+    } else if n <= 0xffffffff {
+        let mut result = vec![0xfe];
+        result.extend_from_slice(&(n as u32).to_le_bytes());
+        result
+    } else {
+        let mut result = vec![0xff];
+        result.extend_from_slice(&n.to_le_bytes());
+        result
+    }
+}
\ No newline at end of file

From dc044da2eea0e835d2e553dd9d98aba339da3ed4 Mon Sep 17 00:00:00 2001
From: jbride 
Date: Mon, 16 Jun 2025 16:09:52 -0600
Subject: [PATCH 045/131] p2qrh; fixes:

P2QRHScriptBuf.new_p2qrh(...) function is generating a scriptPubKey value with with back-to-back duplicate OP_PUSHBYTES_32 opcode.

https://github.com/jbride/bips/issues/6
https://github.com/jbride/rust-bitcoin/issues/1
---
 .../ref-impl/tests/data/bip-0360/test_vectors.json     | 10 +++++-----
 bip-0360/ref-impl/tests/p2qrh_tests.rs                 |  1 +
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/bip-0360/ref-impl/tests/data/bip-0360/test_vectors.json b/bip-0360/ref-impl/tests/data/bip-0360/test_vectors.json
index 1dbc86484a..d4cea1d40a 100644
--- a/bip-0360/ref-impl/tests/data/bip-0360/test_vectors.json
+++ b/bip-0360/ref-impl/tests/data/bip-0360/test_vectors.json
@@ -30,7 +30,7 @@
                 "merkleRoot": "c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b"
             },
             "expected": {
-                "scriptPubKey": "532020c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b",
+                "scriptPubKey": "5320c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b",
                 "bip350Address": "bc1rc5jhzjnlf8pg4mdmhfuvqpvnr2quyd9j7mye5uly6psg9twghu4s0glfcg",
                 "scriptPathControlBlocks": [
                     "c0"
@@ -62,7 +62,7 @@
                 "merkleRoot": "6c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef"
             },
             "expected": {
-                "scriptPubKey": "5320206c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef",
+                "scriptPubKey": "53206c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef",
                 "bip350Address": "bc1rdskuzp4ts94h87ws0c7drmev3sf9dagewj8qsylyahfyqhf800hszs9g88",
                 "scriptPathControlBlocks": [
                     "c0f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a",
@@ -95,7 +95,7 @@
                 "merkleRoot": "ab179431c28d3b68fb798957faf5497d69c883c6fb1e1cd9f81483d87bac90cc"
             },
             "expected": {
-                "scriptPubKey": "532020ab179431c28d3b68fb798957faf5497d69c883c6fb1e1cd9f81483d87bac90cc",
+                "scriptPubKey": "5320ab179431c28d3b68fb798957faf5497d69c883c6fb1e1cd9f81483d87bac90cc",
                 "bip350Address": "bc1r4vtegvwz35ak37me39tl4a2f045u3q7xlv0pek0czjpas7avjrxqapldh6",
                 "scriptPathControlBlocks": [
                     "c02cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb",
@@ -137,7 +137,7 @@
                 "merkleRoot": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2"
             },
             "expected": {
-                "scriptPubKey": "532020ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2",
+                "scriptPubKey": "5320ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2",
                 "bip350Address": "bc1rej7kd3hhar76k3an5jr0t8fgyc47s4lnp4rh8uk4afrlwasuur3qarfta7",
                 "scriptPathControlBlocks": [
                     "c0ffe578e9ea769027e4f5a3de40732f75a88a6353a09d767ddeb66accef85e553",
@@ -180,7 +180,7 @@
                 "merkleRoot": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def"
             },
             "expected": {
-                "scriptPubKey": "5320202f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def",
+                "scriptPubKey": "53202f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def",
                 "bip350Address": "bc1r9a4jc5uhkmtgegvwpx3lq5tpv68layaf3pvz64wx7paatvejnhhsnl669j",
                 "scriptPathControlBlocks": [
                     "c03cd369a528b326bc9d2133cbd2ac21451acb31681a410434672c8e34fe757e91",
diff --git a/bip-0360/ref-impl/tests/p2qrh_tests.rs b/bip-0360/ref-impl/tests/p2qrh_tests.rs
index c242ffa517..b0b492c4ee 100644
--- a/bip-0360/ref-impl/tests/p2qrh_tests.rs
+++ b/bip-0360/ref-impl/tests/p2qrh_tests.rs
@@ -208,6 +208,7 @@ fn process_test_vector_p2qrh(test_vector: &TestVector) -> anyhow::Result<()> {
     let script: &Script = script_buf.as_script();
     let script_pubkey = script.to_hex_string();
     assert_eq!(script_pubkey, *test_vector.expected.script_pubkey.as_ref().unwrap());
+    debug!("just passed script_pubkey validation. script_pubkey = {}", script_pubkey);
 
     // 4)  derive bech32m address and verify against test vector
     let bech32m_address = Address::p2qrh(Some(derived_merkle_root), Network::Bitcoin);

From 3751cb2434431ac546ca4bee9aa07f9f186ff88b Mon Sep 17 00:00:00 2001
From: jbride 
Date: Thu, 19 Jun 2025 11:24:54 -0600
Subject: [PATCH 046/131] p2qrh: enabling serde and rand features of bitcoin
 crate

---
 bip-0360/ref-impl/Cargo.lock           | 96 ++++++++++++++++++++++++++
 bip-0360/ref-impl/Cargo.toml           |  2 +-
 bip-0360/ref-impl/tests/p2qrh_tests.rs |  5 +-
 3 files changed, 101 insertions(+), 2 deletions(-)

diff --git a/bip-0360/ref-impl/Cargo.lock b/bip-0360/ref-impl/Cargo.lock
index e0ca886de3..b24393d0e9 100644
--- a/bip-0360/ref-impl/Cargo.lock
+++ b/bip-0360/ref-impl/Cargo.lock
@@ -102,6 +102,7 @@ dependencies = [
  "hex-conservative",
  "hex_lit",
  "secp256k1",
+ "serde",
 ]
 
 [[package]]
@@ -109,6 +110,9 @@ name = "bitcoin-internals"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2"
+dependencies = [
+ "serde",
+]
 
 [[package]]
 name = "bitcoin-io"
@@ -123,6 +127,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2"
 dependencies = [
  "bitcoin-internals",
+ "serde",
 ]
 
 [[package]]
@@ -133,6 +138,7 @@ checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16"
 dependencies = [
  "bitcoin-io",
  "hex-conservative",
+ "serde",
 ]
 
 [[package]]
@@ -144,6 +150,12 @@ dependencies = [
  "shlex",
 ]
 
+[[package]]
+name = "cfg-if"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
+
 [[package]]
 name = "colorchoice"
 version = "1.0.4"
@@ -173,6 +185,17 @@ dependencies = [
  "log",
 ]
 
+[[package]]
+name = "getrandom"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
 [[package]]
 name = "hex"
 version = "0.4.3"
@@ -230,6 +253,12 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "libc"
+version = "0.2.174"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
+
 [[package]]
 name = "log"
 version = "0.4.27"
@@ -293,6 +322,15 @@ dependencies = [
  "portable-atomic",
 ]
 
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
 [[package]]
 name = "proc-macro2"
 version = "1.0.95"
@@ -311,6 +349,36 @@ dependencies = [
  "proc-macro2",
 ]
 
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
 [[package]]
 name = "regex"
 version = "1.11.1"
@@ -353,7 +421,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113"
 dependencies = [
  "bitcoin_hashes",
+ "rand",
  "secp256k1-sys",
+ "serde",
 ]
 
 [[package]]
@@ -446,6 +516,12 @@ version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
 [[package]]
 name = "windows-sys"
 version = "0.59.0"
@@ -518,3 +594,23 @@ name = "windows_x86_64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "zerocopy"
+version = "0.8.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/bip-0360/ref-impl/Cargo.toml b/bip-0360/ref-impl/Cargo.toml
index ea24ec1b00..80ba13e004 100644
--- a/bip-0360/ref-impl/Cargo.toml
+++ b/bip-0360/ref-impl/Cargo.toml
@@ -9,7 +9,7 @@ edition = "2024"
 miniscript = "13.0.0"
 
 # During local dev, ensure version used here matches the version of the forked local library (referenced in:  patch.crates-io)
-bitcoin = "0.32.6"
+bitcoin = { version="0.32.6", features = ["rand-std", "serde"] }
 
 env_logger = "0.11.5"
 log = "0.4.22"
diff --git a/bip-0360/ref-impl/tests/p2qrh_tests.rs b/bip-0360/ref-impl/tests/p2qrh_tests.rs
index b0b492c4ee..872c9063ba 100644
--- a/bip-0360/ref-impl/tests/p2qrh_tests.rs
+++ b/bip-0360/ref-impl/tests/p2qrh_tests.rs
@@ -211,7 +211,10 @@ fn process_test_vector_p2qrh(test_vector: &TestVector) -> anyhow::Result<()> {
     debug!("just passed script_pubkey validation. script_pubkey = {}", script_pubkey);
 
     // 4)  derive bech32m address and verify against test vector
+    //     p2qrh adress is comprised of network HRP + WitnessProgram (version + program)
     let bech32m_address = Address::p2qrh(Some(derived_merkle_root), Network::Bitcoin);
+    //let bech32m_address = Address::p2qrh(Some(derived_merkle_root), Network::Regtest);
+
     assert_eq!(bech32m_address.to_string(), *test_vector.expected.bip350_address.as_ref().unwrap(), "Bech32m address mismatch.");
 
     Ok(())
@@ -261,4 +264,4 @@ fn compact_size(n: u64) -> Vec {
         result.extend_from_slice(&n.to_le_bytes());
         result
     }
-}
\ No newline at end of file
+}

From 458d2e64d41d5397e6d3bd6cee15aaaad970c393 Mon Sep 17 00:00:00 2001
From: jbride 
Date: Thu, 19 Jun 2025 11:35:42 -0600
Subject: [PATCH 047/131] p2qrh: change name of test to reflect current focus
 on construction of p2qrh utxos

---
 .../{test_vectors.json => p2qrh_construction.json}        | 0
 bip-0360/ref-impl/tests/descriptor_tests.rs               | 2 +-
 .../tests/{p2qrh_tests.rs => p2qrh_construction.rs}       | 8 ++++----
 3 files changed, 5 insertions(+), 5 deletions(-)
 rename bip-0360/ref-impl/tests/data/bip-0360/{test_vectors.json => p2qrh_construction.json} (100%)
 rename bip-0360/ref-impl/tests/{p2qrh_tests.rs => p2qrh_construction.rs} (98%)

diff --git a/bip-0360/ref-impl/tests/data/bip-0360/test_vectors.json b/bip-0360/ref-impl/tests/data/bip-0360/p2qrh_construction.json
similarity index 100%
rename from bip-0360/ref-impl/tests/data/bip-0360/test_vectors.json
rename to bip-0360/ref-impl/tests/data/bip-0360/p2qrh_construction.json
diff --git a/bip-0360/ref-impl/tests/descriptor_tests.rs b/bip-0360/ref-impl/tests/descriptor_tests.rs
index 71d2b885e1..1947195881 100644
--- a/bip-0360/ref-impl/tests/descriptor_tests.rs
+++ b/bip-0360/ref-impl/tests/descriptor_tests.rs
@@ -10,7 +10,7 @@ use anyhow::{anyhow, Result};
 use p2qrh_ref::data_structures::{TestVector, TestVectors};
 
 static TEST_VECTORS: Lazy = Lazy::new(|| {
-    let bip360_test_vectors = include_str!("../tests/data/bip-0360/test_vectors.json");
+    let bip360_test_vectors = include_str!("../tests/data/bip-0360/p2qrh_construction.json");
     let test_vectors: TestVectors = serde_json::from_str(bip360_test_vectors).unwrap();
     assert_eq!(test_vectors.version, 1);
     test_vectors
diff --git a/bip-0360/ref-impl/tests/p2qrh_tests.rs b/bip-0360/ref-impl/tests/p2qrh_construction.rs
similarity index 98%
rename from bip-0360/ref-impl/tests/p2qrh_tests.rs
rename to bip-0360/ref-impl/tests/p2qrh_construction.rs
index 872c9063ba..9931a056bf 100644
--- a/bip-0360/ref-impl/tests/p2qrh_tests.rs
+++ b/bip-0360/ref-impl/tests/p2qrh_construction.rs
@@ -14,7 +14,7 @@ use p2qrh_ref::error::P2QRHError;
 //  This file contains tests that execute against the BIP360 script-path-only test vectors.
 
 static TEST_VECTORS: Lazy = Lazy::new(|| {
-    let bip360_test_vectors = include_str!("../tests/data/bip-0360/test_vectors.json");
+    let bip360_test_vectors = include_str!("../tests/data/bip-0360/p2qrh_construction.json");
     let test_vectors: TestVectors = serde_json::from_str(bip360_test_vectors).unwrap();
     assert_eq!(test_vectors.version, 1);
     test_vectors
@@ -229,9 +229,9 @@ fn tagged_hash(tag: &str, data: &[u8]) -> String {
     // Create preimage:  tag_hash || tag_hash || message
     // tag_hash is prefixed twice so that the prefix is 64 bytes in total
     let mut preimage = sha256::Hash::engine();
-    preimage.write_all(&tag_hash.to_byte_array());  // First tag hash
-    preimage.write_all(&tag_hash.to_byte_array());  // Second tag hash
-    preimage.write_all(data);       // Message data
+    preimage.write_all(&tag_hash.to_byte_array()).unwrap();  // First tag hash
+    preimage.write_all(&tag_hash.to_byte_array()).unwrap();  // Second tag hash
+    preimage.write_all(data).unwrap();       // Message data
     let hash = sha256::Hash::from_engine(preimage).to_byte_array();
     hex::encode(hash)
 }

From e4aae538315528bf9db5877b81bc8047a995c08e Mon Sep 17 00:00:00 2001
From: jbride 
Date: Thu, 19 Jun 2025 15:31:46 -0600
Subject: [PATCH 048/131] p2qrh: initial draft of p2qrh spend related test
 vectors

---
 bip-0360/ref-impl/src/data_structures.rs      | 92 ++++---------------
 bip-0360/ref-impl/src/lib.rs                  | 53 ++++++++++-
 ...escriptors.json => p2qrh_descriptors.json} |  0
 .../tests/data/bip-0360/p2qrh_spend.json      | 20 ++++
 bip-0360/ref-impl/tests/p2qrh_construction.rs | 54 +----------
 ...escriptor_tests.rs => p2qrh_descriptor.rs} |  0
 bip-0360/ref-impl/tests/p2qrh_spend.rs        | 63 +++++++++++++
 7 files changed, 157 insertions(+), 125 deletions(-)
 rename bip-0360/ref-impl/tests/data/bip-0360/{descriptors.json => p2qrh_descriptors.json} (100%)
 create mode 100644 bip-0360/ref-impl/tests/data/bip-0360/p2qrh_spend.json
 rename bip-0360/ref-impl/tests/{descriptor_tests.rs => p2qrh_descriptor.rs} (100%)
 create mode 100644 bip-0360/ref-impl/tests/p2qrh_spend.rs

diff --git a/bip-0360/ref-impl/src/data_structures.rs b/bip-0360/ref-impl/src/data_structures.rs
index fcd6403940..b92b6d1b08 100644
--- a/bip-0360/ref-impl/src/data_structures.rs
+++ b/bip-0360/ref-impl/src/data_structures.rs
@@ -59,10 +59,16 @@ pub struct TestVector {
 
 #[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct TestVectorGiven {
-    #[serde(rename = "internalPubkey")]
-    pub internal_pubkey: Option,
+
     #[serde(rename = "scriptTree")]
     pub script_tree: Option,
+
+    #[serde(rename = "scriptInputs")]
+    pub script_inputs: Option>,
+    #[serde(rename = "scriptHex")]
+    pub script_hex: Option,
+    #[serde(rename = "controlBlock")]
+    pub control_block: Option,
 }
 
 #[derive(Debug, Serialize, Deserialize, Clone)]
@@ -89,6 +95,16 @@ pub struct TestVectorExpected {
     pub error: Option,
     #[serde(rename = "address")]
     pub address: Option,
+    #[serde(default)]
+    pub witness: Option
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct TVScriptLeaf {
+    pub id: u8,
+    pub script: String,
+    #[serde(rename = "leafVersion")]
+    pub leaf_version: u8,
 }
 
 // Taproot script trees are binary trees, so each branch should have exactly two children.
@@ -194,78 +210,6 @@ impl std::fmt::Display for Direction {
     }
 }
 
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct TVScriptLeaf {
-    pub id: u8,
-    pub script: String,
-    #[serde(rename = "leafVersion")]
-    pub leaf_version: u8,
-}
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct TVScriptPubKeyIntermediary {
-    #[serde(default)]
-    #[serde(rename = "leafHashes")]
-    pub leaf_hashes: Vec,
-    #[serde(rename = "merkleRoot")]
-    pub merkle_root: Option
-}
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct TVScriptPubKeyExpected {
-    #[serde(rename = "scriptPubKey")]
-    pub script_pubkey: String,
-    #[serde(rename = "bip350Address")]
-    pub bip350_address: String,
-    #[serde(default)]
-    #[serde(rename = "scriptPathControlBlocks")]
-    pub script_path_control_blocks: Vec,
-}
-
-#[derive(Debug, Serialize, Deserialize)]
-pub struct TVUtxoSpent {
-    #[serde(rename = "scriptPubKey")]
-    pub script_pubkey: String,
-    #[serde(rename = "amountSats")]
-    pub amount_sats: u64,
-}
-
-#[derive(Debug, Serialize, Deserialize)]
-pub struct TVInputSpending {
-    pub given: TVInputSpendingGiven,
-    pub intermediary: TVInputSpendingIntermediary,
-    pub expected: TVInputSpendingExpected,
-}
-
-#[derive(Debug, Serialize, Deserialize)]
-pub struct TVInputSpendingGiven {
-    #[serde(rename = "txinIndex")]
-    pub txin_index: u32,
-    #[serde(rename = "internalPrivkey")]
-    pub internal_privkey: String,
-    #[serde(rename = "merkleRoot")]
-    pub merkle_root: Option,
-    #[serde(rename = "hashType")]
-    pub hash_type: u8,
-}
-
-#[derive(Debug, Serialize, Deserialize)]
-pub struct TVInputSpendingIntermediary {
-    #[serde(rename = "internalPubkey")]
-    pub internal_pubkey: String,
-    #[serde(rename = "sigMsg")]
-    pub sig_msg: String,
-    #[serde(rename = "precomputedUsed")]
-    pub precomputed_used: Vec,
-    #[serde(rename = "sigHash")]
-    pub sig_hash: String,
-}
-
-#[derive(Debug, Serialize, Deserialize)]
-pub struct TVInputSpendingExpected {
-    pub witness: Vec,
-}
-
 pub struct ScriptTreeHashCache {
     pub leaf_hashes: HashMap,
     pub branch_hashes: HashMap,
diff --git a/bip-0360/ref-impl/src/lib.rs b/bip-0360/ref-impl/src/lib.rs
index e9333844cb..fbc00078ca 100644
--- a/bip-0360/ref-impl/src/lib.rs
+++ b/bip-0360/ref-impl/src/lib.rs
@@ -1,2 +1,53 @@
 pub mod data_structures;
-pub mod error;
\ No newline at end of file
+pub mod error;
+
+use std::io::Write;
+use std::collections::HashMap;
+use bitcoin::hashes::{sha256, Hash};
+
+
+// https://learnmeabitcoin.com/technical/upgrades/taproot/#examples
+pub fn tagged_hash(tag: &str, data: &[u8]) -> String {
+
+    // Create a hash of the tag first
+    let tag_hash = sha256::Hash::hash(tag.as_bytes());
+
+    // Create preimage:  tag_hash || tag_hash || message
+    // tag_hash is prefixed twice so that the prefix is 64 bytes in total
+    let mut preimage = sha256::Hash::engine();
+    preimage.write_all(&tag_hash.to_byte_array()).unwrap();  // First tag hash
+    preimage.write_all(&tag_hash.to_byte_array()).unwrap();  // Second tag hash
+    preimage.write_all(data).unwrap();       // Message data
+    let hash = sha256::Hash::from_engine(preimage).to_byte_array();
+    hex::encode(hash)
+}
+
+pub fn serialize_script(script: &Vec) -> Vec {
+    // get length of script as number of bytes
+    let length = script.len();
+
+    // return script with compact size prepended
+    let mut result = compact_size(length as u64);
+    result.extend_from_slice(&script);
+    result
+}
+
+/// Encodes an integer into Bitcoin's compact size format
+/// Returns a Vec containing the encoded bytes
+fn compact_size(n: u64) -> Vec {
+    if n <= 252 {
+        vec![n as u8]
+    } else if n <= 0xffff {
+        let mut result = vec![0xfd];
+        result.extend_from_slice(&(n as u16).to_le_bytes());
+        result
+    } else if n <= 0xffffffff {
+        let mut result = vec![0xfe];
+        result.extend_from_slice(&(n as u32).to_le_bytes());
+        result
+    } else {
+        let mut result = vec![0xff];
+        result.extend_from_slice(&n.to_le_bytes());
+        result
+    }
+}
\ No newline at end of file
diff --git a/bip-0360/ref-impl/tests/data/bip-0360/descriptors.json b/bip-0360/ref-impl/tests/data/bip-0360/p2qrh_descriptors.json
similarity index 100%
rename from bip-0360/ref-impl/tests/data/bip-0360/descriptors.json
rename to bip-0360/ref-impl/tests/data/bip-0360/p2qrh_descriptors.json
diff --git a/bip-0360/ref-impl/tests/data/bip-0360/p2qrh_spend.json b/bip-0360/ref-impl/tests/data/bip-0360/p2qrh_spend.json
new file mode 100644
index 0000000000..cbc0049135
--- /dev/null
+++ b/bip-0360/ref-impl/tests/data/bip-0360/p2qrh_spend.json
@@ -0,0 +1,20 @@
+{
+    "version": 1,
+    "test_vectors": [
+        {
+            "id": "p2qrh_single_leaf_script_tree_no_sigs",
+            "objective": "Tests P2QRH with single trivial script leaf of:  OP_EQUAL OP_3",
+            "given": {
+                "scriptInputs": [
+                    "03"
+                ],
+                "scriptHex" : "8753",
+                "controlBlock": "c0"
+            },
+            "intermediary": { },
+            "expected": {
+                "witness": "038753c0"
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/bip-0360/ref-impl/tests/p2qrh_construction.rs b/bip-0360/ref-impl/tests/p2qrh_construction.rs
index 9931a056bf..23bb708f9e 100644
--- a/bip-0360/ref-impl/tests/p2qrh_construction.rs
+++ b/bip-0360/ref-impl/tests/p2qrh_construction.rs
@@ -1,9 +1,9 @@
-use std::io::Write;
 use std::collections::HashSet;
 use bitcoin::{Address, Network, ScriptBuf, Script};
 use bitcoin::taproot::{LeafVersion, TapTree, ScriptLeaves, TapLeafHash, TaprootMerkleBranch};
 use bitcoin::p2qrh::{P2qrhBuilder, P2qrhScriptBuf, P2qrhControlBlock, P2qrhSpendInfo };
-use bitcoin::hashes::{sha256, Hash};
+use bitcoin::hashes::Hash;
+
 use hex;
 use log::debug;
 use once_cell::sync::Lazy;
@@ -176,7 +176,7 @@ fn process_test_vector_p2qrh(test_vector: &TestVector) -> anyhow::Result<()> {
         debug!("just passed leaf_hash validation: {}", leaf_hash);
     
         // Each leaf in the script tree has a corresponding control block.
-        // The 3 sections of the control block (control byte, public key & merkle path) are highlighted here:
+        // Specific to P2TR, the 3 sections of the control block (control byte, public key & merkle path) are highlighted here:
         //    https://learnmeabitcoin.com/technical/upgrades/taproot/#script-path-spend-control-block
         // The control block, which includes the Merkle path, must be 33 + 32 * n bytes, where n is the number of Merkle path hashes (n ≥ 0).
         // There is no consensus limit on n, but large Merkle trees increase the witness size, impacting block weight.
@@ -218,50 +218,4 @@ fn process_test_vector_p2qrh(test_vector: &TestVector) -> anyhow::Result<()> {
     assert_eq!(bech32m_address.to_string(), *test_vector.expected.bip350_address.as_ref().unwrap(), "Bech32m address mismatch.");
 
     Ok(())
-}
-
-// https://learnmeabitcoin.com/technical/upgrades/taproot/#examples
-fn tagged_hash(tag: &str, data: &[u8]) -> String {
-
-    // Create a hash of the tag first
-    let tag_hash = sha256::Hash::hash(tag.as_bytes());
-
-    // Create preimage:  tag_hash || tag_hash || message
-    // tag_hash is prefixed twice so that the prefix is 64 bytes in total
-    let mut preimage = sha256::Hash::engine();
-    preimage.write_all(&tag_hash.to_byte_array()).unwrap();  // First tag hash
-    preimage.write_all(&tag_hash.to_byte_array()).unwrap();  // Second tag hash
-    preimage.write_all(data).unwrap();       // Message data
-    let hash = sha256::Hash::from_engine(preimage).to_byte_array();
-    hex::encode(hash)
-}
-
-fn serialize_script(script: &Vec) -> Vec {
-    // get length of script as number of bytes
-    let length = script.len();
-
-    // return script with compact size prepended
-    let mut result = compact_size(length as u64);
-    result.extend_from_slice(&script);
-    result
-}
-
-/// Encodes an integer into Bitcoin's compact size format
-/// Returns a Vec containing the encoded bytes
-fn compact_size(n: u64) -> Vec {
-    if n <= 252 {
-        vec![n as u8]
-    } else if n <= 0xffff {
-        let mut result = vec![0xfd];
-        result.extend_from_slice(&(n as u16).to_le_bytes());
-        result
-    } else if n <= 0xffffffff {
-        let mut result = vec![0xfe];
-        result.extend_from_slice(&(n as u32).to_le_bytes());
-        result
-    } else {
-        let mut result = vec![0xff];
-        result.extend_from_slice(&n.to_le_bytes());
-        result
-    }
-}
+}
\ No newline at end of file
diff --git a/bip-0360/ref-impl/tests/descriptor_tests.rs b/bip-0360/ref-impl/tests/p2qrh_descriptor.rs
similarity index 100%
rename from bip-0360/ref-impl/tests/descriptor_tests.rs
rename to bip-0360/ref-impl/tests/p2qrh_descriptor.rs
diff --git a/bip-0360/ref-impl/tests/p2qrh_spend.rs b/bip-0360/ref-impl/tests/p2qrh_spend.rs
new file mode 100644
index 0000000000..17529dd785
--- /dev/null
+++ b/bip-0360/ref-impl/tests/p2qrh_spend.rs
@@ -0,0 +1,63 @@
+use log::debug;
+use once_cell::sync::Lazy;
+
+use bitcoin::blockdata::witness::Witness;
+use bitcoin::ScriptBuf;
+
+use p2qrh_ref::data_structures::{TestVector, TestVectors};
+
+static TEST_VECTORS: Lazy = Lazy::new(|| {
+    let bip360_test_vectors = include_str!("../tests/data/bip-0360/p2qrh_spend.json");
+    let test_vectors: TestVectors = serde_json::from_str(bip360_test_vectors).unwrap();
+    assert_eq!(test_vectors.version, 1);
+    test_vectors
+});
+
+static P2QRH_SINGLE_LEAF_SCRIPT_TREE_NO_SIGS_TEST: &str = "p2qrh_single_leaf_script_tree_no_sigs";
+
+/*  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.
+ */
+
+#[test]
+fn test_p2qrh_single_leaf_script_tree_no_sigs() {
+    let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
+
+    let test_vectors: &TestVectors = &*TEST_VECTORS;
+    let test_vector: &TestVector = test_vectors.test_vector_map.get(P2QRH_SINGLE_LEAF_SCRIPT_TREE_NO_SIGS_TEST).unwrap();
+
+    let mut witness: Witness= Witness::new();
+
+    
+    test_vector.given.script_inputs.as_ref().unwrap().iter().for_each(|tv_script_input| {
+        let script_input_bytes = hex::decode(tv_script_input).unwrap();
+        witness.push(script_input_bytes);
+        
+    });
+
+    // Hint:  use https://learnmeabitcoin.com/technical/script/
+    let tv_script_hex = test_vector.given.script_hex.as_ref().unwrap();
+    let script_buf: ScriptBuf = ScriptBuf::from(hex::decode(tv_script_hex).unwrap());
+    debug!("script asm: {}", script_buf.to_asm_string());
+    witness.push(script_buf.to_bytes());
+
+    let tv_control_block = test_vector.given.control_block.as_ref().unwrap();
+    let control_block_bytes = hex::decode(tv_control_block).unwrap();
+    witness.push(control_block_bytes);
+
+    debug!("witness: {:?}", witness);
+
+    // Concatenate all witness elements into a single hex string
+    let mut witness_hex_string = String::new();
+    for element in witness.iter() {
+        witness_hex_string.push_str(&hex::encode(element));
+    }
+    debug!("witness hex: {}", witness_hex_string);
+
+    let expected_witness = test_vector.expected.witness.as_ref().unwrap();
+    assert_eq!(&witness_hex_string, expected_witness);
+    
+}
+
+
+

From f139a5f2ca5d445beb5cd6478f9b25cd928ef8fe Mon Sep 17 00:00:00 2001
From: jbride 
Date: Thu, 19 Jun 2025 23:14:24 -0600
Subject: [PATCH 049/131] p2qrh: rust-bitcoin modification overview

---
 .../docs/rust_bitcoin_p2pqrh_changes.md       | 166 ++++++++++++++++++
 1 file changed, 166 insertions(+)
 create mode 100644 bip-0360/ref-impl/docs/rust_bitcoin_p2pqrh_changes.md

diff --git a/bip-0360/ref-impl/docs/rust_bitcoin_p2pqrh_changes.md b/bip-0360/ref-impl/docs/rust_bitcoin_p2pqrh_changes.md
new file mode 100644
index 0000000000..545bd7bbe7
--- /dev/null
+++ b/bip-0360/ref-impl/docs/rust_bitcoin_p2pqrh_changes.md
@@ -0,0 +1,166 @@
+*P2QRH specific changes to rust-bitcoin*
+
+# 1. p2qrh module
+
+The p2qrh branch of rust-bitcoin includes a new module: `p2qrh`.
+
+Source code for this new module can be found [here](https://github.com/jbride/rust-bitcoin/blob/p2qrh/bitcoin/src/p2qrh/mod.rs).
+
+Highlights of this _p2qrh_ module as follows:
+
+## 1.1. P2qrhBuilder
+
+This is struct inherits from the rust-bitcoin _TaprootBuilder_.
+It has an important modification in that it disables keypath spend.
+
+Similar to its Taproot parent, P2qrhBuilder provides functionality to add leaves to a TapTree.
+One its TapTree has been fully populated with all leaves, an instance of _P2qrhSpendInfo_ can be retrieved from P2qrhBuilder.
+
+
+```
+pub struct P2qrhBuilder {
+    inner: TaprootBuilder
+}
+
+impl P2qrhBuilder {
+
+    /// Creates a new P2QRH builder.
+    pub fn new() -> Self {
+        Self {
+            inner: TaprootBuilder::new()
+        }
+    }
+
+    /// Adds a leaf to the P2QRH builder.
+    pub fn add_leaf_with_ver(
+        self,
+        depth: u8,
+        script: ScriptBuf,
+        leaf_version: LeafVersion,
+    ) -> Result {
+        match self.inner.add_leaf_with_ver(depth, script, leaf_version) {
+            Ok(builder) => Ok(Self { inner: builder }),
+            Err(_) => Err(P2qrhError::LeafAdditionError)
+        }
+    }
+
+    /// Finalizes the P2QRH builder.
+    pub fn finalize(self) -> Result {
+        let node_info: NodeInfo = self.inner.try_into_node_info().unwrap();
+        Ok(P2qrhSpendInfo {
+            merkle_root: Some(node_info.node_hash()),
+            //script_map: self.inner.script_map().clone(),
+        })
+    }
+
+    /// Converts the P2QRH builder into a Taproot builder.
+    pub fn into_inner(self) -> TaprootBuilder {
+        self.inner
+    }
+}
+```
+
+##  1.2. P2qrhSpendInfo
+
+Provides merkle_root of a completed P2qrh TapTree
+
+```
+/// A struct for P2QRH spend information.
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct P2qrhSpendInfo {
+
+    /// The merkle root of the script path.
+    pub merkle_root: Option
+
+}
+```
+
+## 1.3. P2qrhScriptBuf
+
+Allows for creation of a P2QRH scriptPubKey UTXO using only the merkle root of a script tree only.
+
+```
+/// A wrapper around ScriptBuf for P2QRH (Pay to Quantum Resistant Hash) scripts.
+pub struct P2qrhScriptBuf {
+    inner: ScriptBuf
+}
+
+impl P2qrhScriptBuf {
+    /// Creates a new P2QRH script from a ScriptBuf.
+    pub fn new(inner: ScriptBuf) -> Self {
+        Self { inner }
+    }
+    
+    /// Generates P2QRH scriptPubKey output
+    /// Only accepts the merkle_root (of type TapNodeHash)
+    /// since keypath spend is disabled in p2qrh
+    pub fn new_p2qrh(merkle_root: TapNodeHash) -> Self {
+        // https://github.com/cryptoquick/bips/blob/p2qrh/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();
+        P2qrhScriptBuf::new(script)
+    }
+
+    /// Returns the script as a reference.
+    pub fn as_script(&self) -> &Script {
+        self.inner.as_script()
+    }
+}
+```
+
+## 1.4. P2QRH Control Block
+
+Closely related to P2TR control block.
+Difference being that _internal public key_ is not included.
+
+
+```
+/// A control block for P2QRH (Pay to Quantum Resistant Hash) script path spending.
+/// This is a simplified version of Taproot's control block that excludes key-related fields.
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct P2qrhControlBlock {
+    /// The version of the leaf.
+    pub leaf_version: LeafVersion,
+    /// The merkle branch of the leaf.
+    pub merkle_branch: TaprootMerkleBranch,
+}
+```
+
+# 2. Witness Program
+
+New p2qrh related functions that allow for creation of a new V3 _witness program_ given a merkle_root only.
+
+Found in bitcoin/src/blockdata/script/witness_program.rs
+
+```
+/// Creates a [`WitnessProgram`] from a 32 byte merkle root.
+fn new_p2qrh(program: [u8; 32]) -> Self {
+    WitnessProgram { version: WitnessVersion::V3, program: ArrayVec::from_slice(&program) }
+}
+
+/// Creates a [`WitnessProgram`] from `pk` for a P2WPKH output.
+pub fn p2wpkh(pk: &CompressedPublicKey) -> Self {
+    let hash = pk.wpubkey_hash();
+    WitnessProgram::new_p2wpkh(hash.to_byte_array())
+}
+```
+
+# 3. Address
+
+New _p2qrh_ function that allows for creation of a new _p2qrh_ Address given a merkle_root only.
+
+Found in bitcoin/src/address/mod.rs
+
+```
+/// Creates a pay to quantum resistant hash address from a merkle root.
+pub fn p2qrh(merkle_root: Option, hrp: impl Into) -> Address {
+    let program = WitnessProgram::p2qrh(merkle_root);
+    Address::from_witness_program(program, hrp)
+}
+```
\ No newline at end of file

From f7d2931e6a6f15406736525ca7c117cc6a3a3d54 Mon Sep 17 00:00:00 2001
From: jbride 
Date: Fri, 20 Jun 2025 10:43:28 -0600
Subject: [PATCH 050/131] p2qrh: moving location of test vector data

---
 .../tests/data/{bip-0360 => }/p2qrh_construction.json         | 0
 .../ref-impl/tests/data/{bip-0360 => }/p2qrh_descriptors.json | 0
 bip-0360/ref-impl/tests/data/{bip-0360 => }/p2qrh_spend.json  | 0
 bip-0360/ref-impl/tests/p2qrh_construction.rs                 | 4 ++--
 bip-0360/ref-impl/tests/p2qrh_descriptor.rs                   | 4 ++--
 bip-0360/ref-impl/tests/p2qrh_spend.rs                        | 2 +-
 6 files changed, 5 insertions(+), 5 deletions(-)
 rename bip-0360/ref-impl/tests/data/{bip-0360 => }/p2qrh_construction.json (100%)
 rename bip-0360/ref-impl/tests/data/{bip-0360 => }/p2qrh_descriptors.json (100%)
 rename bip-0360/ref-impl/tests/data/{bip-0360 => }/p2qrh_spend.json (100%)

diff --git a/bip-0360/ref-impl/tests/data/bip-0360/p2qrh_construction.json b/bip-0360/ref-impl/tests/data/p2qrh_construction.json
similarity index 100%
rename from bip-0360/ref-impl/tests/data/bip-0360/p2qrh_construction.json
rename to bip-0360/ref-impl/tests/data/p2qrh_construction.json
diff --git a/bip-0360/ref-impl/tests/data/bip-0360/p2qrh_descriptors.json b/bip-0360/ref-impl/tests/data/p2qrh_descriptors.json
similarity index 100%
rename from bip-0360/ref-impl/tests/data/bip-0360/p2qrh_descriptors.json
rename to bip-0360/ref-impl/tests/data/p2qrh_descriptors.json
diff --git a/bip-0360/ref-impl/tests/data/bip-0360/p2qrh_spend.json b/bip-0360/ref-impl/tests/data/p2qrh_spend.json
similarity index 100%
rename from bip-0360/ref-impl/tests/data/bip-0360/p2qrh_spend.json
rename to bip-0360/ref-impl/tests/data/p2qrh_spend.json
diff --git a/bip-0360/ref-impl/tests/p2qrh_construction.rs b/bip-0360/ref-impl/tests/p2qrh_construction.rs
index 23bb708f9e..ff28ed0187 100644
--- a/bip-0360/ref-impl/tests/p2qrh_construction.rs
+++ b/bip-0360/ref-impl/tests/p2qrh_construction.rs
@@ -14,7 +14,7 @@ use p2qrh_ref::error::P2QRHError;
 //  This file contains tests that execute against the BIP360 script-path-only test vectors.
 
 static TEST_VECTORS: Lazy = Lazy::new(|| {
-    let bip360_test_vectors = include_str!("../tests/data/bip-0360/p2qrh_construction.json");
+    let bip360_test_vectors = include_str!("../tests/data/p2qrh_construction.json");
     let test_vectors: TestVectors = serde_json::from_str(bip360_test_vectors).unwrap();
     assert_eq!(test_vectors.version, 1);
     test_vectors
@@ -218,4 +218,4 @@ fn process_test_vector_p2qrh(test_vector: &TestVector) -> anyhow::Result<()> {
     assert_eq!(bech32m_address.to_string(), *test_vector.expected.bip350_address.as_ref().unwrap(), "Bech32m address mismatch.");
 
     Ok(())
-}
\ No newline at end of file
+}
diff --git a/bip-0360/ref-impl/tests/p2qrh_descriptor.rs b/bip-0360/ref-impl/tests/p2qrh_descriptor.rs
index 1947195881..9832d9d150 100644
--- a/bip-0360/ref-impl/tests/p2qrh_descriptor.rs
+++ b/bip-0360/ref-impl/tests/p2qrh_descriptor.rs
@@ -10,7 +10,7 @@ use anyhow::{anyhow, Result};
 use p2qrh_ref::data_structures::{TestVector, TestVectors};
 
 static TEST_VECTORS: Lazy = Lazy::new(|| {
-    let bip360_test_vectors = include_str!("../tests/data/bip-0360/p2qrh_construction.json");
+    let bip360_test_vectors = include_str!("../tests/data/p2qrh_descriptors.json");
     let test_vectors: TestVectors = serde_json::from_str(bip360_test_vectors).unwrap();
     assert_eq!(test_vectors.version, 1);
     test_vectors
@@ -32,4 +32,4 @@ fn test_descriptor_p2qrh() -> anyhow::Result<()> {
     println!("P2TR: {} (Address: {})", p2tr, p2tr_addr);
 
     Ok(())
-}
\ No newline at end of file
+}
diff --git a/bip-0360/ref-impl/tests/p2qrh_spend.rs b/bip-0360/ref-impl/tests/p2qrh_spend.rs
index 17529dd785..d4b149c10c 100644
--- a/bip-0360/ref-impl/tests/p2qrh_spend.rs
+++ b/bip-0360/ref-impl/tests/p2qrh_spend.rs
@@ -7,7 +7,7 @@ use bitcoin::ScriptBuf;
 use p2qrh_ref::data_structures::{TestVector, TestVectors};
 
 static TEST_VECTORS: Lazy = Lazy::new(|| {
-    let bip360_test_vectors = include_str!("../tests/data/bip-0360/p2qrh_spend.json");
+    let bip360_test_vectors = include_str!("../tests/data/p2qrh_spend.json");
     let test_vectors: TestVectors = serde_json::from_str(bip360_test_vectors).unwrap();
     assert_eq!(test_vectors.version, 1);
     test_vectors

From a6c64490a51ca66a1575898683870122602cda3e Mon Sep 17 00:00:00 2001
From: jbride 
Date: Sat, 21 Jun 2025 12:12:45 -0600
Subject: [PATCH 051/131] p2qrh: separating rust from python test vectors

---
 bip-0360/ref-impl/python/.gitignore           | 129 ++++++++++++++++++
 bip-0360/ref-impl/{ => rust}/Cargo.lock       |   0
 bip-0360/ref-impl/{ => rust}/Cargo.toml       |   0
 bip-0360/ref-impl/{ => rust}/README.md        |   0
 .../docs/rust_bitcoin_p2pqrh_changes.md       |   0
 .../{ => rust}/src/data_structures.rs         |   0
 bip-0360/ref-impl/{ => rust}/src/error.rs     |   0
 bip-0360/ref-impl/{ => rust}/src/lib.rs       |   0
 .../tests/data/p2qrh_construction.json        |   0
 .../tests/data/p2qrh_descriptors.json         |   0
 .../{ => rust}/tests/data/p2qrh_spend.json    |   0
 .../{ => rust}/tests/p2qrh_construction.rs    |   0
 .../{ => rust}/tests/p2qrh_descriptor.rs      |   0
 .../ref-impl/{ => rust}/tests/p2qrh_spend.rs  |   0
 14 files changed, 129 insertions(+)
 create mode 100644 bip-0360/ref-impl/python/.gitignore
 rename bip-0360/ref-impl/{ => rust}/Cargo.lock (100%)
 rename bip-0360/ref-impl/{ => rust}/Cargo.toml (100%)
 rename bip-0360/ref-impl/{ => rust}/README.md (100%)
 rename bip-0360/ref-impl/{ => rust}/docs/rust_bitcoin_p2pqrh_changes.md (100%)
 rename bip-0360/ref-impl/{ => rust}/src/data_structures.rs (100%)
 rename bip-0360/ref-impl/{ => rust}/src/error.rs (100%)
 rename bip-0360/ref-impl/{ => rust}/src/lib.rs (100%)
 rename bip-0360/ref-impl/{ => rust}/tests/data/p2qrh_construction.json (100%)
 rename bip-0360/ref-impl/{ => rust}/tests/data/p2qrh_descriptors.json (100%)
 rename bip-0360/ref-impl/{ => rust}/tests/data/p2qrh_spend.json (100%)
 rename bip-0360/ref-impl/{ => rust}/tests/p2qrh_construction.rs (100%)
 rename bip-0360/ref-impl/{ => rust}/tests/p2qrh_descriptor.rs (100%)
 rename bip-0360/ref-impl/{ => rust}/tests/p2qrh_spend.rs (100%)

diff --git a/bip-0360/ref-impl/python/.gitignore b/bip-0360/ref-impl/python/.gitignore
new file mode 100644
index 0000000000..b6e47617de
--- /dev/null
+++ b/bip-0360/ref-impl/python/.gitignore
@@ -0,0 +1,129 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# pipenv
+#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+#   However, in case of collaboration, if having platform-specific dependencies or dependencies
+#   having no cross-platform support, pipenv may install dependencies that don't work, or not
+#   install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
diff --git a/bip-0360/ref-impl/Cargo.lock b/bip-0360/ref-impl/rust/Cargo.lock
similarity index 100%
rename from bip-0360/ref-impl/Cargo.lock
rename to bip-0360/ref-impl/rust/Cargo.lock
diff --git a/bip-0360/ref-impl/Cargo.toml b/bip-0360/ref-impl/rust/Cargo.toml
similarity index 100%
rename from bip-0360/ref-impl/Cargo.toml
rename to bip-0360/ref-impl/rust/Cargo.toml
diff --git a/bip-0360/ref-impl/README.md b/bip-0360/ref-impl/rust/README.md
similarity index 100%
rename from bip-0360/ref-impl/README.md
rename to bip-0360/ref-impl/rust/README.md
diff --git a/bip-0360/ref-impl/docs/rust_bitcoin_p2pqrh_changes.md b/bip-0360/ref-impl/rust/docs/rust_bitcoin_p2pqrh_changes.md
similarity index 100%
rename from bip-0360/ref-impl/docs/rust_bitcoin_p2pqrh_changes.md
rename to bip-0360/ref-impl/rust/docs/rust_bitcoin_p2pqrh_changes.md
diff --git a/bip-0360/ref-impl/src/data_structures.rs b/bip-0360/ref-impl/rust/src/data_structures.rs
similarity index 100%
rename from bip-0360/ref-impl/src/data_structures.rs
rename to bip-0360/ref-impl/rust/src/data_structures.rs
diff --git a/bip-0360/ref-impl/src/error.rs b/bip-0360/ref-impl/rust/src/error.rs
similarity index 100%
rename from bip-0360/ref-impl/src/error.rs
rename to bip-0360/ref-impl/rust/src/error.rs
diff --git a/bip-0360/ref-impl/src/lib.rs b/bip-0360/ref-impl/rust/src/lib.rs
similarity index 100%
rename from bip-0360/ref-impl/src/lib.rs
rename to bip-0360/ref-impl/rust/src/lib.rs
diff --git a/bip-0360/ref-impl/tests/data/p2qrh_construction.json b/bip-0360/ref-impl/rust/tests/data/p2qrh_construction.json
similarity index 100%
rename from bip-0360/ref-impl/tests/data/p2qrh_construction.json
rename to bip-0360/ref-impl/rust/tests/data/p2qrh_construction.json
diff --git a/bip-0360/ref-impl/tests/data/p2qrh_descriptors.json b/bip-0360/ref-impl/rust/tests/data/p2qrh_descriptors.json
similarity index 100%
rename from bip-0360/ref-impl/tests/data/p2qrh_descriptors.json
rename to bip-0360/ref-impl/rust/tests/data/p2qrh_descriptors.json
diff --git a/bip-0360/ref-impl/tests/data/p2qrh_spend.json b/bip-0360/ref-impl/rust/tests/data/p2qrh_spend.json
similarity index 100%
rename from bip-0360/ref-impl/tests/data/p2qrh_spend.json
rename to bip-0360/ref-impl/rust/tests/data/p2qrh_spend.json
diff --git a/bip-0360/ref-impl/tests/p2qrh_construction.rs b/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs
similarity index 100%
rename from bip-0360/ref-impl/tests/p2qrh_construction.rs
rename to bip-0360/ref-impl/rust/tests/p2qrh_construction.rs
diff --git a/bip-0360/ref-impl/tests/p2qrh_descriptor.rs b/bip-0360/ref-impl/rust/tests/p2qrh_descriptor.rs
similarity index 100%
rename from bip-0360/ref-impl/tests/p2qrh_descriptor.rs
rename to bip-0360/ref-impl/rust/tests/p2qrh_descriptor.rs
diff --git a/bip-0360/ref-impl/tests/p2qrh_spend.rs b/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs
similarity index 100%
rename from bip-0360/ref-impl/tests/p2qrh_spend.rs
rename to bip-0360/ref-impl/rust/tests/p2qrh_spend.rs

From fb8928652902af4f5dea6e2e875792284bdde755 Mon Sep 17 00:00:00 2001
From: jbride 
Date: Sat, 21 Jun 2025 12:17:03 -0600
Subject: [PATCH 052/131] p2qrh: fixed documentation error in
 docs/rust_bitcoin_p2pqrh_changes.md

---
 .../ref-impl/rust/docs/rust_bitcoin_p2pqrh_changes.md  | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/bip-0360/ref-impl/rust/docs/rust_bitcoin_p2pqrh_changes.md b/bip-0360/ref-impl/rust/docs/rust_bitcoin_p2pqrh_changes.md
index 545bd7bbe7..5ff2255e2b 100644
--- a/bip-0360/ref-impl/rust/docs/rust_bitcoin_p2pqrh_changes.md
+++ b/bip-0360/ref-impl/rust/docs/rust_bitcoin_p2pqrh_changes.md
@@ -144,10 +144,10 @@ fn new_p2qrh(program: [u8; 32]) -> Self {
     WitnessProgram { version: WitnessVersion::V3, program: ArrayVec::from_slice(&program) }
 }
 
-/// Creates a [`WitnessProgram`] from `pk` for a P2WPKH output.
-pub fn p2wpkh(pk: &CompressedPublicKey) -> Self {
-    let hash = pk.wpubkey_hash();
-    WitnessProgram::new_p2wpkh(hash.to_byte_array())
+/// Creates a pay to quantum resistant hash address from a merkle root.
+pub fn p2qrh(merkle_root: Option) -> Self {
+    let merkle_root = merkle_root.unwrap();
+    WitnessProgram::new_p2qrh(merkle_root.to_byte_array())
 }
 ```
 
@@ -163,4 +163,4 @@ pub fn p2qrh(merkle_root: Option, hrp: impl Into) -> Addr
     let program = WitnessProgram::p2qrh(merkle_root);
     Address::from_witness_program(program, hrp)
 }
-```
\ No newline at end of file
+```

From b37d1d303d39c1166e3810a123964d10620a6393 Mon Sep 17 00:00:00 2001
From: jbride 
Date: Tue, 24 Jun 2025 08:45:42 -0600
Subject: [PATCH 053/131] p2qrh: adding asm representation and description to
 test-vector leaf scripts

---
 .../rust/tests/data/p2qrh_construction.json         | 13 +++++++++++++
 bip-0360/ref-impl/rust/tests/data/p2qrh_spend.json  |  2 +-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/bip-0360/ref-impl/rust/tests/data/p2qrh_construction.json b/bip-0360/ref-impl/rust/tests/data/p2qrh_construction.json
index d4cea1d40a..2a0f9b886e 100644
--- a/bip-0360/ref-impl/rust/tests/data/p2qrh_construction.json
+++ b/bip-0360/ref-impl/rust/tests/data/p2qrh_construction.json
@@ -20,6 +20,7 @@
                 "scriptTree": {
                     "id": 0,
                     "script": "20b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007ac",
+                    "asm": "b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007 OP_CHECKSIG",
                     "leafVersion": 192
                 }
             },
@@ -45,11 +46,14 @@
                     {
                         "id": 0,
                         "script": "20387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48ac",
+                        "asm": "387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48 OP_CHECKSIG",
                         "leafVersion": 192
                     },
                     {
                         "id": 1,
                         "script": "06424950333431",
+                        "asm": "424950333431",
+                        "description": "just pushes the string 'BIP341' onto the stack",
                         "leafVersion": 250
                     }
                 ]
@@ -78,11 +82,14 @@
                     {
                         "id": 0,
                         "script": "2044b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fdac",
+                        "asm": "44b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fd OP_CHECKSIG",
                         "leafVersion": 192
                     },
                     {
                         "id": 1,
                         "script": "07546170726f6f74",
+                        "asm": "546170726f6f74",
+                        "description": "pushes the string 'Taproot' onto the stack",
                         "leafVersion": 192
                     }
                 ]
@@ -112,17 +119,20 @@
                     {
                         "id": 0,
                         "script": "2072ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69ac",
+                        "asm": "72ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69 OP_CHECKSIG",
                         "leafVersion": 192
                     },
                     [
                         {
                             "id": 1,
                             "script": "202352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8ac",
+                            "asm": "2352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8 OP_CHECKSIG",
                             "leafVersion": 192
                         },
                         {
                             "id": 2,
                             "script": "207337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186aac",
+                            "asm": "7337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186a OP_CHECKSIG",
                             "leafVersion": 192
                         }
                     ]
@@ -155,17 +165,20 @@
                     {
                         "id": 0,
                         "script": "2071981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2ac",
+                        "asm": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG",
                         "leafVersion": 192
                     },
                     [
                         {
                             "id": 1,
                             "script": "20d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748ac",
+                            "asm": "d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748 OP_CHECKSIG",
                             "leafVersion": 192
                         },
                         {
                             "id": 2,
                             "script": "20c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4cac",
+                            "asm": "c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4c OP_CHECKSIG",
                             "leafVersion": 192
                         }
                     ]
diff --git a/bip-0360/ref-impl/rust/tests/data/p2qrh_spend.json b/bip-0360/ref-impl/rust/tests/data/p2qrh_spend.json
index cbc0049135..d11f136d72 100644
--- a/bip-0360/ref-impl/rust/tests/data/p2qrh_spend.json
+++ b/bip-0360/ref-impl/rust/tests/data/p2qrh_spend.json
@@ -8,7 +8,7 @@
                 "scriptInputs": [
                     "03"
                 ],
-                "scriptHex" : "8753",
+                "leafDescriptor" : "tr(INTERNAL_KEY, {pk():OP_EQUAL OP_1}, {pk():OP_EQUAL OP_2}, {pk():OP_EQUAL OP_3})",
                 "controlBlock": "c0"
             },
             "intermediary": { },

From 3f32617cd9eda93e942d9d4c5a4bad08e28ecb54 Mon Sep 17 00:00:00 2001
From: jbride 
Date: Wed, 25 Jun 2025 07:31:44 -0600
Subject: [PATCH 054/131] p2qrh test vectors:  simple lightning contract

---
 .../rust/tests/data/p2qrh_construction.json   | 37 +++++++++++++++++++
 .../ref-impl/rust/tests/p2qrh_construction.rs | 15 +++++++-
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/bip-0360/ref-impl/rust/tests/data/p2qrh_construction.json b/bip-0360/ref-impl/rust/tests/data/p2qrh_construction.json
index 2a0f9b886e..bfeaa90d10 100644
--- a/bip-0360/ref-impl/rust/tests/data/p2qrh_construction.json
+++ b/bip-0360/ref-impl/rust/tests/data/p2qrh_construction.json
@@ -74,6 +74,43 @@
                 ]
             }
         },
+        {
+            "id": "p2qrh_simple_lightning_contract",
+            "objective": "Tests P2QRH with two script leaves that simulate a simple lightning network contract.  Reference: https://github.com/bitcoin-core/btcdeb/blob/master/doc/tapscript-example-with-tap.md",
+            "given": {
+                "scriptTree": [
+                    {
+                        "id": 0,
+                        "script": "029000b275209997a497d964fc1a62885b05a51166a65a90df00492c8d7cf61d6accf54803beac",
+                        "asm": "144 OP_CHECKSEQUENCEVERIFY OP_DROP 9997a497d964fc1a62885b05a51166a65a90df00492c8d7cf61d6accf54803be OP_CHECKSIG",
+                        "description": "Alice takes the money after waiting 1 day",
+                        "leafVersion": 192
+                    },
+                    {
+                        "id": 1,
+                        "script": "a8206c60f404f8167a38fc70eaf8aa17ac351023bef86bcb9d1086a19afe95bd533388204edfcf9dfe6c0b5c83d1ab3f78d1b39a46ebac6798e08e19761f5ed89ec83c10ac",
+                        "asm": "OP_SHA256 6c60f404f8167a38fc70eaf8aa17ac351023bef86bcb9d1086a19afe95bd5333 OP_EQUALVERIFY 4edfcf9dfe6c0b5c83d1ab3f78d1b39a46ebac6798e08e19761f5ed89ec83c10 OP_CHECKSIG",
+                        "description": "Bob takes the money whenever he wishes to by revealing the preimage_hash",
+                        "leafVersion": 192
+                    }
+                ]
+            },
+            "intermediary": {
+                "leafHashes": [
+                    "c81451874bd9ebd4b6fd4bba1f84cdfb533c532365d22a0a702205ff658b17c9",
+                    "632c8632b4f29c6291416e23135cf78ecb82e525788ea5ed6483e3c6ce943b42"
+                ],
+                "merkleRoot": "41646f8c1fe2a96ddad7f5471bc4fee7da98794ef8c45a4f4fc6a559d60c9f6b"
+            },
+            "expected": {
+                "scriptPubKey": "532041646f8c1fe2a96ddad7f5471bc4fee7da98794ef8c45a4f4fc6a559d60c9f6b",
+                "bip350Address": "bc1rg9jxlrqlu25kmkkh74r3h387uldfs72wlrz95n60c6j4n4svna4s258v28",
+                "scriptPathControlBlocks": [
+                    "c0c81451874bd9ebd4b6fd4bba1f84cdfb533c532365d22a0a702205ff658b17c9",
+                    "c0632c8632b4f29c6291416e23135cf78ecb82e525788ea5ed6483e3c6ce943b42"
+                ]
+            }
+        },
         {
             "id": "p2qrh_two_leaf_same_version",
             "objective": "Tests P2QRH with two script leaves of same version",
diff --git a/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs b/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs
index ff28ed0187..64a23ffd5d 100644
--- a/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs
+++ b/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs
@@ -26,6 +26,7 @@ static P2QRH_DIFFERENT_VERSION_LEAVES_TEST: &str = "p2qrh_different_version_leav
 static P2QRH_TWO_LEAF_SAME_VERSION_TEST: &str = "p2qrh_two_leaf_same_version";
 static P2QRH_THREE_LEAF_COMPLEX_TEST: &str = "p2qrh_three_leaf_complex";
 static P2QRH_THREE_LEAF_ALTERNATIVE_TEST: &str = "p2qrh_three_leaf_alternative";
+static P2QRH_SIMPLE_LIGHTNING_CONTRACT_TEST: &str = "p2qrh_simple_lightning_contract";
 
 // https://learnmeabitcoin.com/technical/upgrades/taproot/#example-2-script-path-spend-simple
 #[test]
@@ -58,6 +59,14 @@ fn test_p2qrh_different_version_leaves() {
     process_test_vector_p2qrh(test_vector).unwrap();
 }
 
+#[test]
+fn test_p2qrh_simple_lightning_contract() {
+
+    let test_vectors = &*TEST_VECTORS;
+    let test_vector = test_vectors.test_vector_map.get(P2QRH_SIMPLE_LIGHTNING_CONTRACT_TEST).unwrap();
+    process_test_vector_p2qrh(test_vector).unwrap();
+}
+
 #[test]
 fn test_p2qrh_two_leaf_same_version() {
 
@@ -207,7 +216,11 @@ fn process_test_vector_p2qrh(test_vector: &TestVector) -> anyhow::Result<()> {
     let script_buf: P2qrhScriptBuf = P2qrhScriptBuf::new_p2qrh(derived_merkle_root);
     let script: &Script = script_buf.as_script();
     let script_pubkey = script.to_hex_string();
-    assert_eq!(script_pubkey, *test_vector.expected.script_pubkey.as_ref().unwrap());
+    assert_eq!( 
+        script_pubkey,
+        *test_vector.expected.script_pubkey.as_ref().unwrap(),
+        "Script pubkey mismatch"
+    );
     debug!("just passed script_pubkey validation. script_pubkey = {}", script_pubkey);
 
     // 4)  derive bech32m address and verify against test vector

From 2cbe24684d56b9bbec1df8c003a957dbb2395c67 Mon Sep 17 00:00:00 2001
From: jbride 
Date: Wed, 25 Jun 2025 09:53:18 -0600
Subject: [PATCH 055/131] p2qrh test vectors:  specify Bitcoin network for
 generating p2qrh address

---
 bip-0360/ref-impl/rust/README.md              |  8 +++++
 .../ref-impl/rust/tests/p2qrh_construction.rs | 34 +++++++++++++++++--
 2 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/bip-0360/ref-impl/rust/README.md b/bip-0360/ref-impl/rust/README.md
index 6ac9487fdf..4b391dcadb 100644
--- a/bip-0360/ref-impl/rust/README.md
+++ b/bip-0360/ref-impl/rust/README.md
@@ -19,6 +19,14 @@ As such, these test vectors assume the presence of these customized forks cloned
    $ ln -s /path/to/git/clone/of/rust-miniscript
    ```
 
+1. environment variables
+   ```
+   // Specify Bitcoin network used when generating bip350 (bech32m) address
+   // Options: regtest, testnet, signet
+   // Default: mainnet
+   $ export BITCOIN_NETWORK=
+   ```
+
 1. run a specific test:
    ```
    $ cargo test test_p2qrh_single_leaf_script_tree -- --nocapture
diff --git a/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs b/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs
index 64a23ffd5d..8d3f6c2769 100644
--- a/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs
+++ b/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs
@@ -54,6 +54,8 @@ fn test_p2qrh_single_leaf_script_tree() {
 #[test]
 fn test_p2qrh_different_version_leaves() {
 
+    let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
+
     let test_vectors = &*TEST_VECTORS;
     let test_vector = test_vectors.test_vector_map.get(P2QRH_DIFFERENT_VERSION_LEAVES_TEST).unwrap();
     process_test_vector_p2qrh(test_vector).unwrap();
@@ -62,6 +64,8 @@ fn test_p2qrh_different_version_leaves() {
 #[test]
 fn test_p2qrh_simple_lightning_contract() {
 
+    let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
+
     let test_vectors = &*TEST_VECTORS;
     let test_vector = test_vectors.test_vector_map.get(P2QRH_SIMPLE_LIGHTNING_CONTRACT_TEST).unwrap();
     process_test_vector_p2qrh(test_vector).unwrap();
@@ -70,6 +74,8 @@ fn test_p2qrh_simple_lightning_contract() {
 #[test]
 fn test_p2qrh_two_leaf_same_version() {
 
+    let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
+
     let test_vectors = &*TEST_VECTORS;
     let test_vector = test_vectors.test_vector_map.get(P2QRH_TWO_LEAF_SAME_VERSION_TEST).unwrap();
     process_test_vector_p2qrh(test_vector).unwrap();
@@ -78,6 +84,8 @@ fn test_p2qrh_two_leaf_same_version() {
 #[test]
 fn test_p2qrh_three_leaf_complex() {
 
+    let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
+
     let test_vectors = &*TEST_VECTORS;
     let test_vector = test_vectors.test_vector_map.get(P2QRH_THREE_LEAF_COMPLEX_TEST).unwrap();
     process_test_vector_p2qrh(test_vector).unwrap();
@@ -86,6 +94,8 @@ fn test_p2qrh_three_leaf_complex() {
 #[test]
 fn test_p2qrh_three_leaf_alternative() {
 
+    let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
+
     let test_vectors = &*TEST_VECTORS;
     let test_vector = test_vectors.test_vector_map.get(P2QRH_THREE_LEAF_ALTERNATIVE_TEST).unwrap();
     process_test_vector_p2qrh(test_vector).unwrap();
@@ -223,12 +233,30 @@ fn process_test_vector_p2qrh(test_vector: &TestVector) -> anyhow::Result<()> {
     );
     debug!("just passed script_pubkey validation. script_pubkey = {}", script_pubkey);
 
+    let mut bitcoin_network: Network = Network::Bitcoin;
+
+    // Check for BITCOIN_NETWORK environment variable and override if set
+    if let Ok(network_str) = std::env::var("BITCOIN_NETWORK") {
+        bitcoin_network = match network_str.to_lowercase().as_str() {
+            "regtest" => Network::Regtest,
+            "testnet" => Network::Testnet,
+            "signet" => Network::Signet,
+            _ => {
+                debug!("Invalid BITCOIN_NETWORK value '{}', using default Bitcoin network", network_str);
+                Network::Bitcoin
+            }
+        };
+    }
+
+    
     // 4)  derive bech32m address and verify against test vector
     //     p2qrh adress is comprised of network HRP + WitnessProgram (version + program)
-    let bech32m_address = Address::p2qrh(Some(derived_merkle_root), Network::Bitcoin);
-    //let bech32m_address = Address::p2qrh(Some(derived_merkle_root), Network::Regtest);
+    let bech32m_address = Address::p2qrh(Some(derived_merkle_root), bitcoin_network);
+    debug!("derived bech32m address for bitcoin_network: {} : {}", bitcoin_network, bech32m_address.to_string());
 
-    assert_eq!(bech32m_address.to_string(), *test_vector.expected.bip350_address.as_ref().unwrap(), "Bech32m address mismatch.");
+    if bitcoin_network == Network::Bitcoin {
+        assert_eq!(bech32m_address.to_string(), *test_vector.expected.bip350_address.as_ref().unwrap(), "Bech32m address mismatch.");
+    }
 
     Ok(())
 }

From 7438d08106a979af3bff065f92ef772766f3c069 Mon Sep 17 00:00:00 2001
From: jbride 
Date: Mon, 30 Jun 2025 09:10:07 -0600
Subject: [PATCH 056/131] p2qrh-testvectors: first draft of performance testing
 & failure analysis

---
 bip-0360/ref-impl/.gitignore                  |   1 +
 .../stack_element_size_performance_tests.adoc | 175 ++++++++++++++++++
 2 files changed, 176 insertions(+)
 create mode 100644 bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc

diff --git a/bip-0360/ref-impl/.gitignore b/bip-0360/ref-impl/.gitignore
index ec700b5f90..289b901f3b 100644
--- a/bip-0360/ref-impl/.gitignore
+++ b/bip-0360/ref-impl/.gitignore
@@ -1,3 +1,4 @@
 rust-bitcoin
 rust-miniscript
 target
+.btcdeb_history
diff --git a/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc b/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc
new file mode 100644
index 0000000000..ffc8543ef9
--- /dev/null
+++ b/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc
@@ -0,0 +1,175 @@
+
+:numbered:
+
+== Overview
+
+BIP-0360 proposes an increase in stack element size from current 520 bytes (v0.29) to 8kb.
+
+Subsequently, there is a need to determine the performance and stability related consequences of doing so.
+
+== Regression Tests
+
+The following regression tests failed with `MAX_SCRIPT_ELEMENT_SIZE` set to 8000
+
+[cols="1,1,2"]
+|===
+|feature_taproot.py       | line 1338       | Missing error message 'Push value size limit exceeded' from block response 'mandatory-script-verify-flag-failed (Stack size must be exactly one after execution)'
+|p2p_filter.py            | lines 130-132   | Check that too large data element to add to the filter is rejected
+|p2p_segwit.py            | lines 1047-1049 | mandatory-script-verify-flag-failed (Push value size limit exceeded)
+|rpc_createmultisig.py    | lines 75-75     | No exception raised: redeemScript exceeds size limit: 684 > 520"
+|===
+
+== Performance Analysis
+
+
+
+
+=== Results Summary
+
+|===
+| Preimage Bytes | ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total|
+| 1 | 637.28 | 1,569,165.30 | 0.3% | 8,736.00 | 1,338.55 | 6.526 | 832.00 | 0.0% | 5.53 |
+| 64 | 794.85 | 1,258,098.46 | 0.4% | 11,107.00 | 1,666.92 | 6.663 | 827.00 | 0.0% | 5.61 |
+| 65 | 831.95 | 1,201,996.30 | 0.5% | 11,144.00 | 1,698.26 | 6.562 | 841.00 | 0.0% | 5.53 |
+| 7500 | 19,172.67 | 52,157.58 | 0.5% | 285,220.02 | 40,203.63 | 7.094 | 1,636.02 | 0.4% | 5.49 |
+|===
+
+==== key
+
+[cols="1,6"]
+|===
+| Metric | Description
+| ns/op  | Nanoseconds per operation - the average time it takes to complete one benchmark iteration, measured in billionths of a second
+| op/s   | Operations per second - the throughput rate showing how many benchmark iterations can be completed per second
+| err%   | Error percentage - statistical margin of error in the measurement, indicating the reliability of the benchmark results
+| ins/op | Instructions per operation - the number of CPU instructions executed for each benchmark iteration
+| cyc/op | CPU cycles per operation - the number of CPU clock cycles consumed for each benchmark iteration
+| IPC    | Instructions per cycle - the ratio of instructions executed per CPU cycle, indicating CPU efficiency and pipeline utilization
+| bra/op | Branches per operation - the number of conditional branch instructions executed for each benchmark iteration
+| miss%  | Branch misprediction percentage - the rate at which the CPU incorrectly predicts branch outcomes, causing pipeline stalls
+| total  | Total benchmark time - the total wall-clock time spent running the entire benchmark in seconds
+|===
+
+=== Detailed Results
+
+==== Stack Element Size = 1 Byte
+
+|==
+|               ns/op |                op/s |    err% |          ins/op |          cyc/op |    IPC |         bra/op |   miss% |     total | benchmark
+|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
+|              637.28 |        1,569,165.30 |    0.3% |        8,736.00 |        1,338.55 |  6.526 |         832.00 |    0.0% |      5.53 | `VerifyP2WSHBench`
+|==
+
+==== Stack Element Size = 64 Bytes
+
+|==
+|               ns/op |                op/s |    err% |          ins/op |          cyc/op |    IPC |         bra/op |   miss% |     total | benchmark
+|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
+|              794.85 |        1,258,098.46 |    0.4% |       11,107.00 |        1,666.92 |  6.663 |         827.00 |    0.0% |      5.61 | `VerifyP2WSHBench`
+|==
+
+===== Explanation
+
+Even though 64 bytes doesn't require padding (it's exactly one SHA256 block), the ins/op still increases from 8,736 to 11,107 instructions. Here's why:
+
+. Data Movement Overhead
+   
+    * 1 byte: Minimal data to copy into the SHA256 processing buffer
+    * 64 bytes: 64x more data to move from the witness stack into the SHA256 input buffer
+    * Memory copying operations add instructions
+
+. SHA256 State Initialization
+
+    * 1 byte: The 1-byte input gets padded to 64 bytes internally, but the padding is mostly zeros
+    * 64 bytes: All 64 bytes are actual data that needs to be processed
+    * The SHA256 algorithm may have different code paths for handling "real" data vs padded data
+
+. Memory Access Patterns
+
+    * 1 byte: Single byte access, likely cache-friendly
+    * 64 bytes: Sequential access to 64 bytes, potentially different memory access patterns
+    * May trigger different CPU optimizations or cache behavior
+
+. Bit Length Processing
+
+    * 1 byte: The SHA256 algorithm needs to set the bit length field (8 bits)
+    * 64 bytes: The bit length field is 512 bits
+    * Different bit length values may cause different code paths in the SHA256 implementation
+
+. Loop Unrolling and Optimization
+
+    * 1 byte: Compiler might optimize the single-block case differently
+    * 64 bytes: May use different loop structures or optimization strategies
+    * The SHA256 implementation might have specialized code paths for different input sizes
+
+. Witness Stack Operations
+
+    * 1 byte: Small witness element, minimal stack manipulation
+    * 64 bytes: Larger witness element, more complex stack operations
+    * The Bitcoin script interpreter has to handle larger data on the stack
+
+The increase from 8,736 to 11,107 instructions (~27% increase) suggests that even without padding overhead, the additional data movement and processing of "real" data vs padded data adds significant instruction count.
+This is a good example of how seemingly small changes in input size can affect the underlying implementation's code paths and optimization strategies.
+
+==== Stack Element Size = 65 Bytes
+
+1 byte more than the SHA256 _block_ size
+
+|== 
+|               ns/op |                op/s |    err% |          ins/op |          cyc/op |    IPC |         bra/op |   miss% |     total | benchmark
+|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
+|              831.95 |        1,201,996.30 |    0.5% |       11,144.00 |        1,698.26 |  6.562 |         841.00 |    0.0% |      5.53 | `VerifyP2WSHBench`
+|== 
+
+==== Stack Element Size = 7500 Bytes
+
+|==
+|               ns/op |                op/s |    err% |          ins/op |          cyc/op |    IPC |         bra/op |   miss% |     total | benchmark
+|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
+|           19,172.67 |           52,157.58 |    0.5% |      285,220.02 |       40,203.63 |  7.094 |       1,636.02 |    0.4% |      5.49 | `VerifyP2WSHBench`
+|==
+
+
+=== Procedure
+
+== Failure Analysis
+
+Goals:
+
+* Measure stack memory usage to detect overflows or excessive stack growth.
+* Monitor heap memory usage to identify increased allocations or leaks caused by larger elements.
+* Detect memory errors (e.g., invalid reads/writes, use-after-free) that might arise from modified stack handling.
+* Assess performance impacts (e.g., memory allocation overhead) in critical paths like transaction validation.
+
+== Test Environment
+
+*  Fedora 42 
+*  8 cores (Intel(R) Core(TM) i7-8665U CPU @ 1.90GHz)
+*  32 GB RAM
+
+* OS settings:
++
+-----
+$ ulimit -a
+real-time non-blocking time  (microseconds, -R) unlimited
+core file size              (blocks, -c) unlimited
+data seg size               (kbytes, -d) unlimited
+scheduling priority                 (-e) 0
+file size                   (blocks, -f) unlimited
+pending signals                     (-i) 126896
+max locked memory           (kbytes, -l) 8192
+max memory size             (kbytes, -m) unlimited
+open files                          (-n) 1024
+pipe size                (512 bytes, -p) 8
+POSIX message queues         (bytes, -q) 819200
+real-time priority                  (-r) 0
+stack size                  (kbytes, -s) 8192
+cpu time                   (seconds, -t) unlimited
+max user processes                  (-u) 126896
+virtual memory              (kbytes, -v) unlimited
+file locks                          (-x) unlimited
+-----
+
+== Notes
+
+. test with different thread stack sizes (ie: ulimit -s xxxx )

From 0793e2d0503665693782fc3d987efec78a56027f Mon Sep 17 00:00:00 2001
From: jbride 
Date: Mon, 30 Jun 2025 16:51:27 -0600
Subject: [PATCH 057/131] p2qrh: github action fix

---
 bip-0360/ref-impl/rust/tests/p2qrh_construction.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs b/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs
index 8d3f6c2769..98999ca376 100644
--- a/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs
+++ b/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs
@@ -250,7 +250,7 @@ fn process_test_vector_p2qrh(test_vector: &TestVector) -> anyhow::Result<()> {
 
     
     // 4)  derive bech32m address and verify against test vector
-    //     p2qrh adress is comprised of network HRP + WitnessProgram (version + program)
+    //     p2qrh address is comprised of network HRP + WitnessProgram (version + program)
     let bech32m_address = Address::p2qrh(Some(derived_merkle_root), bitcoin_network);
     debug!("derived bech32m address for bitcoin_network: {} : {}", bitcoin_network, bech32m_address.to_string());
 

From 25a0f56719165c46ba0f1d9ca7cb2f86bb669d5c Mon Sep 17 00:00:00 2001
From: jbride 
Date: Wed, 2 Jul 2025 11:31:52 -0600
Subject: [PATCH 058/131] p2qrh: updates
 stack_element_size_performance_tests.adoc based on performance and failure
 tests.

---
 .../stack_element_size_performance_tests.adoc | 257 +++++++++++++++---
 1 file changed, 219 insertions(+), 38 deletions(-)

diff --git a/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc b/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc
index ffc8543ef9..d7c2dd40be 100644
--- a/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc
+++ b/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc
@@ -1,3 +1,9 @@
+:scrollbar:
+:data-uri:
+:toc2:
+:linkattrs:
+
+= Stack Element Size Performance Tests
 
 :numbered:
 
@@ -9,7 +15,7 @@ Subsequently, there is a need to determine the performance and stability related
 
 == Regression Tests
 
-The following regression tests failed with `MAX_SCRIPT_ELEMENT_SIZE` set to 8000
+The following regression tests failed with `MAX_SCRIPT_ELEMENT_SIZE` set to 8000 .
 
 [cols="1,1,2"]
 |===
@@ -19,28 +25,63 @@ The following regression tests failed with `MAX_SCRIPT_ELEMENT_SIZE` set to 8000
 |rpc_createmultisig.py    | lines 75-75     | No exception raised: redeemScript exceeds size limit: 684 > 520"
 |===
 
-== Performance Analysis
+**Analysis**
+
+These 4 tests explicitly test for a stack element size of 520 and are expected to fail with a stack element size of 8Kb.
+Subsequently, no further action needed.
+
+
+== Performance Tests
+
+=== OP_SHA256
 
+The following Bitcoin script is used to conduct this performance test:
 
+-----
+ OP_SHA256 OP_DROP OP_1
+-----
+
+When executed, this script adds the pre-image array of arbitrary data to the stack.
+Immediately after, a SHA256 hash function pops the pre-image array off the stack, executes a hash and adds the result to the top of the stack.
+The `OP_DROP` operation removes the hash result from the stack.
 
 
-=== Results Summary
+==== Results Summary
 
+[cols="3,1,1,1,1,1,1,1,1,1", options="header"]
 |===
-| Preimage Bytes | ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total|
-| 1 | 637.28 | 1,569,165.30 | 0.3% | 8,736.00 | 1,338.55 | 6.526 | 832.00 | 0.0% | 5.53 |
-| 64 | 794.85 | 1,258,098.46 | 0.4% | 11,107.00 | 1,666.92 | 6.663 | 827.00 | 0.0% | 5.61 |
-| 65 | 831.95 | 1,201,996.30 | 0.5% | 11,144.00 | 1,698.26 | 6.562 | 841.00 | 0.0% | 5.53 |
-| 7500 | 19,172.67 | 52,157.58 | 0.5% | 285,220.02 | 40,203.63 | 7.094 | 1,636.02 | 0.4% | 5.49 |
+| Stack Element Size (Bytes) | ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op |miss% | total
+| 1 | 637.28 | 1,569,165.30 | 0.3% | 8,736.00 | 1,338.55 | 6.526 | 832.00 | 0.0% | 5.53
+| 64 | 794.85 | 1,258,098.46 | 0.4% | 11,107.00 | 1,666.92 | 6.663 | 827.00 | 0.0% | 5.61
+| 65 | 831.95 | 1,201,996.30 | 0.5% | 11,144.00 | 1,698.26 | 6.562 | 841.00 | 0.0% | 5.53
+| 100 | 794.82 | 1,258,139.86 | 0.2% | 11,139.00 | 1,673.89 | 6.655 | 837.00 | 0.0% | 5.50
+| 520 | 1,946.67 | 513,697.88 | 0.2% | 27,681.00 | 4,095.57 | 6.759 | 885.00 | 0.0% | 5.50
+| 8000 | 20,958.63 | 47,713.05 | 2.7% | 304,137.02 | 43,789.86 | 6.945 | 1,689.02 | 0.4% | 5.63
 |===
 
-==== key
+**Analysis**
+
+The following observations are made from the performance test:
+
+. **Performance Scaling**: The increase from 520 bytes to 8000 bytes (15.4x size increase) results in approximately 9.8x performance degradation (19,173 ns/op vs 1,947 ns/op).
+This represents sub-linear scaling, which suggests the implementation handles large data efficiently.
 
-[cols="1,6"]
+. **Instruction Count Scaling**: Instructions per operation increase from 27,681 to 285,220 (10.3x increase), closely matching the performance degradation, indicating the bottleneck is primarily computational rather than memory bandwidth.
+
+. **Throughput Impact**: Operations per second decrease from 513,698 op/s to 52,158 op/s, representing a 9.8x reduction in throughput.
+
+. **Cache Efficiency**: The IPC (Instructions Per Cycle) remains relatively stable (6.759 to 7.094), suggesting good CPU pipeline utilization despite the increased data size.
+
+. **Memory Access Patterns**: The branch mis-prediction rate increases slightly (0.0% to 0.4%), indicating minimal impact on branch prediction accuracy.
+
+
+**key**
+
+[cols="1,6", options="header"]
 |===
 | Metric | Description
-| ns/op  | Nanoseconds per operation - the average time it takes to complete one benchmark iteration, measured in billionths of a second
-| op/s   | Operations per second - the throughput rate showing how many benchmark iterations can be completed per second
+| ns/op  | Nanoseconds per operation - average time it takes to complete one benchmark iteration
+| op/s   | Operations per second - throughput rate showing how many benchmark iterations can be completed per second
 | err%   | Error percentage - statistical margin of error in the measurement, indicating the reliability of the benchmark results
 | ins/op | Instructions per operation - the number of CPU instructions executed for each benchmark iteration
 | cyc/op | CPU cycles per operation - the number of CPU clock cycles consumed for each benchmark iteration
@@ -50,25 +91,25 @@ The following regression tests failed with `MAX_SCRIPT_ELEMENT_SIZE` set to 8000
 | total  | Total benchmark time - the total wall-clock time spent running the entire benchmark in seconds
 |===
 
-=== Detailed Results
+==== Detailed Results
 
-==== Stack Element Size = 1 Byte
+===== Stack Element Size = 1 Byte
 
-|==
-|               ns/op |                op/s |    err% |          ins/op |          cyc/op |    IPC |         bra/op |   miss% |     total | benchmark
-|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
-|              637.28 |        1,569,165.30 |    0.3% |        8,736.00 |        1,338.55 |  6.526 |         832.00 |    0.0% |      5.53 | `VerifyP2WSHBench`
-|==
+[cols="2,1,1,1,1,1,1,1,1", options="header"]
+|===
+|ns/op |op/s |err% |ins/op |cyc/op |IPC |bra/op |miss% |total
+|637.28 |1,569,165.30 |0.3% |8,736.00 |1,338.55 |6.526 |832.00 |0.0% |5.53
+|===
 
-==== Stack Element Size = 64 Bytes
+===== Stack Element Size = 64 Bytes
 
-|==
-|               ns/op |                op/s |    err% |          ins/op |          cyc/op |    IPC |         bra/op |   miss% |     total | benchmark
-|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
-|              794.85 |        1,258,098.46 |    0.4% |       11,107.00 |        1,666.92 |  6.663 |         827.00 |    0.0% |      5.61 | `VerifyP2WSHBench`
-|==
+[cols="2,1,1,1,1,1,1,1,1", options="header"]
+|===
+|               ns/op |                op/s |    err% |          ins/op |          cyc/op |    IPC |         bra/op |   miss% |     total
+|              794.85 |        1,258,098.46 |    0.4% |       11,107.00 |        1,666.92 |  6.663 |         827.00 |    0.0% |      5.61
+|===
 
-===== Explanation
+====== Explanation
 
 Even though 64 bytes doesn't require padding (it's exactly one SHA256 block), the ins/op still increases from 8,736 to 11,107 instructions. Here's why:
 
@@ -111,27 +152,116 @@ Even though 64 bytes doesn't require padding (it's exactly one SHA256 block), th
 The increase from 8,736 to 11,107 instructions (~27% increase) suggests that even without padding overhead, the additional data movement and processing of "real" data vs padded data adds significant instruction count.
 This is a good example of how seemingly small changes in input size can affect the underlying implementation's code paths and optimization strategies.
 
-==== Stack Element Size = 65 Bytes
+===== Stack Element Size = 65 Bytes
 
 1 byte more than the SHA256 _block_ size
 
-|== 
-|               ns/op |                op/s |    err% |          ins/op |          cyc/op |    IPC |         bra/op |   miss% |     total | benchmark
-|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
-|              831.95 |        1,201,996.30 |    0.5% |       11,144.00 |        1,698.26 |  6.562 |         841.00 |    0.0% |      5.53 | `VerifyP2WSHBench`
-|== 
+[cols="2,1,1,1,1,1,1,1,1", options="header"]
+|=== 
+|ns/op |op/s |err% |ins/op |cyc/op |IPC |bra/op |   miss% |     total
+| 831.95 | 1,201,996.30 |0.5% |11,144.00 |1,698.26 |  6.562 |841.00 | 0.0% | 5.53
+|===
+
+===== Stack Element Size = 100 Bytes
+
+[cols="2,1,1,1,1,1,1,1,1", options="header"]
+|=== 
+|ns/op |op/s |err% |ins/op |cyc/op |IPC |bra/op |   miss% |     total
+|              794.82 |        1,258,139.86 |    0.2% |       11,139.00 |        1,673.89 |  6.655 |         837.00 |    0.0% |      5.50
+|===
+
+===== Stack Element Size = 520 Bytes
+
+[cols="2,1,1,1,1,1,1,1,1", options="header"]
+|=== 
+|ns/op |op/s |err% |ins/op |cyc/op |IPC |bra/op |   miss% |     total
+|            1,946.67 |          513,697.88 |    0.2% |       27,681.00 |        4,095.57 |  6.759 |         885.00 |    0.0% |      5.50
+|===
+
+===== Stack Element Size = 8000 Bytes
+
+[cols="2,1,1,1,1,1,1,1,1", options="header"]
+|===
+|ns/op |op/s |err% |ins/op |cyc/op |IPC |bra/op |   miss% |     total
+|           20,958.63 |           47,713.05 |    2.7% |      304,137.02 |       43,789.86 |  6.945 |       1,689.02 |    0.4% |      5.63
+|===
+
+=== OP_DUP OP_SHA256
+
+NOTE:  This test is likely irrelevant as per latest BIP-0360: _To prevent OP_DUP from creating an 8 MB stack by duplicating stack elements larger than 520 bytes we define OP_DUP to fail on stack elements larger than 520 bytes_.
+
+This test builds off the previous (involving the hashing of large stack element data) by duplicating that stack element data.
+
+The following Bitcoin script is used to conduct this performance test:
+
+-----
+ OP_DUP OP_SHA256 OP_DROP OP_1
+-----
+
+When executed, this script adds the pre-image array of arbitrary data to the stack.
+Immediately after, a `OP_DUP` operation duplicates the pre-image array on the stack.
+Then, a SHA256 hash function pops the pre-image array off the stack, executes a hash and adds the result to the top of the stack.
+The `OP_DROP` operation removes the hash result from the stack.
 
-==== Stack Element Size = 7500 Bytes
+==== Results Summary
 
-|==
-|               ns/op |                op/s |    err% |          ins/op |          cyc/op |    IPC |         bra/op |   miss% |     total | benchmark
-|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
-|           19,172.67 |           52,157.58 |    0.5% |      285,220.02 |       40,203.63 |  7.094 |       1,636.02 |    0.4% |      5.49 | `VerifyP2WSHBench`
-|==
+[cols="3,1,1,1,1,1,1,1,1,1", options="header"]
+|===
+| Stack Element Size (Bytes) | ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op |miss% | total
+| 1 | 714.83 | 1,398,937.33 | 0.7% | 9,548.00 | 1,488.22 | 6.416 | 1,012.00 | 0.0% | 5.57
+| 64 | 858.44 | 1,164,905.19 | 0.4% | 11,911.00 | 1,800.87 | 6.614 | 999.00 | 0.0% | 5.11
+| 65 | 868.40 | 1,151,539.31 | 0.8% | 11,968.00 | 1,814.31 | 6.596 | 1,019.00 | 0.0% | 5.56
+| 100 | 864.33 | 1,156,966.91 | 0.4% | 11,963.00 | 1,809.16 | 6.612 | 1,015.00 | 0.0% | 5.49
+| 520 | 2,036.64 | 491,005.94 | 0.7% | 28,615.00 | 4,266.27 | 6.707 | 1,073.00 | 0.0% | 5.52
+| 8000 | 20,883.10 | 47,885.61 | 0.2% | 306,887.04 | 43,782.35 | 7.009 | 2,089.02 | 0.3% | 5.53
+|===
+
+==== Analysis
+
+The following observations are made from the performance test (in comparison to the `OP_SHA256` test):
+
+. OP_DUP Overhead: The OP_DUP operation adds overhead by duplicating the stack element, which requires:
+    * Memory allocation for the duplicate
+    * Data copying from the original to the duplicate
+    * Additional stack manipulation
 
+. Size-Dependent Impact on ns/op:
+    * For small elements (1-100 bytes): Significant overhead (4.4% to 12.2%)
+    * For medium elements (520 bytes): Moderate overhead (4.6%)
+    * For large elements (8000 bytes): Negligible difference (-0.4%)
+
+. Instruction Count Impact:
+    * 8000 bytes: 304,137 → 306,887 instructions (+2,750 instructions)
+    * The additional instructions for OP_DUP are relatively small compared to the SHA256 computation
+
+. Memory Operations:
++
+The OP_DUP operation primarily affects memory operations rather than computational complexity.
+This explains why the impact diminishes with larger data sizes where SHA256 computation dominates the performance.
+
+This analysis shows that the OP_DUP operation has a measurable but manageable performance impact, especially for larger stack elements where the computational overhead of SHA256 dominates the overall execution time.
 
 === Procedure
 
+* Testing is done using functionality found in the link:https://github.com/jbride/bitcoin/tree/p2qrh[p2qrh branch] of Bitcoin Core.
+
+* Compilation of Bitcoin Core is done using the following `cmake` flags:
++
+-----
+$ cmake \
+    -B build \
+    -DWITH_ZMQ=ON \
+    -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
+    -DBUILD_BENCH=ON
+-----
+
+* Bench tests are conducted similar to the following :
++
+-----
+$ export PREIMAGE_SIZE_BYTES=8000
+$ ./build/bin/bench_bitcoin --filter=VerifyP2WSHBench -min-time=5000
+-----
+
 == Failure Analysis
 
 Goals:
@@ -141,6 +271,57 @@ Goals:
 * Detect memory errors (e.g., invalid reads/writes, use-after-free) that might arise from modified stack handling.
 * Assess performance impacts (e.g., memory allocation overhead) in critical paths like transaction validation.
 
+=== Memory Errors
+
+AddressSanitizer is a fast, compiler-based tool (available in GCC/Clang) for detecting memory errors with lower overhead than Valgrind.
+
+==== Results
+
+No memory errors or leaks were revealed by AddressSanetizer when running the `OP_SHA256` bench test for 30 minutes.
+
+==== Procedure
+
+AddressSanitizer is included with Clang/LLVM
+
+. Compilation of Bitcoin Core is done using the following `cmake` flags:
++
+----- 
+$ cmake -B build \
+    -DWITH_ZMQ=ON \
+    -DBUILD_BENCH=ON \
+    -DCMAKE_C_COMPILER=clang \
+    -DCMAKE_CXX_COMPILER=clang++ \
+    -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
+    -DSANITIZERS=address,undefined
+
+$ cmake --build build -j$(nproc) 
+-----
+
+. Check that ASan is statically linked to the _bench_bitcoin_ exeutable:
++
+-----
+$ nm build/bin/bench_bitcoin | grep asan | more
+0000000000148240 T __asan_address_is_poisoned
+00000000000a2fe6 t __asan_check_load_add_16_R13
+
+...
+
+000000000316c828 b _ZZN6__asanL18GlobalsByIndicatorEmE20globals_by_indicator
+0000000003170ccc b _ZZN6__asanL7AsanDieEvE9num_calls
+-----
+
+. Set the following environment variable:
++
+-----
+$ export ASAN_OPTIONS="halt_on_error=0:detect_leaks=1:log_path=/tmp/asan_logs/asan"
+-----
++
+Doing so ensures that _address sanitizer_ :
+
+.. avoids halting on the first error
+.. is enable memory leak detection
+.. writes ASAN related logs to a specified directory
+
 == Test Environment
 
 *  Fedora 42 

From a7419a1203fd05d0ac99ae6241df2c10383733a1 Mon Sep 17 00:00:00 2001
From: D++ <82842780+dplusplus1024@users.noreply.github.com>
Date: Wed, 2 Jul 2025 20:16:56 -0700
Subject: [PATCH 059/131] Remove dashes in BIP numbers and change to SegWit
 version 2
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Updated BIP references to follow the common convention of using a space after “BIP” (e.g., “BIP 173” instead of “BIP-173”).

Also changed SegWit version from 3 to 2. While bc1r was a fun nod to "quantum (r)esistant," jumping versions arbitrarily for stylistic reasons isn’t ideal.
---
 bip-0360.mediawiki | 44 ++++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index 001664ffb3..18623ea369 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -105,7 +105,7 @@ quantum attack:
 |-
 | P2TR || Yes || bc1p || bc1p92aslsnseq786wxfk3ekra90ds9ku47qttupfjsqmmj4z82xdq4q3rr58u
 |-
-| P2QRH || No || bc1r || bc1r8rt68aze8tek87cnz4ndnvfzk6tk93jv39n4lmpu5a4yw453rcpszsft3z
+| P2QRH || No || bc1z || bc1z8rt68aze8tek87cnz4ndnvfzk6tk93jv39n4lmpu5a4yw453rcpszsft3z
 |}
 
 ¹ Funds in P2PKH, P2SH, P2WPKH, and P2WSH outputs become vulnerable to long-exposure quantum attacks when their input script is revealed. An address is no longer safe against long-exposure quantum attacks after funds from it have been spent.
@@ -114,7 +114,7 @@ It should be noted that Taproot outputs are vulnerable in that they encode a 32-
 full public key can be reconstructed.
 
 If a CRQC recovers an extended public key (xpub), including its chain code, it can derive all non-hardened child public
-keys by guessing or iterating through child indexes, as allowed by BIP-32's non-hardened derivation. With Shor's
+keys by guessing or iterating through child indexes, as allowed by BIP 32's non-hardened derivation. With Shor's
 algorithm, the CRQC could then compute the corresponding non-hardened child private keys directly from those public keys,
 without needing the extended private key (xprv) or an exposed child private key. Hardened child keys remain secure since
 they cannot be derived from the xpub alone. However, if the xprv is exposed, then all child private keys--both hardened
@@ -172,9 +172,9 @@ using Grover's algorithm would require at least 10^24 quantum operations. As for
 This is the first in a series of BIPs under a QuBit soft fork. A qubit is a fundamental unit of quantum computing, and
 the capital B refers to Bitcoin. The name QuBit also rhymes to some extent with SegWit.
 
-It is proposed to use SegWit version 3. This results in addresses that start with bc1r, which could be a useful way to
-remember that these are quantum (r)esistant addresses. This is referencing the lookup table under
-[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173].
+It is proposed to use SegWit version 2, yielding addresses that start with bc1z. Z is the last letter in the alphabet,
+which gives it a futuristic feel, fitting for quantum-safe addresses.
+This follows the address format defined in [BIP 173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32).
 
 P2QRH is meant to be implemented on top of P2TR, combining the security of classical Schnorr signatures along with
 post-quantum cryptography. This is a form of hybrid cryptography such that no regression in security is presented
@@ -189,11 +189,11 @@ provide approximately 2^128 security against Grover's algorithm. The practical i
 remains theoretical since quantum circuits for SHA-256 are still theoretical, but using the same hash function as
 Proof of Work maintains consistency with Bitcoin's existing security model. This hash serves as a minimal cryptographic
 commitment to a public key in the style of a
-[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#user-content-Witness_program BIP-141 witness program].
+[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#user-content-Witness_program BIP 141 witness program].
 Because it goes into the scriptPubKey, it does not receive a witness or attestation discount.
 
 Post-quantum public keys are generally larger than those used by ECC, depending on the security level.
-Originally BIP-360 proposed NIST Level V, 256-bit security, but this was changed to NIST Level I, 128-bit security
+Originally BIP 360 proposed NIST Level V, 256-bit security, but this was changed to NIST Level I, 128-bit security
 due to concerns over the size of the public keys, the time it would take to verify signatures, and being generally
 deemed "overkill".
 
@@ -239,11 +239,11 @@ attack, while P2QS is quantum secure. These will require specialized quantum har
 
 While P2QRH lacks features like signature aggregation for smaller transactions, it offers a pragmatic first step
 toward quantum resistance. Future BIPs can add enhancements like P2QS, signature aggregation, and possibly full
-BIP-32 compatibility once tested and viable. Until quantum cryptography hardware and advanced schemes are widespread,
+BIP 32 compatibility once tested and viable. Until quantum cryptography hardware and advanced schemes are widespread,
 P2QRH provides meaningful protection against quantum threats without delaying deployment for a perfect solution.
 
-Additional follow-on BIPs will be needed to implement P2QS, signature aggregation, and full BIP-32 compatibility
-(if possible) BIP-32 relies on elliptic curve operations to derive keys from xpubs to support
+Additional follow-on BIPs will be needed to implement P2QS, signature aggregation, and full BIP 32 compatibility
+(if possible) BIP 32 relies on elliptic curve operations to derive keys from xpubs to support
 watch-only wallets, which PQC schemes may not support.. However, until specialized quantum cryptography hardware
 is widespread and signature aggregation schemes are thoroughly vetted, P2QRH addresses should be an adequate
 intermediate solution that provides meaningful protection against quantum threats.
@@ -298,13 +298,13 @@ output.
 
 === Address Format ===
 
-P2QRH uses SegWit version 3 outputs, resulting in addresses that start with bc1r, following
-[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. Bech32 encoding maps version 3 to the
+P2QRH uses SegWit version 3 outputs, resulting in addresses that start with bc1z, following
+[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP 173]. Bech32 encoding maps version 3 to the
 prefix r.
 
 Example P2QRH address:
 
-bc1r... (32-byte Bech32m-encoded HASH256 of the HASH256 of the public keys)
+bc1z... (32-byte Bech32m-encoded HASH256 of the HASH256 of the public keys)
 
 === ScriptPubKey ===
 
@@ -387,7 +387,7 @@ Only a single 32-byte X-only secp256k1 public key can be provided as key type 0.
 3. When a secp256k1 key is specified in the key type bitmask, how many keys it commits to is unambiguous.
 4. If multiple keys need to be committed to, they must be aggregated, which saves on transaction size.
 
-This design maintains compatibility for [https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki BIP-114]
+This design maintains compatibility for [https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki BIP 114]
 Taproot Merkelized Alternative Script Tree (MAST) merkle root in the commitment, which makes P2QRH a
 quantum-resistant version of Taproot transactions. The TapScript itself must however be provided in the witness,
 as no script execution is allowed in the attestation.
@@ -407,7 +407,7 @@ bitmask will indicate how many keys of each type are present.
 
 === Transaction Serialization ===
 
-Following BIP-141, a new transaction serialization format is introduced to include an attestation field after the witness field:
+Following BIP 141, a new transaction serialization format is introduced to include an attestation field after the witness field:
 
   [nVersion][marker][flag][txins][txouts][witness][attestation][nLockTime]
 
@@ -494,7 +494,7 @@ indicates which algorithm was used.
 
 Supported PQC algorithms and their NIST Level I parameters:
 
-* '''secp256k1 - BIP-340 - Schnorr + X-Only'''
+* '''secp256k1 - BIP 340 - Schnorr + X-Only'''
 ** Key Type 0
 ** Public Key Length: 32 bytes
 ** Signature Length: 64 bytes
@@ -553,7 +553,7 @@ enough keys to meet the threshold are provided.
 
 ==== Sighash Calculation ====
 
-The sighash for P2QRH outputs follows the same procedure as defined in [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341] for Taproot transactions:
+The sighash for P2QRH outputs follows the same procedure as defined in [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP 341] for Taproot transactions:
 
 * '''Signature Message:''' A single-SHA256 of a tagged hash with the tag "TapSighash", containing transaction data.
 * '''Tagged Hash:''' Computed as H(tag || tag || data) where H is SHA256 and tag is the SHA256 of the tag name.
@@ -562,7 +562,7 @@ The sighash for P2QRH outputs follows the same procedure as defined in [https://
 
 This signature hash construction ensures transaction malleability is prevented while providing flexibility through
 different sighash types (DEFAULT, ALL, NONE, SINGLE, and ANYONECANPAY variants). The exact computation follows the
-procedure specified in BIP-341 to maintain compatibility with Taproot signatures.
+procedure specified in BIP 341 to maintain compatibility with Taproot signatures.
 
 If a sighash flag other than DEFAULT is needed, it can be placed in the transaction witness. In this case, it will be
 the only field in the witness.
@@ -584,11 +584,11 @@ Signature verification is as follows:
 4. Ensure that the signature algorithm used matches the expected lengths for NIST Level I security, and is supported by
 the implementation.
 
-=== Compatibility with BIP-141 ===
+=== Compatibility with BIP 141 ===
 
 By adhering to the SegWit transaction structure and versioning, P2QRH outputs are compatible with existing transaction
 processing rules. Nodes that do not recognize SegWit version 3 will treat these outputs as anyone-can-spend but, per
-[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP-141], will not relay or mine such transactions.
+[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP 141], will not relay or mine such transactions.
 
 === Usage Considerations ===
 
@@ -696,7 +696,7 @@ TBD
 It is worth noting by way of comparison that
 [https://ethresear.ch/t/how-to-hard-fork-to-save-most-users-funds-in-a-quantum-emergency/18901 Vitalik Buterin's
 proposed solution] in an Ethereum quantum emergency is quite different from the approach in this BIP. His plan involves
-a hard fork of the chain, reverting all blocks after a sufficient amount of theft, and using STARKs based on BIP-32
+a hard fork of the chain, reverting all blocks after a sufficient amount of theft, and using STARKs based on BIP 32
 seeds to act as the authoritative secret when signing. These measures are deemed far too heavy-handed for Bitcoin.
 
 == References ==
@@ -729,7 +729,7 @@ To help implementors understand updates to this BIP, we keep a list of substanti
 
 == Acknowledgements ==
 
-This document is inspired by [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341], which introduced
+This document is inspired by [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP 341], which introduced
 the design of the P2TR (Taproot) output type using Schnorr signatures.
 
 Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name

From 4ed8dcbcf6ffbf6590d76082388bed0cee9a4036 Mon Sep 17 00:00:00 2001
From: D++ <82842780+dplusplus1024@users.noreply.github.com>
Date: Wed, 2 Jul 2025 21:16:21 -0700
Subject: [PATCH 060/131] Removed more dashes and continued changes for moving
 version to 2

---
 bip-0360.mediawiki | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index 18623ea369..82f20ed56f 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -110,7 +110,7 @@ quantum attack:
 
 ¹ Funds in P2PKH, P2SH, P2WPKH, and P2WSH outputs become vulnerable to long-exposure quantum attacks when their input script is revealed. An address is no longer safe against long-exposure quantum attacks after funds from it have been spent.
 
-It should be noted that Taproot outputs are vulnerable in that they encode a 32-byte x-only public key, from which a
+It should be noted that Taproot outputs are vulnerable in that they encode a 32 byte x-only public key, from which a
 full public key can be reconstructed.
 
 If a CRQC recovers an extended public key (xpub), including its chain code, it can derive all non-hardened child public
@@ -182,7 +182,7 @@ should a vulnerability exist in one of the signature algorithms used. One key di
 however is that P2QRH will encode a hash of the public key. This is a significant deviation from how Taproot works by
 itself, but it is necessary to avoid exposing public keys on-chain where they are vulnerable to attack.
 
-P2QRH uses a 32-byte HASH256 (specifically SHA-256 twice-over) of the public key to reduce the size of new outputs and
+P2QRH uses a 32 byte HASH256 (specifically SHA-256 twice-over) of the public key to reduce the size of new outputs and
 also to increase security by not having the public key available on-chain. While HASH256 uses double SHA-256 like
 Bitcoin's Proof of Work, this does not meaningfully increase quantum resistance compared to single SHA-256, as both
 provide approximately 2^128 security against Grover's algorithm. The practical impact of quantum attacks on SHA-256
@@ -298,28 +298,28 @@ output.
 
 === Address Format ===
 
-P2QRH uses SegWit version 3 outputs, resulting in addresses that start with bc1z, following
-[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP 173]. Bech32 encoding maps version 3 to the
-prefix r.
+P2QRH uses SegWit version 2 outputs, resulting in addresses that start with bc1z, following
+[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP 173]. Bech32 encoding maps version 2 to the
+prefix z.
 
 Example P2QRH address:
 
-bc1z... (32-byte Bech32m-encoded HASH256 of the HASH256 of the public keys)
+bc1z... (32 byte Bech32m-encoded HASH256 of the HASH256 of the public keys)
 
 === ScriptPubKey ===
 
 The scriptPubKey for a P2QRH output is:
 
-  OP_PUSHNUM_3 OP_PUSHBYTES_32 
+  OP_PUSHNUM_2 OP_PUSHBYTES_32 <32 byte hash>
 
 Where:
 
-* OP_PUSHNUM_3 (0x03) indicates SegWit version 3.
-*  is the 32-byte HASH256 of the commitment, as defined in the Hash Commitment section below.
+* OP_PUSHNUM_2 (0x03) indicates SegWit version 2.
+*  is the 32 byte HASH256 of the commitment, as defined in the Hash Commitment section below.
 
 ==== Key Type Bitmask ====
 
-The key type bitmask is a 1-byte value that indicates the type of key used in the commitment. It is encoded as follows:
+The key type bitmask is a 1 byte value that indicates the type of key used in the commitment. It is encoded as follows:
 
 * 0x01 - Key type 0 - secp256k1
 * 0x02 - Key type 1 - FALCON-512
@@ -380,7 +380,7 @@ selective disclosure.
 A threshold is provided to indicate the number of signatures required to spend the output. This is used in the
 cryptographic commitment in the hash computation and revealed in the attestation when spent.
 
-Only a single 32-byte X-only secp256k1 public key can be provided as key type 0. There are a few reasons for this:
+Only a single 32 byte X-only secp256k1 public key can be provided as key type 0. There are a few reasons for this:
 
 1. It maintains Taproot compatibility by removing ambiguity which key is representative of the Taptree.
 2. It prevents abuse of public keys to store arbitrary data once quantum computing is ubiquitous.
@@ -535,7 +535,7 @@ To spend a P2QRH output, the following conditions must be met:
 
 1. The scriptPubKey must be of the form:
 
-OP_PUSHNUM_3 <32-byte hash>
+OP_PUSHNUM_2 OP_PUSHBYTES_32 <32 byte hash>
 
 2. The attestation must include:
 
@@ -587,7 +587,7 @@ the implementation.
 === Compatibility with BIP 141 ===
 
 By adhering to the SegWit transaction structure and versioning, P2QRH outputs are compatible with existing transaction
-processing rules. Nodes that do not recognize SegWit version 3 will treat these outputs as anyone-can-spend but, per
+processing rules. Nodes that do not recognize SegWit version 2 will treat these outputs as anyone-can-spend but, per
 [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP 141], will not relay or mine such transactions.
 
 === Usage Considerations ===
@@ -615,7 +615,7 @@ choose to implement support for multiple algorithms in wallets and on nodes to o
 
 ==== Backward Compatibility ====
 
-Older wallets and nodes that have not been made compatible with SegWit version 3 and P2QRH will not recognize these
+Older wallets and nodes that have not been made compatible with SegWit version 2 and P2QRH will not recognize these
 outputs. Users should ensure they are using updated wallets and nodes to use P2QRH addresses and validate transactions
 using P2QRH outputs.
 

From 32cf0bd612d7d9fa0ad2176d178d6520ec956422 Mon Sep 17 00:00:00 2001
From: jbride 
Date: Fri, 4 Jul 2025 12:38:31 -0600
Subject: [PATCH 061/131] p2qrh: pure p2tr script path spend test vector

---
 .../ref-impl/rust/tests/p2qrh_construction.rs |   2 +-
 bip-0360/ref-impl/rust/tests/p2qrh_spend.rs   | 201 ++++++++++++++++--
 2 files changed, 182 insertions(+), 21 deletions(-)

diff --git a/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs b/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs
index 98999ca376..baac428251 100644
--- a/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs
+++ b/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs
@@ -136,7 +136,7 @@ fn process_test_vector_p2qrh(test_vector: &TestVector) -> anyhow::Result<()> {
                 debug!("traverse_with_depth: leaf_count: {}, depth: {}, modified_depth: {}, direction: {}, tv_leaf_script: {}", 
                     tv_leaf_count, depth, modified_depth, direction, tv_leaf.script);
                 
-                // NOTE: Some of the the test vectors in this project specify leaves with non-standardversions (ie: 250 / 0xfa)
+                // NOTE: Some of the the test vectors in this project specify leaves with non-standard versions (ie: 250 / 0xfa)
                 p2qrh_builder = p2qrh_builder.clone().add_leaf_with_ver(depth, tv_leaf_script_buf.clone(), tv_leaf_version)
                     .unwrap_or_else(|e| {
                         panic!("Failed to add leaf: {:?}", e);
diff --git a/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs b/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs
index d4b149c10c..c76e8ad7e1 100644
--- a/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs
+++ b/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs
@@ -1,10 +1,22 @@
-use log::debug;
+use log::{debug, info};
 use once_cell::sync::Lazy;
 
-use bitcoin::blockdata::witness::Witness;
-use bitcoin::ScriptBuf;
-
-use p2qrh_ref::data_structures::{TestVector, TestVectors};
+use bitcoin::sighash::{EcdsaSighashType, Prevouts, TapSighash};
+use bitcoin::hashes::Hash;
+use bitcoin::secp256k1::{Message, Secp256k1, SecretKey};
+use bitcoin::ecdsa::Signature;
+use bitcoin::{ Amount, TxOut, sighash::TapSighashType, transaction, ScriptBuf, WPubkeyHash,
+    OutPoint,
+    blockdata::witness::Witness,
+    sighash::SighashCache,
+    taproot::{LeafVersion, TapLeafHash},
+    transaction::Transaction,
+};
+
+use p2qrh_ref::{
+    data_structures::{TestVector, TestVectors},
+    serialize_script,
+};
 
 static TEST_VECTORS: Lazy = Lazy::new(|| {
     let bip360_test_vectors = include_str!("../tests/data/p2qrh_spend.json");
@@ -16,24 +28,177 @@ static TEST_VECTORS: Lazy = Lazy::new(|| {
 static P2QRH_SINGLE_LEAF_SCRIPT_TREE_NO_SIGS_TEST: &str = "p2qrh_single_leaf_script_tree_no_sigs";
 
 /*  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.
- */
+   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_p2qrh_single_leaf_script_tree_no_sigs() {
+fn test_script_path_spend_simple() {
     let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
 
-    let test_vectors: &TestVectors = &*TEST_VECTORS;
-    let test_vector: &TestVector = test_vectors.test_vector_map.get(P2QRH_SINGLE_LEAF_SCRIPT_TREE_NO_SIGS_TEST).unwrap();
+    let script_inputs_count = hex::decode("03").unwrap();
+    let script_inputs_bytes: Vec = hex::decode("08").unwrap();
+    let leaf_script_bytes: Vec = hex::decode("5887").unwrap();
+    let control_block_bytes: Vec =
+        hex::decode("c1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap();
+    let test_witness_bytes: Vec = 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 = derived_witness.iter().flatten().cloned().collect();
+
+    assert_eq!(derived_witness_vec, test_witness_bytes);
+}
+
+
+// https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature
+#[test]
+fn test_script_path_spend_signatures() {
+    let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
+
+    let input_tx_id_bytes =
+        hex::decode("d1c40446c65456a9b11a9dddede31ee34b8d3df83788d98f690225d2958bfe3c").unwrap();
+
+    let input_leaf_script_bytes: Vec =
+        hex::decode("206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac").unwrap();
+    let input_control_block_bytes: Vec =
+        hex::decode("c0924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap();
+    let input_script_pubkey_bytes: Vec =
+        hex::decode("5120f3778defe5173a9bf7169575116224f961c03c725c0e98b8da8f15df29194b80")
+            .unwrap();
+    let input_script_priv_key_bytes: Vec = hex::decode("9b8de5d7f20a8ebb026a82babac3aa47a008debbfde5348962b2c46520bd5189").unwrap();
 
-    let mut witness: Witness= Witness::new();
+    let spend_pubkey_hash_bytes: Vec = hex::decode("0de745dc58d8e62e6f47bde30cd5804a82016f9e").unwrap();
+
+    let test_sighash_bytes: Vec = hex::decode("752453d473e511a0da2097d664d69fe5eb89d8d9d00eab924b42fc0801a980c9").unwrap();
+    let test_p2wpkh_signature_bytes: Vec = hex::decode("01769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f01").unwrap();
+    let test_witness_bytes: Vec = hex::decode("034101769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f0122206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac21c0924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap();
+
+    let mut txid_little_endian = input_tx_id_bytes.clone();
+    txid_little_endian.reverse();
 
     
-    test_vector.given.script_inputs.as_ref().unwrap().iter().for_each(|tv_script_input| {
-        let script_input_bytes = hex::decode(tv_script_input).unwrap();
-        witness.push(script_input_bytes);
-        
-    });
+    // vin: Create TxIn from the input utxo
+    // Details of this input tx are not known at this point
+    let input_tx_in = bitcoin::TxIn {
+        previous_output: OutPoint {
+            txid: bitcoin::Txid::from_slice(&txid_little_endian).unwrap(), // bitcoin::Txid expects the bytes in little-endian format
+            vout: 0,
+        },
+        script_sig: ScriptBuf::new(), // Empty for segwit transactions - script goes in witness
+        sequence: transaction::Sequence::MAX, // Default sequence, allows immediate spending (no RBF or timelock)
+        witness: bitcoin::Witness::new(), // Empty for now, will be filled with signature and pubkey after signing
+    };
+
+    let spend_wpubkey_hash = WPubkeyHash::from_byte_array(spend_pubkey_hash_bytes.try_into().unwrap());
+    let spend_output: TxOut = TxOut {
+        value: Amount::from_sat(15000),
+        script_pubkey: ScriptBuf::new_p2wpkh(&spend_wpubkey_hash),
+    };
+
+    // The spend tx to eventually be signed and broadcast
+    let mut unsigned_spend_tx = Transaction {
+        version: bitcoin::transaction::Version::TWO,
+        lock_time: bitcoin::locktime::absolute::LockTime::ZERO,
+        input: vec![input_tx_in],
+        output: vec![spend_output],
+    };
+
+    // Create SighashCache
+    // At this point, sighash_cache does not know the values and type of input UTXO
+    let mut tapscript_sighash_cache = SighashCache::new(&mut unsigned_spend_tx);
+
+    // Create the leaf hash
+    let leaf_version = LeafVersion::TapScript;
+    let leaf_script = ScriptBuf::from_bytes(input_leaf_script_bytes.clone());
+    let leaf_hash: TapLeafHash = TapLeafHash::from_script(&leaf_script, leaf_version);
+
+    /*  prevouts parameter tells the sighash algorithm:
+            1. The value of each input being spent (needed for fee calculation and sighash computation)
+            2. The scriptPubKey of each input being spent (ie: type of output & how to validate the spend)
+     */
+    let prevouts = vec![TxOut {
+        value: Amount::from_sat(20000),
+        script_pubkey: ScriptBuf::from_bytes(input_script_pubkey_bytes.clone()),
+    }];
+    info!("prevouts: {:?}", prevouts);
+
+    // Compute the sighash
+    let tapscript_sighash: TapSighash = tapscript_sighash_cache.taproot_script_spend_signature_hash(
+        0, // input_index
+        &Prevouts::All(&prevouts),
+        leaf_hash,
+        TapSighashType::All
+    ).unwrap();
+
+    assert_eq!(tapscript_sighash.as_byte_array().as_slice(), test_sighash_bytes.as_slice(), "sighash mismatch");
+    info!("sighash: {:?}", tapscript_sighash);
+
+    let spend_msg = Message::from(tapscript_sighash);
+
+    // Signing: Sign the sighash using the secp256k1 library (re-exported by rust-bitcoin).
+    let secp = Secp256k1::new();
+    let secret_key = SecretKey::from_slice(&input_script_priv_key_bytes).unwrap();
+
+    // Spending a p2tr UTXO thus using Schnorr signature
+    // The aux_rand parameter ensures that signing the same message with the same key produces the same signature
+    let p2wpkh_signature: bitcoin::secp256k1::schnorr::Signature = secp.sign_schnorr_with_aux_rand(
+        &spend_msg, 
+        &secret_key.keypair(&secp), 
+        &[0u8; 32] // 32 zero bytes of auxiliary random data
+    );
+    let mut p2wpkh_sig_bytes: Vec = p2wpkh_signature.serialize().to_vec();
+    p2wpkh_sig_bytes.push(EcdsaSighashType::All as u8);
+
+    assert_eq!(p2wpkh_sig_bytes, test_p2wpkh_signature_bytes, "p2wpkh_signature mismatch");
+    let p2wpkh_sig_hex = hex::encode(p2wpkh_sig_bytes.clone());
+    info!("p2wpkh_signature: {:?}", p2wpkh_sig_hex);
+
+    let mut derived_witness: Witness = Witness::new();
+    derived_witness.push(hex::decode("03").unwrap());
+    derived_witness.push(serialize_script(&p2wpkh_sig_bytes));
+    derived_witness.push(serialize_script(&input_leaf_script_bytes));
+    derived_witness.push(serialize_script(&input_control_block_bytes));
+
+    let derived_witness_vec: Vec = derived_witness.iter().flatten().cloned().collect();
+
+    assert_eq!(derived_witness_vec, test_witness_bytes, "derived_witness mismatch");
+
+    let derived_witness_hex = hex::encode(derived_witness_vec);
+    info!("derived_witness_hex: {:?}", derived_witness_hex);
+}
+
+#[test]
+fn test_p2qrh_single_leaf_script_tree_no_sigs() {
+    let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
+
+    let test_vectors: &TestVectors = &*TEST_VECTORS;
+    let test_vector: &TestVector = test_vectors
+        .test_vector_map
+        .get(P2QRH_SINGLE_LEAF_SCRIPT_TREE_NO_SIGS_TEST)
+        .unwrap();
+
+    let mut witness: Witness = Witness::new();
+
+    test_vector
+        .given
+        .script_inputs
+        .as_ref()
+        .unwrap()
+        .iter()
+        .for_each(|tv_script_input| {
+            let script_input_bytes = hex::decode(tv_script_input).unwrap();
+            witness.push(script_input_bytes);
+        });
 
     // Hint:  use https://learnmeabitcoin.com/technical/script/
     let tv_script_hex = test_vector.given.script_hex.as_ref().unwrap();
@@ -56,8 +221,4 @@ fn test_p2qrh_single_leaf_script_tree_no_sigs() {
 
     let expected_witness = test_vector.expected.witness.as_ref().unwrap();
     assert_eq!(&witness_hex_string, expected_witness);
-    
 }
-
-
-

From a375b65e2df340915a74bff5401a8bc83472b1a3 Mon Sep 17 00:00:00 2001
From: Ethan Heilman 
Date: Mon, 7 Jul 2025 11:02:27 -0400
Subject: [PATCH 062/131] Changes BIP-360 to use tapscript (#21)

* Rewrote rationale

* Fix bolded principles

* Actually fix bold

* Updates to talk about signature + public key size rather than just signature size

* Took a pass over rationale

* Started work on specification

* Adds example tapscript hybrid signatures

* More work on the specification

* Cleans up TODO

* Fixing grammar, other minor changes

* SHL --> SLH

* Apply suggestions from code review

Co-authored-by: Hunter Beast 

* Adds discussion of SQIsign

* Fixes broken llink to libbitcoinpqc

Co-authored-by: Hunter Beast 

* Fixes writing in SQIsign section

Co-authored-by: Hunter Beast 

* Add rational section on big signatures and public keys

* Fixes typos

* Adds script validation from BIP 341

* Add commas

* Add design section, stack element size increase now in PQ sigs

* Fixes typo

* Fixes typos and formatting

Co-authored-by: Hunter Beast 

* Add authorship to readme

* Add diagram of P2QRH merke tree, scriptPubKey and Witness

* Remove completed todo

* Add security section

* Clean up wording, moves some things around

* Minor rewording

* Review suggestions

Co-authored-by: Hunter Beast 

* Clarified size differences

* Changed header size and order

* does --> doUpdate bip-0360.mediawiki

Co-authored-by: Hunter Beast 

* Add related work section

* Better scale figure

* Respond to review comments

* remove double space

Co-authored-by: Armin Sabouri 

* Address review comments

* Addressing Ademan comments

* Sync source svg

* Address review

* Addresses review

* Apply suggestions from code review

Co-authored-by: Joey Yandle 

* Update bip-0360.mediawiki

Co-authored-by: Joey Yandle 

* Update bip-0360.mediawiki

Co-authored-by: Joey Yandle 

* Addressing review comments

* Addressing reviews

---------

Co-authored-by: Hunter Beast 
Co-authored-by: Armin Sabouri 
Co-authored-by: Joey Yandle 
---
 README.mediawiki        |    2 +-
 bip-0360.mediawiki      |  749 ++++++++--------
 bip-0360/merkletree.png |  Bin 0 -> 75700 bytes
 bip-0360/merkletree.svg | 1874 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 2244 insertions(+), 381 deletions(-)
 create mode 100644 bip-0360/merkletree.png
 create mode 100644 bip-0360/merkletree.svg

diff --git a/README.mediawiki b/README.mediawiki
index daf3248d0c..42c54577f6 100644
--- a/README.mediawiki
+++ b/README.mediawiki
@@ -1173,7 +1173,7 @@ Those proposing changes should consider that ultimately consent may rest with th
 | [[bip-0360.mediawiki|360]]
 | Consensus (soft fork)
 | Pay to Quantum Resistant Hash
-| Hunter Beast
+| Hunter Beast, Ethan Heilman
 | Standard
 | Draft
 |- style="background-color: #cfffcf"
diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki
index 001664ffb3..66a28a08f4 100644
--- a/bip-0360.mediawiki
+++ b/bip-0360.mediawiki
@@ -3,6 +3,7 @@
   Title: Pay to Quantum Resistant Hash
   Layer: Consensus (soft fork)
   Author: Hunter Beast 
+          Ethan Heilman 
   Comments-Summary: No comments yet.
   Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0360
   Status: Draft
@@ -11,13 +12,16 @@
   License: BSD-3-Clause
 
- == Introduction == === Abstract === -This document proposes the introduction of a new output type using signatures based on Post-Quantum Cryptography (PQC). -This approach for adding a post-quantum secure output type does not require a hard fork or block size increase. +This document proposes the introduction of a new output type, Pay to Quantum Resistant Hash (P2QRH), via a soft fork. +P2QRH provides the same tapscript functionality as Pay to TapRoot (P2TR) but removes the quantum-vulnerable +key-spend path in P2TR. By itself, P2QRH provides protection against long-exposure quantum attacks, +but requires PQ signatures to provide full security against Cryptanalytically-Relevant Quantum Computing (CRQCs). +P2QRH is designed to provide the foundation necessary for a future soft fork activating PQ signature verification +in tapscript. === Copyright === @@ -25,7 +29,7 @@ This document is licensed under the 3-clause BSD license. === Motivation === -The primary threat to Bitcoin from Cryptoanalytically-Relevant Quantum Computers (CRQCs) +The primary threat to Bitcoin from Cryptanalytically-Relevant Quantum Computing (CRQCs) A Cryptoanalytically-Relevant Quantum Computer is an ''object'' which is only loosely defined by ''characteristics'' in quantum physics as of today. It could be understood in the context of this BIP and in bitcoin that it's a ''hardware-agnostic'' computer supposed to have the architecture to keep ''coherent'' a sufficient number of logical qubits to be able to run the Shor algorithm in an efficient fashion. is their potential to break the cryptographic assumptions of Elliptic Curve Cryptography (ECC), which secures Bitcoin's signatures and Taproot commitments. Specifically, [https://arxiv.org/pdf/quant-ph/0301141 Shor's algorithm] enables a CRQC to solve the @@ -39,7 +43,7 @@ offering insufficient protection. The computational complexity of this attack is [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault-tolerant regime'']. This proposal aims to mitigate these risks by introducing a Pay to Quantum Resistant Hash (P2QRH) output type that -relies on PQC signature algorithms. By adopting PQC, Bitcoin can enhance its quantum +makes tapscript quantum resistant and enables the use of PQ signature algorithms. By adopting PQC, Bitcoin can enhance its quantum resistance without requiring a hard fork or block size increase. The vulnerability of existing Bitcoin addressesA vulnerable Bitcoin address is any @@ -79,8 +83,9 @@ As the value being sent increases, so too should the fee in order to commit the possible. Once the transaction is mined, it makes useless the public key revealed by spending a UTXO, so long as it is never reused. -It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) output type that relies on a PQC signature -algorithm. This new output type protects transactions submitted to the mempool and helps preserve the free market by +As the first step to address these issues we propose Pay to Quantum Resistant Hash (P2QRH), an output type that allows +tapscript to be used in a quantum resistant manner. +This new output type protects transactions submitted to the mempool and helps preserve the fee market by preventing the need for private, out-of-band mempool transactions. The following table is intended to inform the average Bitcoin user whether their bitcoin is vulnerable to a long-exposure @@ -167,389 +172,307 @@ HASH160 Used by P2PKH, P2SH, and P2WPKH addresses, though no using Grover's algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques' post on this]. -=== Rationale === +=== Design === This is the first in a series of BIPs under a QuBit soft fork. A qubit is a fundamental unit of quantum computing, and -the capital B refers to Bitcoin. The name QuBit also rhymes to some extent with SegWit. +the capital B refers to Bitcoin. The name QuBit also rhymes to some extent with SegWit. This BIP proposes a new output type +called P2QRH (Pay to Quantum Resistant Hash). This output type is designed to support post-quantum signature algorithms +but those algorithms will be specified in future BIPs. It is proposed to use SegWit version 3. This results in addresses that start with bc1r, which could be a useful way to remember that these are quantum (r)esistant addresses. This is referencing the lookup table under [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. -P2QRH is meant to be implemented on top of P2TR, combining the security of classical Schnorr signatures along with -post-quantum cryptography. This is a form of hybrid cryptography such that no regression in security is presented -should a vulnerability exist in one of the signature algorithms used. One key distinction between P2QRH and P2TR -however is that P2QRH will encode a hash of the public key. This is a significant deviation from how Taproot works by -itself, but it is necessary to avoid exposing public keys on-chain where they are vulnerable to attack. - -P2QRH uses a 32-byte HASH256 (specifically SHA-256 twice-over) of the public key to reduce the size of new outputs and -also to increase security by not having the public key available on-chain. While HASH256 uses double SHA-256 like -Bitcoin's Proof of Work, this does not meaningfully increase quantum resistance compared to single SHA-256, as both -provide approximately 2^128 security against Grover's algorithm. The practical impact of quantum attacks on SHA-256 -remains theoretical since quantum circuits for SHA-256 are still theoretical, but using the same hash function as -Proof of Work maintains consistency with Bitcoin's existing security model. This hash serves as a minimal cryptographic -commitment to a public key in the style of a -[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#user-content-Witness_program BIP-141 witness program]. -Because it goes into the scriptPubKey, it does not receive a witness or attestation discount. - -Post-quantum public keys are generally larger than those used by ECC, depending on the security level. -Originally BIP-360 proposed NIST Level V, 256-bit security, but this was changed to NIST Level I, 128-bit security -due to concerns over the size of the public keys, the time it would take to verify signatures, and being generally -deemed "overkill". - -Support for FALCON signatures will be introduced first, with the intention of adding other post-quantum -algorithms as they are approved. By way of comparison, FALCON signatures are roughly 20x larger than Schnorr signatures. -FALCON has recently been approved by NIST. NIST approval streamlines implementations through establishing -consensus in the scientific and developer community. This means, to maintain present transaction throughput, an -increase in the witness discount will likely be desired in a QuBit soft fork. That will be specified in a future QuBit -BIP. - -An increase in the witness discount must not be taken lightly. It must be resistant to applications that might take -advantage of this discount (e.g., storage of arbitrary data as seen with "inscriptions") without a corresponding -increase in economic activity. An increase in the witness discount would not only impact node runners but those with -inscriptions would also have the scarcity of their non-monetary assets affected. The only way to prevent these effects -while also increasing the discount is to have a completely separate witness--a "quantum witness." Because it is meant -only for public keys and signatures, we call this section of the transaction the attestation. - -Additionally, it should be noted, whether an output with a P2QRH spend script corresponds to a PQC signature is not -known until the output is spent. - -While it might be seen as a maintenance burden for Bitcoin ecosystem devs to go from a single cryptosystem -implementation to three additional distinct PQC cryptosystems--and it most certainly is--the ramifications of a chain -broken through extrinsic factors should provide sufficient motivation. An increase in software maintenance everywhere -signatures are used should be seen as an acceptable compromise for maintained integrity of Bitcoin transfers during a -regime of quantum advantage. - -The inclusion of these three cryptosystems: SPHINCS+, CRYSTALS-Dilithium, and FALCON have various advocates -within the community due to their varying security assumptions. Hash-based cryptosystems are more conservative, -time-tested, and well-reviewed. Lattice cryptography is relatively new and introduces novel security assumptions to -Bitcoin, but their signatures are smaller and might be considered by some to be an adequate alternative to hash-based -signatures. - -The reason multiple cryptosystems are included is in the interest of supporting hybrid cryptography, especially for -high value outputs, such as cold wallets used by exchanges. To improve the viability of the activation client and -adoption by wallets and libraries, a library akin to libsecp256k1 will be developed. This library, libbitcoinpqc, -will support the new PQC cryptosystems and can be used as a reference for other language-native implementations. - -In the distant future, following the implementation of the P2QRH output type in a QuBit soft fork, there will likely -be a need for Pay to Quantum Secure (P2QS) addresses. A distinction is made between cryptography that's merely resistant -to quantum attack, and cryptography that's secured by specialized quantum hardware. P2QRH is resistant to quantum -attack, while P2QS is quantum secure. These will require specialized quantum hardware for signing, while still -[https://quantum-journal.org/papers/q-2023-01-19-901/ using public keys that are verifiable via classical means]. - -While P2QRH lacks features like signature aggregation for smaller transactions, it offers a pragmatic first step -toward quantum resistance. Future BIPs can add enhancements like P2QS, signature aggregation, and possibly full -BIP-32 compatibility once tested and viable. Until quantum cryptography hardware and advanced schemes are widespread, -P2QRH provides meaningful protection against quantum threats without delaying deployment for a perfect solution. - -Additional follow-on BIPs will be needed to implement P2QS, signature aggregation, and full BIP-32 compatibility -(if possible) BIP-32 relies on elliptic curve operations to derive keys from xpubs to support -watch-only wallets, which PQC schemes may not support.. However, until specialized quantum cryptography hardware -is widespread and signature aggregation schemes are thoroughly vetted, P2QRH addresses should be an adequate -intermediate solution that provides meaningful protection against quantum threats. - -== Specification == - -We define the signature scheme and transaction structure as follows. - -=== Descriptor Format === - -To integrate P2QRH into existing wallet software and scripts, we introduce a new output descriptor function -qrh(). This function represents a P2QRH output, similar to how wpkh() and tr() -are used for P2WPKH and P2TR outputs, respectively. - -The qrh() function takes a threshold value and multiple key specifications grouped by key type. The format is: - - qrh(threshold, keytype(0x01, [hash1, hash2, ...]), keytype(0x02, [hash1, hash2, ...]), ...) - -Where: - -* threshold is an integer specifying the minimum number of signatures required -* keytype is the hex value representing the key type (0x01 for secp256k1, 0x02 for FALCON-512, 0x04 for CRYSTALS-Dilithium Level I, 0x08 for SPHINCS+-128s) -* [hash1, hash2, ...] is an array of HASH256 hashes of public keys for the corresponding algorithm type - -For example: - - qrh(3, keytype(0x01, hash256(secp256k1_pubkey1), hash256(secp256k1_pubkey2), hash256(secp256k1_pubkey3), secp256k1_pubkey4_hash, secp256k1_pubkey5_hash), - keytype(0x02, hash256(falcon_pubkey1), hash256(falcon_pubkey2), hash256(falcon_pubkey3), falcon_pubkey4_hash, falcon_pubkey5_hash), - keytype(0x04, hash256(dilithium_pubkey1), hash256(dilithium_pubkey2), hash256(dilithium_pubkey3), dilithium_pubkey4_hash, dilithium_pubkey5_hash), - keytype(0x08, hash256(sphincs_pubkey1), hash256(sphincs_pubkey2), hash256(sphincs_pubkey3), sphincs_pubkey4_hash, sphincs_pubkey5_hash)) - -This represents a 3-of-5 multisig for each key type, with a total of 20 keys: 5 keys per type (3 full public keys and 2 -hashes) across 4 different key types. - -Internally, the descriptor computes the HASH256 of the concatenated HASH256 of all the quantum-resistant public keys, -with the threshold and key type bitmask prepended. For each key in the descriptor: - -- If it is already a hash (indicated in the descriptor), it is used directly -- If it is a public key, HASH256 is applied to it first - -This approach ensures that all items in the vector are HASH256 values, whether they originated from raw public keys or -were provided as hashes. During spending, this allows for selective disclosure of public keys, where some keys can -remain hidden (represented only by their hashes) while others are fully revealed with their corresponding public keys. -This flexibility is particularly valuable in multisig schemes where not all keys need to be revealed to satisfy the -threshold requirement. At a minimum, there should be two different key types in a P2QRH output: one key that makes use -of classical cryptography, and one that makes use of a PQC algorithm chosen within the wallet. - -Also, it's important to note that order of keys and hashes in the descriptor matters and is based on the original -public key values, in addition to the key type. Additionally, qrh() does not compile to script, but instead, describes -what's needed to compute the scriptPubKey hash commitment and also to reveal the attestation needed to spend the -output. - -=== Address Format === - -P2QRH uses SegWit version 3 outputs, resulting in addresses that start with bc1r, following -[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. Bech32 encoding maps version 3 to the -prefix r. - -Example P2QRH address: - -bc1r... (32-byte Bech32m-encoded HASH256 of the HASH256 of the public keys) - -=== ScriptPubKey === - -The scriptPubKey for a P2QRH output is: - - OP_PUSHNUM_3 OP_PUSHBYTES_32 - -Where: - -* OP_PUSHNUM_3 (0x03) indicates SegWit version 3. -* is the 32-byte HASH256 of the commitment, as defined in the Hash Commitment section below. - -==== Key Type Bitmask ==== - -The key type bitmask is a 1-byte value that indicates the type of key used in the commitment. It is encoded as follows: - -* 0x01 - Key type 0 - secp256k1 -* 0x02 - Key type 1 - FALCON-512 -* 0x04 - Key type 2 - CRYSTALS-Dilithium Level I -* 0x08 - Key type 3 - SPHINCS+-128s -* 0x10 - Unused -* 0x20 - Unused -* 0x40 - Unused -* 0x80 - Reserved for if additional key types are added in the future - -Example key type bitmask using all supported key types: - - 0x01 | 0x02 | 0x04 | 0x08 = 0x0F - -==== Hash Commitment ==== - -If there is only a single public key, the hash is computed as the HASH256 of the public key. - -In order to support multiple keys, as in the context of multisig or singlesig hybrid cryptography, the hash is -computed as a commitment to a vector of public key hashes: - -1. Sort the public keys first by key type, then by public key value -2. For each sorted public key, compute its HASH256 -3. Concatenate all the public key hashes in sorted order -4. Prepend key type bitmask and threshold to the concatenated hashes -5. Compute the HASH256 of the result - -For example with 4 public keys: - - // First sort the public keys - sorted_pubkeys = sort_by_key_type_and_value([pubkey1, pubkey2, pubkey3, pubkey4]) - - // Then compute hashes of sorted keys - h1 = HASH256(sorted_pubkeys[0]) - h2 = HASH256(sorted_pubkeys[1]) - h3 = HASH256(sorted_pubkeys[2]) - h4 = HASH256(sorted_pubkeys[3]) - - // Concatenate all hashes - concatenated = h1 || h2 || h3 || h4 +P2QRH (Pay to Quantum Resistant Hash) is a new output type that commits to the root of a tapleaf merkle tree. It is functionally +the same as a P2TR (Pay to Taproot) output with the quantum vulnerable key-spend path removed. Since P2QRH has no key-spend path, P2QRH omits the +taproot internal key as it is not needed. Instead a P2QRH output is just the 32 byte root of the tapleaf merkle tree as defined +in [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341] and hashed with the tag "QuantumRoot" as shown below. - commitment = key_type_bitmask || threshold || concatenated +[[File:bip-0360/merkletree.png|center|550px|thumb|]] - hash = HASH256(commitment) +To construct a P2QRH output we follow the same process as [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341] +to compute the tapscript merkle root. However, instead of the root of the Merkle tree being hashed together with the internal +key in P2QRH the root is hashed by itself using the tag "QuantumRoot". -With sort_by_key_type_and_value defined as: + +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) +Root = tagged_hash("QuantumRoot", ABCDE) + - def sort_by_key_type_and_value(pubkeys): - return sorted(pubkeys, key=lambda x: (x.key_type, x.public_key)) +A P2QRH input witness provides the following: -When spending, if a public key hash is provided in the attestation with an empty signature, that hash will be used -directly in the vector computation rather than hashing the full public key. This allows unused public keys to be -excluded from the transaction while still proving they were part of the original commitment. + +initial stack element 0, +..., +initial stack element N, +tapleaf script, +control block = [control byte, 32 * m byte Merkle path] # m is the depth of the Merkle tree + -The vector construction creates an efficient cryptographic commitment to multiple public keys while enabling -selective disclosure. +The initial stack elements provide the same functionality as they do in P2TR. That is, they place elements on the stack to +be evaluated by the tapleaf script, a.k.a. the redeem script. -A threshold is provided to indicate the number of signatures required to spend the output. This is used in the -cryptographic commitment in the hash computation and revealed in the attestation when spent. +The control block is a 1 + 32 * m byte array, where the first byte is the control byte and the next 32*m bytes are the +Merkle path to the tapleaf script. The control byte is the same as the control byte in a P2TR control block, +including the 7 bits are used to specify the tapleaf version. The parity bit of the control byte is always 1 +since P2QRH does not have a key-spend path. We omit the public key from the control block as it is not needed in P2QRH. +We maintain support for the optional annex in the witness (see specification for more details). -Only a single 32-byte X-only secp256k1 public key can be provided as key type 0. There are a few reasons for this: - -1. It maintains Taproot compatibility by removing ambiguity which key is representative of the Taptree. -2. It prevents abuse of public keys to store arbitrary data once quantum computing is ubiquitous. -3. When a secp256k1 key is specified in the key type bitmask, how many keys it commits to is unambiguous. -4. If multiple keys need to be committed to, they must be aggregated, which saves on transaction size. - -This design maintains compatibility for [https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki BIP-114] -Taproot Merkelized Alternative Script Tree (MAST) merkle root in the commitment, which makes P2QRH a -quantum-resistant version of Taproot transactions. The TapScript itself must however be provided in the witness, -as no script execution is allowed in the attestation. - -In a multisig context, aside from secp256k1 keys, the number of keys provided in the attestation is variable and -must meet the threshold as committed to in the hash computation and revealed in the attestation. - -When the address is generated, all public keys must be known in advance, and they must be sorted, first by key -type, then by public key value, so as to be deterministic. - -The key count does not need to be provided for PQC keys because the key type bitmask and threshold are sufficient -to validate a multisig transaction. - -In a singlesig context, multiple PQC keys can be provided, but the key type bitmask and threshold must still also -be provided to be consistent with the multisig semantics. The threshold will be set as 0x01, and the key type -bitmask will indicate how many keys of each type are present. - -=== Transaction Serialization === - -Following BIP-141, a new transaction serialization format is introduced to include an attestation field after the witness field: - - [nVersion][marker][flag][txins][txouts][witness][attestation][nLockTime] - -* marker: 0x00 (same as SegWit) -* flag: -** 0x02 (indicates the presence of attestation data only) -** 0x03 (indicates the presence of both witness and attestation data) -* attestation: Contains the quantum-resistant public keys and signatures. - -=== Quantum Transaction ID (qtxid) === - -The transaction ID is computed as the HASH256 of the serialized transaction, including the attestation and witness -(if a witness is present). When decoded, this is called the qtxid, which will differ from the txid and wtxid if an -attestation is present. - -=== Attestation Structure === - -The attestation field consists of: - -* key_type_bitmask: A [https://learnmeabitcoin.com/technical/general/compact-size/ compact size] value indicating which key types are present. -* threshold: A compact size value indicating the number of signatures required to spend the output. -* num_pubkeys: The number of public keys (compact size). - -For each public key: - -* key_type: The key type (compact size). Only one bit is used to indicate the key type. -* pubkey_length: compact size length of the public key (compact size). -* pubkey: The public key bytes. - -Then: - -* num_signatures: The number of signatures (compact size). - -For each signature: - -* signature_length: compact size length of the signature. -* signature: The signature bytes. +=== Rationale === -This structure repeats for each input, in order, for flexibility in supporting multisig schemes and various -quantum-resistant algorithms. +Our design to augment Bitcoin with quantum resistance is guided by the following principles: + +'''Minimize changes.''' We should reuse existing Bitcoin code and preserve +existing software behavior, workflows, user expectations and compatibility whenever possible. + +'''Gradual upgrade path.''' We should provide an upgrade path for wallets and exchanges which can be +carried out gradually and iteratively rather than all at once. This is critical as the earlier the ecosystem +begins upgrading to quantum resistance, the lower the number of coins at risk when quantum attacks become practical. + +'''Use standardized post-quantum signature algorithms.''' Standardized algorithms have undergone the most scrutiny and +are likely to be most well supported and well studied going forward. The entire Bitcoin ecosystem will benefit +from using the most popular post-quantum signature algorithms, including leveraging hardware acceleration +instructions, commodity trusted hardware, software libraries and cryptography research. + +'''Provide security against unexpected cryptanalytic breakthroughs.''' Consider the risk +if Bitcoin only supported one PQ signature algorithm, and then following the widespread rollout of CRQCs, a critical +weakness is unexpectedly discovered in this signature algorithm. There would be no safe algorithm available. We believe that +prudence dictates we take such risks seriously and ensure that Bitcoin always has at least two secure signature algorithms built +on orthogonal cryptographic assumptions. In the event one algorithm is broken, an alternative will be available. An added benefit +is that parties seeking to securely store bitcoins over decades can secure their coins under multiple algorithms, +ensuring their coins will not be stolen even in the face of a catastrophic break in one of those signature algorithms. + +Based on these principles, we propose two independent changes that together provide Bitcoin with +full quantum resistance. In this BIP, we introduce a new output type called P2QRH (Pay to Quantum Resistant Hash) so that tapscript +can be used in a quantum resistant manner. In a future BIP, we enable tapscript programs to verify two Post-Quantum (PQ) signature +algorithms, ML-DSA (CRYSTALS-Dilithium) and SLH-DSA (SPHINCS+). It is important to consider these two changes together because P2QRH must +be designed to support the addition of these PQ signature algorithms. The full description of these signatures will be provided in a future BIP. + +==== P2QRH ==== + +P2QRH is simply P2TR with the quantum vulnerable key-spend path removed so that it commits to the root of +the tapleaf merkle tree in the output. This allows P2QRH to reuse the mature and battle tested P2TR, tapleaf +and tapscript code already in Bitcoin. This reduces the implementation burden on wallets, exchanges, and +libraries since they can reuse code they already have. + +Both P2WSH (Pay 2 Witness Script Hash) and P2QRH protect against long-exposure quantum attacks and both provide +the same 256-bit security level. One may ask why not use the existing output type P2WSH instead of add a new one? +The problem with P2WSH is that it only works with pre-tapscript Script and cannot work with tapscript Script. +New protocols and programs in the Bitcoin ecosystem have largely moved to tapscript. Using P2WSH would require turning +back the clock and forcing projects to move from tapscript to pre-tapscript. More importantly, tapscript provides a far +easier and safer upgrade path for adding PQ signatures. Changes to pre-tapscript to enable it to support PQ signatures would likely +require adding tapscript features into pre-tapscript. Even if this was possible, it would represent far more work and +risk than adding a new output type like P2QRH. Tapscript, and thereby a tapscript compatible output such as P2QRH, +is the most plausible and convenient upgrade path to full quantum resistance. + +==== PQ signatures ==== + +By separating P2QRH from the introduction of PQ signatures, relying parties can move from P2TR to P2QRH +without simultaneously having to change from Schnorr signatures to PQ signatures. Simply moving coins from +P2TR to P2QRH protects those coins from long-exposure quantum attacks. Then to gain full quantum resistance, +verification of PQ signatures can be added as an additional tapleaf alongside Schnorr signaturesMatt Corallo, [https://groups.google.com/g/bitcoindev/c/8O857bRSVV8/m/rTrpeFjWDAAJ Trivial QC signatures with clean upgrade path], (2024). +When quantum attacks become practical, users would then be fully protected as the P2QRH output would allow +them to switch to sending their coins using the PQ signature algorithms. This allows the upgrade to quantum +resistance to be largely invisible to users. + +Consider the P2QRH output with three tapscripts: + +* Spend requires a Schnorr signature +* Spend requires a ML-DSA signature +* Spend requires a SLH-DSA signature + +In the event that Schnorr signatures are broken, users can spend their coins using ML-DSA. +If both Schnorr and ML-DSA are broken, the user can still rely on SLH-DSA. +While this pattern allows users to spend their coins securely without revealing the public +keys associated with vulnerable algorithms, the user can compromise their own security if +they leak these public keys in other contexts, e.g. key reuse. + +One intent in supporting Schnorr, ML-DSA, and SLH-DSA in tapscript, is to allow parties to construct outputs such that funds +are still secure even if two of the three the signature algorithms are completely broken. This is motivated by the use case +of securely storing Bitcoins in a cold wallet for very long periods of time (50 to 100 years). + +For PQ signatures we considered the NIST approved SLH-DSA (SPHINCS+), ML-DSA (CRYSTALS-Dilithium), +FN-DSA (FALCON). Of these three algorithms, SLH-DSA has the largest signature size, but is the most conservative +choice from a security perspective because SLH-DSA is based on well studied and time-tested hash-based cryptography. +Both FN-DSA and ML-DSA signatures are significantly smaller than SLH-DSA signatures but are based on newer lattice-based +cryptography. Since ML-DSA and FN-DSA are both similar lattice-based designs, we choose to only support one of them as the +additional value in diversity of cryptographic assumptions would be marginal. It should be noted that ML-DSA and FN-DSA do +rely on different lattice assumptions and it may be that case that a break in one algorithm's assumptions would not necessarily +break the assumptions used by the other other algorithm. + +We also considered SQIsign. While it outperforms the three other PQ signature algorithms by having the smallest signatures, +it has the worst verification performance and requires a much more complex implementation. We may revisit SQIsign separately in the +future as recent research shows massive performance improvements to SQIsign in version 2.0. "[SQIsign] signing is now nearly 20× faster, at 103.0 Mcycles, and verification is more than 6× faster, at 5.1 Mcycles" [https://csrc.nist.gov/csrc/media/Projects/pqc-dig-sig/documents/round-2/spec-files/sqisign-spec-round2-web.pdf SQIsign: Algorithm specifications and supporting documentation Version 2.0 (February 5 2025)]. + +ML-DSA is intended as the main PQ signature algorithm in Bitcoin. It provides a good balance of security, performance +and signature size and is likely to be the most widely supported PQ signature algorithm on the internet. SLH-DSA has a radically +different design and set of cryptographic assumptions than ML-DSA. As such SLH-DSA provides an effective +hedge against an unexpected cryptanalytic breakthrough. + +P2QRH, ML-DSA, and SLH-DSA could be activated simultaneously in a single soft fork or P2QRH could be activated first and then +ML-DSA and SLH-DSA could be independently activated. If at some future point another signature +algorithm was desired it could follow this pattern. + +We consider two different paths for activating PQ signatures in Bitcoin. The first approach is to redefine OP_SUCCESSx opcodes for each +signature algorithm. For ML-DSA this would give us OP_CHECKMLSIG, OP_CHECKMLSIGVERIFY and OP_CHECKMLSIGADD. The second approach is to use a new tapleaf version that changes the OP_CHECKSIG opcodes to support the +new PQ signature algorithms. In both cases, we would need to include as part of the soft fork an increase in the tapscript stack element +size to accommodate the larger signatures and public keys sizes of the PQ signature algorithms. + +The OP_SUCCESSx approach has the advantage of providing a straightforward path to add new signature algorithms in the future. Simply redefine +a set of five OP_SUCCESSx opcodes for the new signature algorithm. This would allow us to activate a single PQ signature at a time, adding +new ones as needed. Additionally this approach allows developers to be very explicit in the signature algorithm type that they wish to verify. +The main disadvantage is that it uses five OP_SUCCESSx opcodes per signature algorithm. Supporting ML-DSA and SLH-DSA would require ten new opcodes. + +Adding PQ signatures via a tapleaf version increase does not introduce any new opcodes and allows previously written tapscript programs to be used with PQ signatures +by simply using the new tapleaf version. Instead of developers explicitly specifying the intended signature algorithm through an opcode, the algorithm +to use must be indicated within the public key or public key hash'''Why not have CHECKSIG infer the algorithm based on signature size?''' Each of the three signature algorithms, Schnorr, ML-DSA, and SLH-DSA, have unique signature sizes. The problem with using signature size to infer algorithm is that spender specifies the signature. This would allow a public key which was intended to be verified by Schnorr to be verified using ML-DSA as the spender specified a ML-DSA signature. Signature algorithms are not often not secure if you can mix and match public key and signature across algorithms.. +The disadvantage of this approach is that it requires a new tapleaf version each time we want to add a new signature algorithm. + +Both approaches must raise the stack element size limit. In the OP_SUCCESSx case, the increased size limit would only be effect for transaction outputs +that use of the new opcodes. Otherwise this stack element size limit increase would be a soft fork. If the tapleaf version is used, then the stack +element size limit increase would apply to any tapscript program with the new tapleaf version. + +To improve the viability of the activation client and adoption by wallets and libraries, a library akin to +libsecp256k1 will be developed. This library, [https://github.com/cryptoquick/libbitcoinpqc libbitcoinpqc], will support the new PQ signature algorithms +and can be used as a reference for other language-native implementations. + +==== PQ signature size ==== + +Post-quantum public keys are generally larger than those used by ECC, depending on the security level. Originally BIP-360 +proposed NIST Level V, 256-bit security, but this was changed to NIST Level I, 128-bit security due to concerns over the +size of the public keys, the time it would take to verify signatures, and being generally deemed "overkill". + +We recognize that the size of ML-DSA (CRYSTALS-Dilithium) and SLH-DSA (SPHINCS+) signatures + public key pairs is a significant concern. +By way of comparison with Schnorr public key + signature pairs, SLH-DSA is roughly 80x larger and ML-DSA is roughly 40x larger. This means to +maintain present transaction throughput, an increase in the witness discount may be desired. + +An increase in the witness discount must not be taken lightly. Parties may take advantage of this discount for purposes other than +authorizing transactions (e.g., storage of arbitrary data as seen with "inscriptions"). An increase in the witness discount would +not only impact node runners but those with inscriptions would have the scarcity of their non-monetary assets affected. + +There was some hope of designing P2QRH such that discounted public keys and signatures could not be repurposed for the storage of +arbitrary data by requiring that they successfully be verified before being written to Bitcoin's blockchain, a.k.a. "JPEG resistance". +Later research Bas Westerbaan (2025), [https://groups.google.com/g/bitcoindev/c/5Ff0jdQPofo jpeg resistance of various post-quantum signature schemes] +provided strong evidence that this was not a feasible approach for the NIST approved Post-Quantum signature algorithms. +It is an open question if Post-Quantum signature algorithms can be designed to provide JPEG resistance. + +==== Raising tapscript's stack element size ==== + +A problem faced by any attempt to add PQ signatures to tapscript is that the stack elements in tapscript cannot be larger than 520 bytes +because the MAX_SCRIPT_ELEMENT_SIZE=520. This is problematic because PQ signature algorithms often have signatures and +public keys in excess of 520 bytes. For instance: -For each input, a separate attestation field is used. To know how many attestation fields are present, implementations -must count the number of inputs present in the transaction. +* ML-DSA public keys are 1,312 bytes and signatures are 2,420 bytes +* SLH-DSA public keys are 32 bytes and signatures are 7,856 bytes -==== Attestation Parsing Example ==== +We will first look at our approach to the problem of PQ signatures and then give our solution for public keys larger than 520 bytes. -Signing for a single input using both secp256k1 Schnorr and FALCON-512: +To keep P2QRH small and simple, we have opted not to raise the stack element size limit as part of P2QRH, but instead make this change when +adding of PQ signatures. That said, we are not strongly opposed to putting this increase in P2QRH. -Number of public keys: +We propose a stack element size limit of 8,000 bytes. We arrive at 8,000 by rounding up from the needed 7,856 bytes. - [key_type_bitmask]: 0x03 - [threshold]: 0x01 - [num_pubkeys]: 0x02 +OP_DUP will duplicate any stack element. Thus, if we allowed OP_DUP to duplicate stack elements of size 8,000 bytes, it would be possible +to write a tapscript which will duplicate stack elements until it reaches the maximum number of elements on stack, i.e. 1000 elements. +An increase from 520 bytes to 8,000 bytes would increase the memory footprint from 520 KB to 8 MB. -Pubkey 1: - [key_type]: 0x01 - [pubkey_length]: 0x20 (32 bytes) - [pubkey]: public_key_secp256k1 +To prevent OP_DUP from creating an 8 MB stack by duplicating stack elements larger than 520 bytes we define OP_DUP to fail on stack +elements larger than 520 bytes. Note this change to OP_DUP is not consensus critical and does not require any sort of fork. This is +because currently there is no way to get a stack element larger than 520 bytes onto the stack so triggering this rule is currently +impossible and would only matter if the stack element size limit was raised. -Pubkey 2: - [key_type]: 0x02 - [pubkey_length]: 0x0701 (1793 bytes) - [pubkey]: public_key_falcon_512 +==== Public keys larger than 520 bytes ==== -Number of signatures: +Turning our attention to public keys larger than 520 bytes. This is not needed for SLH-DSA as its public key is only 32 bytes. +This is a different problem than signatures as public keys are typically pushed onto +the stack by the tapleaf script (redeem script) to commit to public keys in output. The OP_PUSHDATA opcode in tapscript fails if asked to push +more than 520 bytes onto the stack. - [num_signatures]: 0x02 +To solve this issue, for signature schemes with public keys greater than 520 bytes, we use the hash of the public key in the tapleaf script. +We then package the public key and signature together as the same stack element on the input stack. Since the hash of the public key is +only 32 bytes, the tapleaf script can push it on the stack as it does today. Consider the following example with a +OP_CHECKMLSIG opcode for ML-DSA: -Signature 1: - [signature_length]: 0x40 (64 bytes) - [signature]: signature_secp256k1 + +stack = [pubkey||signature] +tapscript = [OP_PUSHDATA HASH256(expected_pubkey), OP_CHECKMLSIG] + -Signature 2: - [signature_length]: 0x0500 (1280 bytes) - [signature]: signature_falcon_512 +1. OP_PUSHDATA HASH256(expected_pubkey) updates the stack to [HASH256(expected_pubkey), pubkey||signature] +2. OP_CHECKMLSIG pops HASH256(expected_pubkey) and pubkey||signature, checks HASH256(expected_pubkey) == pubkey and verifies signature against pubkey. -Note: This contrasts with multisig inputs, where the attestation structure repeats for each public key and signature. +==== Future considerations ==== -=== Signature Algorithms === +Additional follow-on BIPs will be needed to implement PQ signature algorithms, signature aggregation, and full BIP-32 compatibility +(if possible) BIP-32 relies on elliptic curve operations to derive keys from xpubs to support +watch-only wallets, which PQC schemes may not support.. However, until specialized quantum cryptography hardware +is widespread and signature aggregation schemes are thoroughly vetted, P2QRH addresses are an intermediate solution +to quantum threats. -The specific quantum-resistant signature algorithm used cannot be inferred from the length of the public key due to -collisions in length between algorithms. Instead, when each key is revealed in the attestation, the key type bitmask -indicates which algorithm was used. +== Specification == -Supported PQC algorithms and their NIST Level I parameters: +We define the Pay to Quantum Resistant Hash (P2QRH) output structure as follows. -* '''secp256k1 - BIP-340 - Schnorr + X-Only''' -** Key Type 0 -** Public Key Length: 32 bytes -** Signature Length: 64 bytes -** Total Size: 96 bytes -** Cycles to sign: 42,000 (EdDSA) -** Cycles to verify: 130,000 (EdDSA) -* '''FN-DSA-512 - FIPS 206 - FALCON-512:''' -** Key Type 1 -** Public Key Length: 897 bytes -** Signature Length: 667 bytes -** Total Size: 1,564 bytes -** Cycles to sign: 1,009,764 -** Cycles to verify: 81,036 -* '''ML-DSA-44 - FIPS 204 - CRYSTALS-Dilithium Level I:''' -** Key Type 2 -** Public Key Length: 1,312 bytes -** Signature Length: 2,420 bytes -** Total Size: 3,732 bytes -** Cycles to sign: 333,013 -** Cycles to verify: 118,412 -* '''SLH-DSA-SHAKE-128s - FIPS 205 - SPHINCS+-128s:''' -** Key Type 3 -** Public Key Length: 32 bytes -** Signature Length: 7,856 bytes -** Total Size: 7,888 bytes -** Cycles to sign: 4,682,570,992 -** Cycles to verify: 4,764,084 +=== Pay to Quantum Resistant Hash (P2QRH) === -Implementations must recognize the supported algorithms and validate accordingly. +A P2QRH output is simply the root of the tapleaf Merkle tree defined in [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341] +and used as an internal value in P2TR. -A bitmask is used to indicate the algorithm used for each public key and signature pair. The bitmask enumerates based on -the key type as indicated above. This is used in the cryptographic commitment in the hash computation and -revealed in the attestation for each public key when spent. +To construct a P2QRH output we follow the same process as [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341] +to compute the tapscript merkle root. However, instead of the root of the Merkle tree being hashed together with the internal +key in P2QRH the root is hashed by itself using the tag "QuantumRoot" and then set as the witness program. -=== Script Validation === +=== Address Format === -To spend a P2QRH output, the following conditions must be met: +P2QRH uses SegWit version 3 outputs, resulting in addresses that start with bc1r, following +[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. Bech32 encoding maps version 3 to the +prefix r. -1. The scriptPubKey must be of the form: +Example P2QRH address: -OP_PUSHNUM_3 <32-byte hash> +bc1r... (32-byte Bech32m-encoded tapleaf merkle root) -2. The attestation must include: +=== ScriptPubKey === -* The quantum-resistant public key(s) whose HASH256 concatenated and hashed again matches the in -the scriptPubKey. +The scriptPubKey for a P2QRH output is: -* Valid signatures corresponding to the public key(s) and the transaction data. + OP_PUSHNUM_3 OP_PUSHBYTES_32 -* The key type bitmask and threshold must match the commitment in the scriptPubKey. +Where: -3. For multi-signature schemes, all required public keys and signatures must be provided for that input within the -attestation. Public keys that are not needed or available can be selectively disclosed by including their hash in the -attestation accompanied with an empty signature by providing a 0x00 signature length byte. This works so long as -enough keys to meet the threshold are provided. +* OP_PUSHNUM_3 (0x53) indicates SegWit version 3. +* is the 32-byte tapleaf merkle root. + +==== Script Validation ==== + +A P2QRH output is a native SegWit output (see [[bip-0141.mediawiki|BIP141]]) with version number 3, and a 32-byte witness program. +Unlike taproot this witness program is the tapleaf merkle root. For the sake of comparison we have, as much as possible, copied the +language verbatim from the [[bip-0341.mediawiki|BIP341]] script validation section. + +* Let ''q'' be the 32-byte array containing the witness program (the second push in the scriptPubKey) which represents root of tapleaf merkle tree. +* Fail if the witness stack does not have two or more elements. +* If there are at least three witness elements, and the first byte of the last element is 0x50, this last element is called ''annex'' ''a'' and is removed from the witness stack. The annex (or the lack of thereof) is always covered by the signature and contributes to transaction weight, but is otherwise ignored during taproot validation. +* There must be at least two witness elements left. +** Call the second-to-last stack element ''s'', the script (as defined in [[bip-0341.mediawiki|BIP341]]) +** The last stack element is called the control block ''c'', and must have length ''1 + 32 * m'', for a value of ''m'' that is an integer between 0 and 128, inclusive. Fail if it does not have such a length. +** Let ''v = c[0] & 0xfe'' be the ''leaf version'' (as defined in [[bip-0341.mediawiki|BIP-341]]). To maintain ''leaf version'' encoding compatibility the last bit of c[0] is unused and must be 1 '''Why set the last bit of c[0] to one?''' Consider a faulty implementation that deserializes the ''leaf version'' as c[0] rather than c[0] & 0xfe for both P2TR and P2QRH. If they test against P2QRH outputs and require that last bit is 1, this deserialization bug will cause an immediate error.. +** Let ''k0 = hashTapLeaf(v || compact_size(size of s) || s)''; also call it the ''tapleaf hash''. +** For ''j'' in ''[0,1,...,m-1]'': +*** Let ''ej = c[33+32j:65+32j]''. +*** Let ''kj+1 depend on whether ''kj < ej'' (lexicographically): +**** If ''kj < ej'': ''kj+1 = hashTapBranch(kj || ej)''. +**** If ''kj ≥ ej'': ''kj+1 = hashTapBranch(ej || kj)''. +** Let ''r = hashQuantumRoot(km)''. +** If ''q ≠ r'', fail. +** Execute the script, according to the applicable script rules, using the witness stack elements excluding the script ''s'', the control block ''c'', and the annex ''a'' if present, as initial stack. This implies that for the future leaf versions (non-''0xC0'') the execution must succeed. + +The steps above follow the script path spending logic from [[bip-0341.mediawiki|BIP-341]] with the following changes: +- The witness program is the tapleaf merkle root and not a public key. This means that we skip directly to BIP-341 spend path tapleaf merkle tree validation. +- We compute the tagged tapleaf merkle root r and compare it directly to the witness program q. +- The control block is 1 + 32*m bytes, instead of 33 + 32*m bytes. ==== Sighash Calculation ==== @@ -567,60 +490,91 @@ procedure specified in BIP-341 to maintain compatibility with Taproot signatures If a sighash flag other than DEFAULT is needed, it can be placed in the transaction witness. In this case, it will be the only field in the witness. -==== Signature Verification ==== - -Signature verification is as follows: - -1. Extract the from the scriptPubKey. - -2. For each input: +=== Compatibility with BIP-141 === -* Compute hashed_pubkeys as specified in the Hash Computation section. +By adhering to the SegWit transaction structure and versioning, P2QRH outputs are compatible with existing transaction +processing rules. Nodes that do not recognize SegWit version 3 will treat these outputs as anyone-can-spend but, per +[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP-141], will not relay or mine such transactions. -* Compare the resulting hash to . If they do not match, the script fails. -3. Verify each signature against the corresponding public key and the sighash. +=== Transaction Size and Fees === -4. Ensure that the signature algorithm used matches the expected lengths for NIST Level I security, and is supported by -the implementation. +Equivalent P2QRH and P2TR outputs are always the same size. P2QRH inputs can be slightly larger or smaller than +their equivalent P2TR inputs. Let's consider the cases: -=== Compatibility with BIP-141 === +'''P2TR key-spend''' P2QRH inputs will be larger than P2TR inputs when the P2TR output would have been spent via the key-spend path. +P2QRH quantum resistance comes from removing the P2TR key-spend path. Consequently it cannot make use of taproot's optimization +where P2TR key-spends do not require including a merkle path in the P2TR input. If the Merkle tree only has a single tapleaf, +no Merkle path is needed in the control block giving us a 1 byte control block. -By adhering to the SegWit transaction structure and versioning, P2QRH outputs are compatible with existing transaction -processing rules. Nodes that do not recognize SegWit version 3 will treat these outputs as anyone-can-spend but, per -[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP-141], will not relay or mine such transactions. +P2QRH witness (103 bytes): + +[count] (1 byte), # Number of elements in the witness +[size] signature (1 + 64 bytes = 65 bytes), +tapleaf script = [size] [OP_PUSHBYTES_32, 32 byte public key, OP_CHECKSIG] (1 + 1 + 32 + 1 bytes = 35 bytes), +control block = [size] [control byte] (1 + 1 = 2 bytes) + -=== Usage Considerations === +P2TR key-spend witness (66 bytes): + +[count] (1 byte), # Number of elements in the witness +[size] signature (1 + 64 bytes = 65 bytes) + -==== Transaction Size and Fees ==== +Thus, the P2QRH input would be 103 - 66 = 37 bytes larger than a P2TR key-spend input. -Quantum-resistant signatures are significantly larger than traditional signatures, increasing transaction size and the -fees required. Users and wallet developers should be aware of this and plan accordingly. +If the Merkle tree has more than a single tapleaf, then the Merkle path must be included in +the control block. +P2QRH witness (103+32*m bytes) + +[count] (1 byte), # Number of elements in the witness +[size] signature (64 + 1 bytes = 65 bytes), +tapleaf script = [size] [OP_PUSHBYTES_32, 32 byte public key, OP_CHECKSIG] (34 + 1 bytes = 35 bytes), +control block = [size] [control byte, 32 * m byte Merkle path] (1 + 1 + 32 * m = 2 + 32 * m bytes) + -For example, for CRYSTALS-Dilithium Level I, a single public key is 1,312 bytes, and a signature is 2,420 bytes, resulting in a substantial increase over current -ECDSA or Schnorr signatures. +For a Merkle path of length m, it would add an additional ~32 * m bytes to the P2QRH input. This would +make it 37 + 32 * m bytes larger than a P2TR key-spend inputIf m >= 8, then the compact size will use 3 bytes rather than 1 byte. -==== Performance Impact ==== +Considering a P2QRH output that has a PQ signature tapleaf and a Schnorr tapleaf. The P2QRH witness to spend the Schnorr path +would be 103 + 32 * 1 = 135 bytes. It is unfortunate that we can not use the key-spend optimization for P2QRH inputs, but the key-spend optimization is +exactly what makes P2TR vulnerable to quantum attacks. If spend-key was quantum resistant we wouldn't need P2QRH at all. -Verification of quantum-resistant signatures will be computationally more intensive, and any attestation discount will -also increase storage requirements. Node operators should consider the potential impact on resource usage in the long -term. Developers may need to optimize signature verification implementations, especially by implementing caching for -key generation. +'''P2TR script-spend''' P2QRH inputs will be smaller than equivalent script-spend path P2TR inputs. This is because P2QRH inputs +do not require that the input includes a public key in the witness control block to open the commitment to the tapleaf merkle root. +An equivalent P2QRH input will be 32 bytes smaller than a P2TR script-spend input. -==== Algorithm Selection ==== +=== Performance Impact === -Introducing three quantum-resistant algorithms to the Bitcoin ecosystem provides users with the option to select an -appropriate algorithm for their use case, generally based on the amount of value they wish to secure. Developers can -choose to implement support for multiple algorithms in wallets and on nodes to offer quantum-resistant options. +P2QRH is slightly more computationally performant than P2TR, as the operations to spending a P2QRH output is a strict +subset of the operations needed to spend a P2TR output. -==== Backward Compatibility ==== +=== Backward Compatibility === Older wallets and nodes that have not been made compatible with SegWit version 3 and P2QRH will not recognize these outputs. Users should ensure they are using updated wallets and nodes to use P2QRH addresses and validate transactions using P2QRH outputs. +P2QRH is fully compatible with tapscript and existing tapscript programs can be used in P2QRH outputs without modification. + == Security == +P2QRH outputs provide the same tapscript functionality as P2TR outputs, but without the quantum-vulnerable key-spend +path. This enables users, exchanges and other hodlers to easily move their coins from taproot outputs to P2QRH outputs +and thereby protect their coins from long-exposure quantum attacks. The protection from long-exposure quantum attacks +does not depend on the activation of post-quantum signatures in Bitcoin but does require that users do not expose their +quantum vulnerable public keys to attackers via address reuse or other unsafe practices. + +P2QRH uses a 256-bit hash output, providing 128 bits of collision resistance and 256 bits of preimage resistance. +This is the same level of security as P2WSH, which also uses a 256-bit hash output. + +P2QRH does not, by itself, protect against short-exposure quantum attacks, but such attacks can be mitigated by the future +activation of post-quantum signatures in Bitcoin. With P2QRH hash, these would provide full quantum resistance to P2QRH outputs in Bitcoin. +That said, the protection offered by resistance to long-exposure quantum attacks should not be underestimated. It is likely +that the first CRQCs (Cryptographically Relevant Quantum Computers) will not be able to perform short-exposure quantum +attacks. + + {| class="wikitable" |+ Candidate quantum-resistant signature algorithms ordered by largest to smallest NIST Level V signature size |- @@ -699,6 +653,41 @@ proposed solution] in an Ethereum quantum emergency is quite different from the a hard fork of the chain, reverting all blocks after a sufficient amount of theft, and using STARKs based on BIP-32 seeds to act as the authoritative secret when signing. These measures are deemed far too heavy-handed for Bitcoin. +P2QRH and MAST (Merkelized Abstract Syntax Tree) [https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki BIP-114], +and related BIPs [https://github.com/bitcoin/bips/blob/master/bip-0116.mediawiki BIP-116], [https://github.com/bitcoin/bips/blob/master/bip-0117.mediawiki BIP-117], +share the idea of committing to a Merkle tree of scripts. While MAST was never activated, taproot +[https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341] incorporated this idea of a Merkle tree of +scripts into its design. P2QRH inherits this capability from taproot because P2QRH is simply taproot with the key-spend +path removed. As a result, P2QRH does have the taproot internal key or tweak key, instead P2QRH commits directly to the +Merkle tree of scripts. + +Below we attempt to summarize some of the ideas discussed on the Bitcoin Bitcoin-Dev that relate to P2QRH. + +The idea of a taproot but with the key-spend path removed has been discussed a number of times in the Bitcoin community. +[https://gnusha.org/pi/bitcoindev/CAD5xwhgzR8e5r1e4H-5EH2mSsE1V39dd06+TgYniFnXFSBqLxw@mail.gmail.com/ OP_CAT Makes Bitcoin Quantum Secure] +notes that if we disable the key-spend in taproot and activated CAT [https://github.com/bitcoin/bips/blob/master/bip-0347.mediawik BIP-347], +we could achieve quantum resistance by using Lamport signatures with CAT. Lamport and WOTS (Winternitz One-Time Signatures) built from CAT +are quantum resistant but are one-time signatures. This means that if you sign twice for the same public key, you leak your secret key. +This would require major changes to wallet behavior and would represent a significant security downgrade. +[https://groups.google.com/g/bitcoindev/c/8O857bRSVV8/m/rTrpeFjWDAAJ Trivial QC signatures with clean upgrade path] and +[https://groups.google.com/g/bitcoindev/c/oQKezDOc4us/m/T1vSMkZNAAAJ Re: P2QRH / BIP-360 Update] discusses the idea of +taproot but with the future ability to disable the key-spend path. +The design of P2QRH is partly inspired by these discussions as P2QRH can be understood as P2TR without the key-spend path. + +Commit-reveal schemes such as +[https://gnusha.org/pi/bitcoindev/1518710367.3550.111.camel@mmci.uni-saarland.de/ Re: Transition to post-quantum (2018)] +and [https://groups.google.com/g/bitcoindev/c/LpWOcXMcvk8/m/YEiH-kTHAwAJ Post-Quantum commit / reveal Fawkescoin variant as a soft fork (2025)] +have been proposed as a way to safely spend bitcoins if CRQCs become practical prior to Bitcoin adopting achieving quantum resistance. +The essential idea is to leverage the fact that a CRQC can only learn your private key after a user has revealed their public key. +Thus, Bitcoin could fork in an alternative way to spend an output that would leverage this property. +Spending via commit-reveal would require two steps, first the user's commits on-chain to their public key along with a set of outputs the user wishes +to spend to. Then, in reveal, the user sign and reveals their public key. While CRQC might be able to generate competing signatures it can not produce +a commitment to the user's public key earlier than the user's commitment as it does not learn it until the reveal step. + +Commit-reveal schemes can only be spent from and to outputs that are not vulnerable to long-exposure quantum attacks, such as +P2PKH, P2SK, P2WPKH, etc... To use tapscript outputs with this system either a soft fork could disable the key-spend path of P2TR outputs +or P2QRH could be used here as it does not have a key-spend path and thus is not vulnerable to long-exposure quantum attacks. + == References == * [https://groups.google.com/g/bitcoindev/c/Aee8xKuIC2s/m/cu6xej1mBQAJ Mailing list discussion] @@ -735,4 +724,4 @@ the design of the P2TR (Taproot) output type using Schnorr signatures. Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name "QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as well to those who took the time to review and contribute, including Jeff Bride, Adam Borcany, Antoine Riard, Pierre-Luc -Dallaire-Demers, Ethan Heilman, Jon Atack, Jameson Lopp, Murchandamus, and Vojtěch Strnad. +Dallaire-Demers, Mark Erhardt, Joey Yandle, Jon Atack, Jameson Lopp, Murchandamus, and Vojtěch Strnad. diff --git a/bip-0360/merkletree.png b/bip-0360/merkletree.png new file mode 100644 index 0000000000000000000000000000000000000000..62c73f3139243ce88ef0a0e88f28f5c53d483472 GIT binary patch literal 75700 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%0D4?unJ!OJy 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 M7q6u9CEoh}A6o_^^#A|> literal 0 HcmV?d00001 diff --git a/bip-0360/merkletree.svg b/bip-0360/merkletree.svg new file mode 100644 index 0000000000..a3dcb37937 --- /dev/null +++ b/bip-0360/merkletree.svg @@ -0,0 +1,1874 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + P2QRH Witness (input) + + + + + + + + + + + + annex + 50 + + + + Control byte + Script + tapleaf B + Initial stack + + + + + Merkle path (32*m bytes) + Control block + Witness Program + SegWit version 3 + tapleaf version + + tapleaf version + 1 + { + { + P2QRH scriptPubkey (output) + How the tapleaf Merkle Root is computed: + + + OP_PUSHNUM3 + tapleaf Merkle root + + tapleaf Merkle root + + tagged_hashQuantumRoot + + tagged_hash Tapleaf + + tagged_hash TapBranch + + tagged_hash TapBranch + + tagged_hash TapBranch + + tagged_hash TapBranch + + + + + + tapleaf + A + + tapleaf version + + + + + tapleaf + B + + tapleaf version + + + + + tapleaf + C + + tapleaf version + + + + + tapleaf + D + + tapleaf version + + + + + tapleaf + E + + + + + + + + + + + + + tagged_hash Tapleaf + + + tagged_hash Tapleaf + + + tagged_hash Tapleaf + + + + + tagged_hash Tapleaf + + + + + From 77dbeee502b606fda2006ae53f4014cef612aacd Mon Sep 17 00:00:00 2001 From: Hunter Beast Date: Mon, 7 Jul 2025 09:28:32 -0600 Subject: [PATCH 063/131] Update changelog and acknowledgements with the new developments in BIP-360. (#24) --- bip-0360.mediawiki | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki index 66a28a08f4..58a3bb971e 100644 --- a/bip-0360.mediawiki +++ b/bip-0360.mediawiki @@ -703,6 +703,7 @@ or P2QRH could be used here as it does not have a key-spend path and thus is not To help implementors understand updates to this BIP, we keep a list of substantial changes. +* 2025-07-07 - P2QRH is now a P2TR with the vulnerable key-spend path disabled. Number of PQ signature algorithms supported reduced from three to two. PQ signature algorithm support is now added via opcodes or tapleaf version. * 2025-03-18 - Correct inconsistencies in commitment and attestation structure. Switch from merkle tree commitment to sorted vector hash commitment. Update descriptor format. * 2025-03-12 - Add verification times for each algorithm. 256 -> 128 (NIST V -> NIST I). Add key type bitmask. Clarify multisig semantics. * 2025-02-23 - More points of clarification from review. Update dead link. @@ -722,6 +723,8 @@ This document is inspired by [https://github.com/bitcoin/bips/blob/master/bip-03 the design of the P2TR (Taproot) output type using Schnorr signatures. Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name -"QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as +"QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. The +attestation was later discarded when Ethan Heilman joined as co-author, whom I'm incredibly grateful to for +transforming this BIP into something far more congruent with existing Bitcoin design. Thank you as well to those who took the time to review and contribute, including Jeff Bride, Adam Borcany, Antoine Riard, Pierre-Luc -Dallaire-Demers, Mark Erhardt, Joey Yandle, Jon Atack, Jameson Lopp, Murchandamus, and Vojtěch Strnad. +Dallaire-Demers, Mark Erhardt, Joey Yandle, Jon Atack, Armin Sabouri, Jameson Lopp, Murchandamus, and Vojtěch Strnad. From 99dc227e03337c1fd4e9597305b2b52ba3750ed1 Mon Sep 17 00:00:00 2001 From: jbride Date: Mon, 7 Jul 2025 09:30:22 -0600 Subject: [PATCH 064/131] p2qrh: removing experimental tests pertaining to descriptors --- .../rust/tests/data/p2qrh_descriptors.json | 231 ------------------ .../ref-impl/rust/tests/data/p2qrh_spend.json | 20 -- .../ref-impl/rust/tests/p2qrh_descriptor.rs | 35 --- 3 files changed, 286 deletions(-) delete mode 100644 bip-0360/ref-impl/rust/tests/data/p2qrh_descriptors.json delete mode 100644 bip-0360/ref-impl/rust/tests/data/p2qrh_spend.json delete mode 100644 bip-0360/ref-impl/rust/tests/p2qrh_descriptor.rs diff --git a/bip-0360/ref-impl/rust/tests/data/p2qrh_descriptors.json b/bip-0360/ref-impl/rust/tests/data/p2qrh_descriptors.json deleted file mode 100644 index 327fdffa4c..0000000000 --- a/bip-0360/ref-impl/rust/tests/data/p2qrh_descriptors.json +++ /dev/null @@ -1,231 +0,0 @@ -{ - "version": 1, - "test_vectors": [ - { - "id": "p2qrh_single_key_commitment", - "objective": "Tests P2QRH with single SECP256K1-SCHNORR public key only. Expect error", - "description": "At a minimum, there should be two different key types in a P2QRH output: one key that makes use of classical cryptography, and one that makes use of a PQC algorithm chosen within the wallet", - "given": { - "threshold": 2, - "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074" - }, - "intermediary": { - }, - "expected": { - "error": "P2QRH addresses expect at least one PQC public key of type ML-DSA-44 and/or SLH_DSA_128S" - } - }, - { - "id": "p2qrh_mixed_single_key_commitment", - "objective": "Tests P2QRH with single mix of SECP256K1-SCHNORR and ML-DSA-44 public keys", - "given": { - "threshold": 2, - "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074", - "publicKey": "6fe991c97f0094b2fb636ab4951878f239e2871c3cfdc2936230dac5dde8441d3ff41704025260c25b7e44416142778452694110793465d38ff66244a87aaacaf38103adde0dcf2f6056d48fcc43da9483ce6cfdd96ba2159b2f9653d24fe1f280c924db81830abe6d1070e5b32d2cf373c67dade4bd7c02bb6f5e76ff934316a774cc965fd9e921efbb81053260a07b84dd696d3eb012f9989cab684ce3c104bf926c7fd51a305a79ac2e825d6b5ea51618412b9076ca8f836342fb2412bcd525a9b435de5b0e1643dc2c49aa16a0ae710694657325bc86221ad6f9b5bb6195dee7d7f282c3046ae79f49c3d6339fe52b547ab06af76c12ae1812fa4d87f27700885e35ed91fac93388a4a5c0e37a65eb39f516122e264d716cc120500dc883eee64b22d944bc8061361629e27fc9105b28ff0723330793d6aa62dd6736d7cb157fe7e7545ed6be95d25d795eb24bff5e5b0445b18aa1081bbf99dc9eefb5e04984ca2d340278e2033e40d47824ff5e7c32343c3ffd7b209a49f88046fc52f3e145725aa5aff7cfa785a70accaaec63602f1e92f9a40c9aab89866b8ceab649dc58c4ae338297f8a9a419b70fe23229fd9bf264f403b5fee4e51651a7c5f21d82a3b5871436e85d84a2a036b117502d92e91cbef77ba75891eafcd8054dccd2b6c7201d1abc0dc2a5709a4897bafd88e673184c783ba5eed4f687df619280b532fd9e1b3c87028bc13bff6a71249825391e9b1790a5678ed021cd2820da1245dfda436d32394cbea6b5803b49e7234a538ddfbbd1a70051ee7357906660f71aac0728348230b66158ce6d6e061f2003cb3523fe5878b858c6c1aa94a4380a6cbe3012ec21a78a5fc94ab6697d64277fb5a3de6d7a9950aef094531303832dc77a334fabfcc4f9140fd8d420acf1f66e5a44e21c468dca0dee61913536d0bdf296618b73e43ecdc8a77b24644f0dfba4d009b552557d81a3203f9d434801925296763a2901360469547b3bc921217d1dbeb2f76e0dfaef9f91fc4a15baa57aca815b92d67615dee4c75b35df324246854f72a15109311ec2b5358446f48c1f925299bf701819c86be5aeafde4f616cd6c5db2762634a3387cb4b7eb317c569a50824fdce1bb858852550207144fc7ef6f3957c3417bcc6a7fb317441f87da106303a7da85b05dfacdcbc36910311669bb4f580d5282502c6797517521def3fd5d8bc04e5b55ba840a4cf193b8cc3e275bbd96632912ac5c4d26816c411ff4820401eceaffe1e32cfc6963565854b44a96585397cbb3aa3cd42ce8466748a8e769593fdd57a6f85dbdcf2705434302da89bd825196ae3ab3a2b3bd54864c41f0ba9dfccf0c2b508ef5e95b30e2706fc709f1261ca47fa236906c6d75e44ad388b8dc587ae98cd7442e279542e9bd776f20eefd24e701dab038a409f1ca25e7a8003519f3a7daf98e8ac2e9c11287a8bb4fa4219216387023418e9525c61e96440b48404fb8fbba19c469fe9e0291c2e4b61425cd69cfdd17826ce1652385316b461e6433a61185d13c548a16942403c75fceedb7823824b69986e6ce364784de01624429a149f9adb40c3274aa3ab2c13ac8769cc8f0a9e385c72410f08743a55f77066405af9fc9d036042788fc806eb1575c81cc3fbcc9f6a493ca54ee25eb202395f299bbc36f9e111edccc2e0020123b63b9ae53440bcdab7f7902f4acbee8b41f9b46551dc2185cfe3bffe4d2cd2e8abafbe01aed638cf9f1768466a74b055edb98002bc812fb6fb7d82abe53e4c94bc5e63d5836a931cec902044770a9406e4539145d5c8a5c699df243520c9c710de92582f180297ea0422e4196bf205" - }, - "intermediary": { - "concatenated": "xxxx", - "commitment": "yyyy" - }, - "expected": { - "hash": "zzzz", - "address": "bc1r8rt68aze8tek87cnz4ndnvfzk6tk93jv39n4lmpu5a4yw453rcpszsft3z" - } - }, - { - "id": "p2qrh_mixed_multiple_key_commitment", - "objective": "Tests P2QRH with multiple mix of SECP256K1_SCHNORR, ML_DSA_44 and SLH_DSA_128S public keys", - "given": { - "threshold": 3, - "publicKey": "9d46fdd36eac78059fa4d146a654c1221ae878f54690a9646a600674222f33ca", - "publicKey": "0b16be67d10c2d49adaadc17c2f566c67e95adfd529047bc6b65c3a5f47f738789e2d2768bc5bec3fcaba3efc717063a48957a0f562a49683ec2852696eda7f7b72c84665b7459409f58bad095dfc122912fce3d62306c7787b3a587745be34b579eeaabb574ce66b7139bff491c6e4c5eb65cccea321da3412a10eaca3528d4fac4a2147abb2104d830e29b32a8e6052fd3b9ac338fe51b9a6e0f893a8acdf93d55deebb7f4226d6cd4e02b0723081701121740d3ae7d11cbab82f23b14ddfd9032a434ad972c047aa3b577590605b7dc8b2c75fcbd490d504f2edffaae249a78fd554932d3bf3008b609171420216bd9d8c4607a60c953bc4512cf0c5cca73aa51de9185519768846f6c1f1b19a96748d44b80a8b8acd551a1902c967ab138f64ec6c9f662d5903aa0324d9b50fb52e262ae6676ed602ca622b705a2878e29db4e4134e81fa4cacbcf9ac8825a2d24e573acb6ad2b6323741630ae247c626bd82f1e460457f883c84f7708180ce66f4ea65ff90b7d604806d4fb5a3a27d6890d32f6266ffa6d06399e740c95d30b03777b9a90ec9e7e9aeb7492bd6a2c8574617a3bc55df2679ee50707876d095809c75b2b0cd526d0c2d2c232686f4f712606b87a648438b731823dc4cd7dc7ac6eeca2a19506f738152a828d9d953cc5a729a70b1c68643c39081e543488261e73fc5ddac2c5ec8303985eab64916b174f9c9cac01316795465968e68a78cea4accd7ba8530472f856930fb97cbd8130827cee5a5537abfaaa1d9fd88e8eefdf5dea3a92a502c53962d08a2ccda3b00608f02fc26165538a0ed90876d780986b4b551ce7fb68783e301735add0810bb16904bbe8c217ee8ca40aafab17f3ba535acdb87508140bdf01d550719a7d29a26a4b494956c84e2025d73741e4f5c30a17f47428d6af8c1145a1d67b4c76bddbd546c42004ccf3533e6630d8531891ffe7800a27f249b0af7cee08c6599546ea4c73721eabbda08bff659ce69bc9ab8224aa59b0566413e6cb6ff1f98dd1cb37d45c2e297cee9cc0d1fd28ad26171b54c67848cec24faaa5698427d53fa297f8f4ba741c794064cd195fb2a1602cba52f5232dc066405d6b5687b4948b8d0884c9be46a3660858c7684488c463d2c155c06282b7ddd93eff0ab52aa93998485a0225040499de4e7a0381defa63a1e8539929a2a2d433c84818de17db1528926d00fae6a836b48d44caab624ac8891dd9356e41680f551d81b4dac2f1d52d540c2b36c49909ac3d87a24c7eae849496af33c7bfcae36546cfd46936ec1bf90b6cd394d2a8fd0c236af4fd00789e05f738247cf35562f967c3f9b939adf613ab79cbfa0e06b07a09a55cf2e677a08d6c727f802bf0855be7153713d5633071d4ebb00ddda676c1578cfaf74a715935d094cfa9f7b97d2b5d440801cec996f1fde42c64cafbe348fa619521dcfd5b8d2cb3ca2c9d6cd276d0af1e2fa8fc2e5531868b6daad393eed8c7197d40779ff7df88fea2a769653b5f616af3f4a1eecfd1c5bac89f6c56d46a733826d0ffec129fc3cb1187aebc087c53bfe9a973cb145915ca140cb30a020609401a018fcb1c1b882c6cf95fd06eb9c70ac6de5ec98666dc10534eba017d36ea45d28e73d50202fa06f7e9cc29afd0e15548a15a841afbe793027e653b6993471280cbb3c7f4174053881242f0759c8f40ca2d7fdbabd0d180e99b02c08bfcd7201ed589e3afafefebac6365a5436b113a47f75587e03413752fd103fa0d868f0c4ec13812e6e3e13c5356a371b838d94a9aa8c858aa827c5a6e11302d9b35aa7faa11e0ddac2a2e697442ee9963623dce52989de3ccc20e81", - "publicKey": "768a54113541212e258a8d24f912f61fcb3f40e6967570ba0ea35d8023e965d2" - }, - "intermediary": { - "concatenated": "xxxx", - "commitment": "yyyy" - }, - "expected": { - "hash": "zzzz" - } - }, - { - "id": "valid_p2qrh_address_generation", - "objective": "Verify the correct generation of a P2QRH address from a given public key using the specified quantum-resistant hash function", - "given": { - "threshold": 2, - "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074", - "publicKey": "xxx" - }, - "intermediary": { - }, - "expected": { - "error": "P2QRH addresses expect at least one PQC public key of type ML-DSA-44 and/or SLH_DSA_128S" - } - }, - { - "id": "invalid_public_key_handling", - "objective": "Ensure the system correctly identifies and rejects invalid or malformed public keys during address generation", - "given": { - "threshold": 2, - "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074", - "publicKey": "xxx" - }, - "intermediary": { - }, - "expected": { - "error": "P2QRH addresses expect at least one PQC public key of type ML-DSA-44 and/or SLH_DSA_128S" - } - }, - { - "id": "quantum_resistant_sig_verification", - "objective": "Test the verification process of a transaction signed with a quantum-resistant signature algorithm", - "given": { - "threshold": 2, - "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074", - "publicKey": "6fe991c97f0094b2fb636ab4951878f239e2871c3cfdc2936230dac5dde8441d3ff41704025260c25b7e44416142778452694110793465d38ff66244a87aaacaf38103adde0dcf2f6056d48fcc43da9483ce6cfdd96ba2159b2f9653d24fe1f280c924db81830abe6d1070e5b32d2cf373c67dade4bd7c02bb6f5e76ff934316" - }, - "intermediary": { - "concatenated": "xxxx", - "commitment": "yyyy" - }, - "expected": { - "hash": "zzzz" - } - }, - { - "id": "p2qrh_unsupported_signature_algorithm_rejection", - "objective": "Ensure that signatures using unsupported algorithms are correctly rejected", - "given": { - "threshold": 2, - "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074", - "publicKey": "invalid_quantum_key_type_12345" - }, - "intermediary": { - }, - "expected": { - "error": "Unsupported quantum-resistant signature algorithm" - } - }, - { - "id": "p2qrh_scriptpubkey_construction", - "objective": "Validate the correct construction of the scriptPubKey for P2QRH addresses", - "given": { - "threshold": 2, - "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074", - "publicKey": "6fe991c97f0094b2fb636ab4951878f239e2871c3cfdc2936230dac5dde8441d3ff41704025260c25b7e44416142778452694110793465d38ff66244a87aaacaf38103adde0dcf2f6056d48fcc43da9483ce6cfdd96ba2159b2f9653d24fe1f280c924db81830abe6d1070e5b32d2cf373c67dade4bd7c02bb6f5e76ff934316" - }, - "intermediary": { - "concatenated": "xxxx", - "commitment": "yyyy", - "scriptPubKey": "OP_2 OP_EQUAL" - }, - "expected": { - "valid": true, - "scriptPubKeyHex": "5220zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz87" - } - }, - { - "id": "p2qrh_scriptsig_validation", - "objective": "Ensure that the scriptSig correctly unlocks the P2QRH scriptPubKey", - "given": { - "threshold": 2, - "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074", - "publicKey": "6fe991c97f0094b2fb636ab4951878f239e2871c3cfdc2936230dac5dde8441d3ff41704025260c25b7e44416142778452694110793465d38ff66244a87aaacaf38103adde0dcf2f6056d48fcc43da9483ce6cfdd96ba2159b2f9653d24fe1f280c924db81830abe6d1070e5b32d2cf373c67dade4bd7c02bb6f5e76ff934316", - "message": "0000000000000000000000000000000000000000000000000000000000000000" - }, - "intermediary": { - "scriptSig": " ", - "scriptPubKey": "OP_2 OP_EQUAL" - }, - "expected": { - "valid": true, - "stack_result": true - } - }, - { - "id": "p2qrh_multisig_address_handling", - "objective": "Test the creation and validation of multisig P2QRH addresses", - "given": { - "threshold": 3, - "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074", - "publicKey": "6fe991c97f0094b2fb636ab4951878f239e2871c3cfdc2936230dac5dde8441d3ff41704025260c25b7e44416142778452694110793465d38ff66244a87aaacaf38103adde0dcf2f6056d48fcc43da9483ce6cfdd96ba2159b2f9653d24fe1f280c924db81830abe6d1070e5b32d2cf373c67dade4bd7c02bb6f5e76ff934316", - "publicKey": "768a54113541212e258a8d24f912f61fcb3f40e6967570ba0ea35d8023e965d2" - }, - "intermediary": { - "concatenated": "xxxx", - "commitment": "yyyy", - "scriptPubKey": "OP_3 OP_EQUAL" - }, - "expected": { - "valid": true, - "address": "qrh1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4" - } - }, - { - "id": "p2qrh_encoding_and_decoding_integrtiy", - "objective": "Verify that encoding and decoding processes for P2QRH addresses are lossless and accurate", - "given": { - "threshold": 2, - "publicKey": "41203a81d53c97f5276865c1d29f5bfe742ff05ad1d63dfa0719cb78a0660074", - "publicKey": "6fe991c97f0094b2fb636ab4951878f239e2871c3cfdc2936230dac5dde8441d3ff41704025260c25b7e44416142778452694110793465d38ff66244a87aaacaf38103adde0dcf2f6056d48fcc43da9483ce6cfdd96ba2159b2f9653d24fe1f280c924db81830abe6d1070e5b32d2cf373c67dade4bd7c02bb6f5e76ff934316", - "address": "qrh1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4" - }, - "intermediary": { - "decoded_data": "xxxx", - "reencoded_address": "qrh1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4" - }, - "expected": { - "valid": true, - "matches_original": true - } - }, - { - "id": "p2qrh_checksum_validation", - "objective": "confirm that the checksum mechanism detects errors in p2qrh addresses", - "given": { - "valid_address": "qrh1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", - "corrupted_addresses": [ - "qrh1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", - "qrh1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t3", - "qrh2qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4" - ] - }, - "intermediary": { - "checksum_calculations": ["xxxx", "yyyy", "zzzz"] - }, - "expected": { - "valid_address_check": true, - "corrupted_addresses_check": [false, false, false], - "error": "Invalid checksum" - } - }, - { - "id": "p2qrh_utxo_serialization_compatibility", - "objective": "ensure (de)serializer functionality supports p2qrh utxos", - "given": { - "utxo": { - "txid": "0000000000000000000000000000000000000000000000000000000000000000", - "vout": 0, - "amount": 100000000, - "height": 1000000, - "scriptPubKey": "5220zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz87" - } - }, - "intermediary": { - "serialized": "xxxx", - "deserialized": { - "txid": "0000000000000000000000000000000000000000000000000000000000000000", - "vout": 0, - "amount": 100000000, - "height": 1000000, - "scriptPubKey": "5220zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz87" - } - }, - "expected": { - "valid": true, - "matches_original": true - } - } - ] -} diff --git a/bip-0360/ref-impl/rust/tests/data/p2qrh_spend.json b/bip-0360/ref-impl/rust/tests/data/p2qrh_spend.json deleted file mode 100644 index d11f136d72..0000000000 --- a/bip-0360/ref-impl/rust/tests/data/p2qrh_spend.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "version": 1, - "test_vectors": [ - { - "id": "p2qrh_single_leaf_script_tree_no_sigs", - "objective": "Tests P2QRH with single trivial script leaf of: OP_EQUAL OP_3", - "given": { - "scriptInputs": [ - "03" - ], - "leafDescriptor" : "tr(INTERNAL_KEY, {pk():OP_EQUAL OP_1}, {pk():OP_EQUAL OP_2}, {pk():OP_EQUAL OP_3})", - "controlBlock": "c0" - }, - "intermediary": { }, - "expected": { - "witness": "038753c0" - } - } - ] -} \ No newline at end of file diff --git a/bip-0360/ref-impl/rust/tests/p2qrh_descriptor.rs b/bip-0360/ref-impl/rust/tests/p2qrh_descriptor.rs deleted file mode 100644 index 9832d9d150..0000000000 --- a/bip-0360/ref-impl/rust/tests/p2qrh_descriptor.rs +++ /dev/null @@ -1,35 +0,0 @@ -use miniscript::descriptor::{Descriptor, DescriptorPublicKey}; -use miniscript::Miniscript; -use bitcoin::secp256k1::{Secp256k1, PublicKey, XOnlyPublicKey}; -use bitcoin::address::Address; -use bitcoin::Network; -use log::{debug, info, error}; -use once_cell::sync::Lazy; -use anyhow::{anyhow, Result}; - -use p2qrh_ref::data_structures::{TestVector, TestVectors}; - -static TEST_VECTORS: Lazy = Lazy::new(|| { - let bip360_test_vectors = include_str!("../tests/data/p2qrh_descriptors.json"); - let test_vectors: TestVectors = serde_json::from_str(bip360_test_vectors).unwrap(); - assert_eq!(test_vectors.version, 1); - test_vectors -}); - -#[test] -fn test_descriptor_p2qrh() -> anyhow::Result<()> { - let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error - - let test_vectors = &*TEST_VECTORS; - - let secp = Secp256k1::new(); - - let xonly_pubkey = XOnlyPublicKey::from_slice(&hex::decode("03cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115").unwrap())?; - - // P2TR - let p2tr = Descriptor::new_tr(xonly_pubkey, None)?; - let p2tr_addr = Address::from_script(&p2tr.script_pubkey(), Network::Bitcoin)?; - println!("P2TR: {} (Address: {})", p2tr, p2tr_addr); - - Ok(()) -} From 2412aa3d29cabe2d62391d389af7d2473b8debc8 Mon Sep 17 00:00:00 2001 From: jbride Date: Mon, 7 Jul 2025 09:32:26 -0600 Subject: [PATCH 065/131] p2qrh: modified spend test to reflect p2qrh specification requirement that parity bit is always 1 --- bip-0360/ref-impl/rust/tests/p2qrh_spend.rs | 66 ++++----------------- 1 file changed, 10 insertions(+), 56 deletions(-) diff --git a/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs b/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs index c76e8ad7e1..653ea3dac9 100644 --- a/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs +++ b/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs @@ -18,14 +18,6 @@ use p2qrh_ref::{ serialize_script, }; -static TEST_VECTORS: Lazy = Lazy::new(|| { - let bip360_test_vectors = include_str!("../tests/data/p2qrh_spend.json"); - let test_vectors: TestVectors = serde_json::from_str(bip360_test_vectors).unwrap(); - assert_eq!(test_vectors.version, 1); - test_vectors -}); - -static P2QRH_SINGLE_LEAF_SCRIPT_TREE_NO_SIGS_TEST: &str = "p2qrh_single_leaf_script_tree_no_sigs"; /* 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. @@ -68,10 +60,15 @@ fn test_script_path_spend_signatures() { let input_tx_id_bytes = hex::decode("d1c40446c65456a9b11a9dddede31ee34b8d3df83788d98f690225d2958bfe3c").unwrap(); + // OP_PUSHBYTES_32 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0 OP_CHECKSIG let input_leaf_script_bytes: Vec = hex::decode("206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac").unwrap(); + + // Modified from learnmeabitcoin example + // Changed from c0 to c1 control byte to reflect p2qrh specification: The parity bit of the control byte is always 1 since P2QRH does not have a key-spend path. let input_control_block_bytes: Vec = - hex::decode("c0924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap(); + hex::decode("c1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap(); + let input_script_pubkey_bytes: Vec = hex::decode("5120f3778defe5173a9bf7169575116224f961c03c725c0e98b8da8f15df29194b80") .unwrap(); @@ -81,7 +78,10 @@ fn test_script_path_spend_signatures() { let test_sighash_bytes: Vec = hex::decode("752453d473e511a0da2097d664d69fe5eb89d8d9d00eab924b42fc0801a980c9").unwrap(); let test_p2wpkh_signature_bytes: Vec = hex::decode("01769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f01").unwrap(); - let test_witness_bytes: Vec = hex::decode("034101769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f0122206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac21c0924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap(); + + // Modified from learnmeabitcoin example + // Changed from c0 to c1 control byte to reflect p2qrh specification: The parity bit of the control byte is always 1 since P2QRH does not have a key-spend path. + let test_witness_bytes: Vec = hex::decode("034101769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f0122206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac21c1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap(); let mut txid_little_endian = input_tx_id_bytes.clone(); txid_little_endian.reverse(); @@ -176,49 +176,3 @@ fn test_script_path_spend_signatures() { let derived_witness_hex = hex::encode(derived_witness_vec); info!("derived_witness_hex: {:?}", derived_witness_hex); } - -#[test] -fn test_p2qrh_single_leaf_script_tree_no_sigs() { - let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error - - let test_vectors: &TestVectors = &*TEST_VECTORS; - let test_vector: &TestVector = test_vectors - .test_vector_map - .get(P2QRH_SINGLE_LEAF_SCRIPT_TREE_NO_SIGS_TEST) - .unwrap(); - - let mut witness: Witness = Witness::new(); - - test_vector - .given - .script_inputs - .as_ref() - .unwrap() - .iter() - .for_each(|tv_script_input| { - let script_input_bytes = hex::decode(tv_script_input).unwrap(); - witness.push(script_input_bytes); - }); - - // Hint: use https://learnmeabitcoin.com/technical/script/ - let tv_script_hex = test_vector.given.script_hex.as_ref().unwrap(); - let script_buf: ScriptBuf = ScriptBuf::from(hex::decode(tv_script_hex).unwrap()); - debug!("script asm: {}", script_buf.to_asm_string()); - witness.push(script_buf.to_bytes()); - - let tv_control_block = test_vector.given.control_block.as_ref().unwrap(); - let control_block_bytes = hex::decode(tv_control_block).unwrap(); - witness.push(control_block_bytes); - - debug!("witness: {:?}", witness); - - // Concatenate all witness elements into a single hex string - let mut witness_hex_string = String::new(); - for element in witness.iter() { - witness_hex_string.push_str(&hex::encode(element)); - } - debug!("witness hex: {}", witness_hex_string); - - let expected_witness = test_vector.expected.witness.as_ref().unwrap(); - assert_eq!(&witness_hex_string, expected_witness); -} From 107fb972db00f895019785e7c27c4c5ccb9247a6 Mon Sep 17 00:00:00 2001 From: Ethan Heilman Date: Mon, 7 Jul 2025 11:02:27 -0400 Subject: [PATCH 066/131] Changes BIP-360 to use tapscript (#21) * Rewrote rationale * Fix bolded principles * Actually fix bold * Updates to talk about signature + public key size rather than just signature size * Took a pass over rationale * Started work on specification * Adds example tapscript hybrid signatures * More work on the specification * Cleans up TODO * Fixing grammar, other minor changes * SHL --> SLH * Apply suggestions from code review Co-authored-by: Hunter Beast * Adds discussion of SQIsign * Fixes broken llink to libbitcoinpqc Co-authored-by: Hunter Beast * Fixes writing in SQIsign section Co-authored-by: Hunter Beast * Add rational section on big signatures and public keys * Fixes typos * Adds script validation from BIP 341 * Add commas * Add design section, stack element size increase now in PQ sigs * Fixes typo * Fixes typos and formatting Co-authored-by: Hunter Beast * Add authorship to readme * Add diagram of P2QRH merke tree, scriptPubKey and Witness * Remove completed todo * Add security section * Clean up wording, moves some things around * Minor rewording * Review suggestions Co-authored-by: Hunter Beast * Clarified size differences * Changed header size and order * does --> doUpdate bip-0360.mediawiki Co-authored-by: Hunter Beast * Add related work section * Better scale figure * Respond to review comments * remove double space Co-authored-by: Armin Sabouri * Address review comments * Addressing Ademan comments * Sync source svg * Address review * Addresses review * Apply suggestions from code review Co-authored-by: Joey Yandle * Update bip-0360.mediawiki Co-authored-by: Joey Yandle * Update bip-0360.mediawiki Co-authored-by: Joey Yandle * Addressing review comments * Addressing reviews --------- Co-authored-by: Hunter Beast Co-authored-by: Armin Sabouri Co-authored-by: Joey Yandle --- README.mediawiki | 2 +- bip-0360.mediawiki | 749 ++++++++-------- bip-0360/merkletree.png | Bin 0 -> 75700 bytes bip-0360/merkletree.svg | 1874 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 2244 insertions(+), 381 deletions(-) create mode 100644 bip-0360/merkletree.png create mode 100644 bip-0360/merkletree.svg diff --git a/README.mediawiki b/README.mediawiki index daf3248d0c..42c54577f6 100644 --- a/README.mediawiki +++ b/README.mediawiki @@ -1173,7 +1173,7 @@ Those proposing changes should consider that ultimately consent may rest with th | [[bip-0360.mediawiki|360]] | Consensus (soft fork) | Pay to Quantum Resistant Hash -| Hunter Beast +| Hunter Beast, Ethan Heilman | Standard | Draft |- style="background-color: #cfffcf" diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki index 001664ffb3..66a28a08f4 100644 --- a/bip-0360.mediawiki +++ b/bip-0360.mediawiki @@ -3,6 +3,7 @@ Title: Pay to Quantum Resistant Hash Layer: Consensus (soft fork) Author: Hunter Beast + Ethan Heilman Comments-Summary: No comments yet. Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0360 Status: Draft @@ -11,13 +12,16 @@ License: BSD-3-Clause

- == Introduction == === Abstract === -This document proposes the introduction of a new output type using signatures based on Post-Quantum Cryptography (PQC). -This approach for adding a post-quantum secure output type does not require a hard fork or block size increase. +This document proposes the introduction of a new output type, Pay to Quantum Resistant Hash (P2QRH), via a soft fork. +P2QRH provides the same tapscript functionality as Pay to TapRoot (P2TR) but removes the quantum-vulnerable +key-spend path in P2TR. By itself, P2QRH provides protection against long-exposure quantum attacks, +but requires PQ signatures to provide full security against Cryptanalytically-Relevant Quantum Computing (CRQCs). +P2QRH is designed to provide the foundation necessary for a future soft fork activating PQ signature verification +in tapscript. === Copyright === @@ -25,7 +29,7 @@ This document is licensed under the 3-clause BSD license. === Motivation === -The primary threat to Bitcoin from Cryptoanalytically-Relevant Quantum Computers (CRQCs) +The primary threat to Bitcoin from Cryptanalytically-Relevant Quantum Computing (CRQCs) A Cryptoanalytically-Relevant Quantum Computer is an ''object'' which is only loosely defined by ''characteristics'' in quantum physics as of today. It could be understood in the context of this BIP and in bitcoin that it's a ''hardware-agnostic'' computer supposed to have the architecture to keep ''coherent'' a sufficient number of logical qubits to be able to run the Shor algorithm in an efficient fashion. is their potential to break the cryptographic assumptions of Elliptic Curve Cryptography (ECC), which secures Bitcoin's signatures and Taproot commitments. Specifically, [https://arxiv.org/pdf/quant-ph/0301141 Shor's algorithm] enables a CRQC to solve the @@ -39,7 +43,7 @@ offering insufficient protection. The computational complexity of this attack is [https://pubs.aip.org/avs/aqs/article/4/1/013801/2835275/The-impact-of-hardware-specifications-on-reaching ''The impact of hardware specifications on reaching quantum advantage in the fault-tolerant regime'']. This proposal aims to mitigate these risks by introducing a Pay to Quantum Resistant Hash (P2QRH) output type that -relies on PQC signature algorithms. By adopting PQC, Bitcoin can enhance its quantum +makes tapscript quantum resistant and enables the use of PQ signature algorithms. By adopting PQC, Bitcoin can enhance its quantum resistance without requiring a hard fork or block size increase. The vulnerability of existing Bitcoin addressesA vulnerable Bitcoin address is any @@ -79,8 +83,9 @@ As the value being sent increases, so too should the fee in order to commit the possible. Once the transaction is mined, it makes useless the public key revealed by spending a UTXO, so long as it is never reused. -It is proposed to implement a Pay to Quantum Resistant Hash (P2QRH) output type that relies on a PQC signature -algorithm. This new output type protects transactions submitted to the mempool and helps preserve the free market by +As the first step to address these issues we propose Pay to Quantum Resistant Hash (P2QRH), an output type that allows +tapscript to be used in a quantum resistant manner. +This new output type protects transactions submitted to the mempool and helps preserve the fee market by preventing the need for private, out-of-band mempool transactions. The following table is intended to inform the average Bitcoin user whether their bitcoin is vulnerable to a long-exposure @@ -167,389 +172,307 @@ HASH160 Used by P2PKH, P2SH, and P2WPKH addresses, though no using Grover's algorithm would require at least 10^24 quantum operations. As for Grover's application to mining, see [https://quantumcomputing.stackexchange.com/a/12847 Sam Jaques' post on this]. -=== Rationale === +=== Design === This is the first in a series of BIPs under a QuBit soft fork. A qubit is a fundamental unit of quantum computing, and -the capital B refers to Bitcoin. The name QuBit also rhymes to some extent with SegWit. +the capital B refers to Bitcoin. The name QuBit also rhymes to some extent with SegWit. This BIP proposes a new output type +called P2QRH (Pay to Quantum Resistant Hash). This output type is designed to support post-quantum signature algorithms +but those algorithms will be specified in future BIPs. It is proposed to use SegWit version 3. This results in addresses that start with bc1r, which could be a useful way to remember that these are quantum (r)esistant addresses. This is referencing the lookup table under [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. -P2QRH is meant to be implemented on top of P2TR, combining the security of classical Schnorr signatures along with -post-quantum cryptography. This is a form of hybrid cryptography such that no regression in security is presented -should a vulnerability exist in one of the signature algorithms used. One key distinction between P2QRH and P2TR -however is that P2QRH will encode a hash of the public key. This is a significant deviation from how Taproot works by -itself, but it is necessary to avoid exposing public keys on-chain where they are vulnerable to attack. - -P2QRH uses a 32-byte HASH256 (specifically SHA-256 twice-over) of the public key to reduce the size of new outputs and -also to increase security by not having the public key available on-chain. While HASH256 uses double SHA-256 like -Bitcoin's Proof of Work, this does not meaningfully increase quantum resistance compared to single SHA-256, as both -provide approximately 2^128 security against Grover's algorithm. The practical impact of quantum attacks on SHA-256 -remains theoretical since quantum circuits for SHA-256 are still theoretical, but using the same hash function as -Proof of Work maintains consistency with Bitcoin's existing security model. This hash serves as a minimal cryptographic -commitment to a public key in the style of a -[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#user-content-Witness_program BIP-141 witness program]. -Because it goes into the scriptPubKey, it does not receive a witness or attestation discount. - -Post-quantum public keys are generally larger than those used by ECC, depending on the security level. -Originally BIP-360 proposed NIST Level V, 256-bit security, but this was changed to NIST Level I, 128-bit security -due to concerns over the size of the public keys, the time it would take to verify signatures, and being generally -deemed "overkill". - -Support for FALCON signatures will be introduced first, with the intention of adding other post-quantum -algorithms as they are approved. By way of comparison, FALCON signatures are roughly 20x larger than Schnorr signatures. -FALCON has recently been approved by NIST. NIST approval streamlines implementations through establishing -consensus in the scientific and developer community. This means, to maintain present transaction throughput, an -increase in the witness discount will likely be desired in a QuBit soft fork. That will be specified in a future QuBit -BIP. - -An increase in the witness discount must not be taken lightly. It must be resistant to applications that might take -advantage of this discount (e.g., storage of arbitrary data as seen with "inscriptions") without a corresponding -increase in economic activity. An increase in the witness discount would not only impact node runners but those with -inscriptions would also have the scarcity of their non-monetary assets affected. The only way to prevent these effects -while also increasing the discount is to have a completely separate witness--a "quantum witness." Because it is meant -only for public keys and signatures, we call this section of the transaction the attestation. - -Additionally, it should be noted, whether an output with a P2QRH spend script corresponds to a PQC signature is not -known until the output is spent. - -While it might be seen as a maintenance burden for Bitcoin ecosystem devs to go from a single cryptosystem -implementation to three additional distinct PQC cryptosystems--and it most certainly is--the ramifications of a chain -broken through extrinsic factors should provide sufficient motivation. An increase in software maintenance everywhere -signatures are used should be seen as an acceptable compromise for maintained integrity of Bitcoin transfers during a -regime of quantum advantage. - -The inclusion of these three cryptosystems: SPHINCS+, CRYSTALS-Dilithium, and FALCON have various advocates -within the community due to their varying security assumptions. Hash-based cryptosystems are more conservative, -time-tested, and well-reviewed. Lattice cryptography is relatively new and introduces novel security assumptions to -Bitcoin, but their signatures are smaller and might be considered by some to be an adequate alternative to hash-based -signatures. - -The reason multiple cryptosystems are included is in the interest of supporting hybrid cryptography, especially for -high value outputs, such as cold wallets used by exchanges. To improve the viability of the activation client and -adoption by wallets and libraries, a library akin to libsecp256k1 will be developed. This library, libbitcoinpqc, -will support the new PQC cryptosystems and can be used as a reference for other language-native implementations. - -In the distant future, following the implementation of the P2QRH output type in a QuBit soft fork, there will likely -be a need for Pay to Quantum Secure (P2QS) addresses. A distinction is made between cryptography that's merely resistant -to quantum attack, and cryptography that's secured by specialized quantum hardware. P2QRH is resistant to quantum -attack, while P2QS is quantum secure. These will require specialized quantum hardware for signing, while still -[https://quantum-journal.org/papers/q-2023-01-19-901/ using public keys that are verifiable via classical means]. - -While P2QRH lacks features like signature aggregation for smaller transactions, it offers a pragmatic first step -toward quantum resistance. Future BIPs can add enhancements like P2QS, signature aggregation, and possibly full -BIP-32 compatibility once tested and viable. Until quantum cryptography hardware and advanced schemes are widespread, -P2QRH provides meaningful protection against quantum threats without delaying deployment for a perfect solution. - -Additional follow-on BIPs will be needed to implement P2QS, signature aggregation, and full BIP-32 compatibility -(if possible) BIP-32 relies on elliptic curve operations to derive keys from xpubs to support -watch-only wallets, which PQC schemes may not support.. However, until specialized quantum cryptography hardware -is widespread and signature aggregation schemes are thoroughly vetted, P2QRH addresses should be an adequate -intermediate solution that provides meaningful protection against quantum threats. - -== Specification == - -We define the signature scheme and transaction structure as follows. - -=== Descriptor Format === - -To integrate P2QRH into existing wallet software and scripts, we introduce a new output descriptor function -qrh(). This function represents a P2QRH output, similar to how wpkh() and tr() -are used for P2WPKH and P2TR outputs, respectively. - -The qrh() function takes a threshold value and multiple key specifications grouped by key type. The format is: - - qrh(threshold, keytype(0x01, [hash1, hash2, ...]), keytype(0x02, [hash1, hash2, ...]), ...) - -Where: - -* threshold is an integer specifying the minimum number of signatures required -* keytype is the hex value representing the key type (0x01 for secp256k1, 0x02 for FALCON-512, 0x04 for CRYSTALS-Dilithium Level I, 0x08 for SPHINCS+-128s) -* [hash1, hash2, ...] is an array of HASH256 hashes of public keys for the corresponding algorithm type - -For example: - - qrh(3, keytype(0x01, hash256(secp256k1_pubkey1), hash256(secp256k1_pubkey2), hash256(secp256k1_pubkey3), secp256k1_pubkey4_hash, secp256k1_pubkey5_hash), - keytype(0x02, hash256(falcon_pubkey1), hash256(falcon_pubkey2), hash256(falcon_pubkey3), falcon_pubkey4_hash, falcon_pubkey5_hash), - keytype(0x04, hash256(dilithium_pubkey1), hash256(dilithium_pubkey2), hash256(dilithium_pubkey3), dilithium_pubkey4_hash, dilithium_pubkey5_hash), - keytype(0x08, hash256(sphincs_pubkey1), hash256(sphincs_pubkey2), hash256(sphincs_pubkey3), sphincs_pubkey4_hash, sphincs_pubkey5_hash)) - -This represents a 3-of-5 multisig for each key type, with a total of 20 keys: 5 keys per type (3 full public keys and 2 -hashes) across 4 different key types. - -Internally, the descriptor computes the HASH256 of the concatenated HASH256 of all the quantum-resistant public keys, -with the threshold and key type bitmask prepended. For each key in the descriptor: - -- If it is already a hash (indicated in the descriptor), it is used directly -- If it is a public key, HASH256 is applied to it first - -This approach ensures that all items in the vector are HASH256 values, whether they originated from raw public keys or -were provided as hashes. During spending, this allows for selective disclosure of public keys, where some keys can -remain hidden (represented only by their hashes) while others are fully revealed with their corresponding public keys. -This flexibility is particularly valuable in multisig schemes where not all keys need to be revealed to satisfy the -threshold requirement. At a minimum, there should be two different key types in a P2QRH output: one key that makes use -of classical cryptography, and one that makes use of a PQC algorithm chosen within the wallet. - -Also, it's important to note that order of keys and hashes in the descriptor matters and is based on the original -public key values, in addition to the key type. Additionally, qrh() does not compile to script, but instead, describes -what's needed to compute the scriptPubKey hash commitment and also to reveal the attestation needed to spend the -output. - -=== Address Format === - -P2QRH uses SegWit version 3 outputs, resulting in addresses that start with bc1r, following -[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. Bech32 encoding maps version 3 to the -prefix r. - -Example P2QRH address: - -bc1r... (32-byte Bech32m-encoded HASH256 of the HASH256 of the public keys) - -=== ScriptPubKey === - -The scriptPubKey for a P2QRH output is: - - OP_PUSHNUM_3 OP_PUSHBYTES_32 - -Where: - -* OP_PUSHNUM_3 (0x03) indicates SegWit version 3. -* is the 32-byte HASH256 of the commitment, as defined in the Hash Commitment section below. - -==== Key Type Bitmask ==== - -The key type bitmask is a 1-byte value that indicates the type of key used in the commitment. It is encoded as follows: - -* 0x01 - Key type 0 - secp256k1 -* 0x02 - Key type 1 - FALCON-512 -* 0x04 - Key type 2 - CRYSTALS-Dilithium Level I -* 0x08 - Key type 3 - SPHINCS+-128s -* 0x10 - Unused -* 0x20 - Unused -* 0x40 - Unused -* 0x80 - Reserved for if additional key types are added in the future - -Example key type bitmask using all supported key types: - - 0x01 | 0x02 | 0x04 | 0x08 = 0x0F - -==== Hash Commitment ==== - -If there is only a single public key, the hash is computed as the HASH256 of the public key. - -In order to support multiple keys, as in the context of multisig or singlesig hybrid cryptography, the hash is -computed as a commitment to a vector of public key hashes: - -1. Sort the public keys first by key type, then by public key value -2. For each sorted public key, compute its HASH256 -3. Concatenate all the public key hashes in sorted order -4. Prepend key type bitmask and threshold to the concatenated hashes -5. Compute the HASH256 of the result - -For example with 4 public keys: - - // First sort the public keys - sorted_pubkeys = sort_by_key_type_and_value([pubkey1, pubkey2, pubkey3, pubkey4]) - - // Then compute hashes of sorted keys - h1 = HASH256(sorted_pubkeys[0]) - h2 = HASH256(sorted_pubkeys[1]) - h3 = HASH256(sorted_pubkeys[2]) - h4 = HASH256(sorted_pubkeys[3]) - - // Concatenate all hashes - concatenated = h1 || h2 || h3 || h4 +P2QRH (Pay to Quantum Resistant Hash) is a new output type that commits to the root of a tapleaf merkle tree. It is functionally +the same as a P2TR (Pay to Taproot) output with the quantum vulnerable key-spend path removed. Since P2QRH has no key-spend path, P2QRH omits the +taproot internal key as it is not needed. Instead a P2QRH output is just the 32 byte root of the tapleaf merkle tree as defined +in [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341] and hashed with the tag "QuantumRoot" as shown below. - commitment = key_type_bitmask || threshold || concatenated +[[File:bip-0360/merkletree.png|center|550px|thumb|]] - hash = HASH256(commitment) +To construct a P2QRH output we follow the same process as [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341] +to compute the tapscript merkle root. However, instead of the root of the Merkle tree being hashed together with the internal +key in P2QRH the root is hashed by itself using the tag "QuantumRoot". -With sort_by_key_type_and_value defined as: + +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) +Root = tagged_hash("QuantumRoot", ABCDE) + - def sort_by_key_type_and_value(pubkeys): - return sorted(pubkeys, key=lambda x: (x.key_type, x.public_key)) +A P2QRH input witness provides the following: -When spending, if a public key hash is provided in the attestation with an empty signature, that hash will be used -directly in the vector computation rather than hashing the full public key. This allows unused public keys to be -excluded from the transaction while still proving they were part of the original commitment. + +initial stack element 0, +..., +initial stack element N, +tapleaf script, +control block = [control byte, 32 * m byte Merkle path] # m is the depth of the Merkle tree + -The vector construction creates an efficient cryptographic commitment to multiple public keys while enabling -selective disclosure. +The initial stack elements provide the same functionality as they do in P2TR. That is, they place elements on the stack to +be evaluated by the tapleaf script, a.k.a. the redeem script. -A threshold is provided to indicate the number of signatures required to spend the output. This is used in the -cryptographic commitment in the hash computation and revealed in the attestation when spent. +The control block is a 1 + 32 * m byte array, where the first byte is the control byte and the next 32*m bytes are the +Merkle path to the tapleaf script. The control byte is the same as the control byte in a P2TR control block, +including the 7 bits are used to specify the tapleaf version. The parity bit of the control byte is always 1 +since P2QRH does not have a key-spend path. We omit the public key from the control block as it is not needed in P2QRH. +We maintain support for the optional annex in the witness (see specification for more details). -Only a single 32-byte X-only secp256k1 public key can be provided as key type 0. There are a few reasons for this: - -1. It maintains Taproot compatibility by removing ambiguity which key is representative of the Taptree. -2. It prevents abuse of public keys to store arbitrary data once quantum computing is ubiquitous. -3. When a secp256k1 key is specified in the key type bitmask, how many keys it commits to is unambiguous. -4. If multiple keys need to be committed to, they must be aggregated, which saves on transaction size. - -This design maintains compatibility for [https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki BIP-114] -Taproot Merkelized Alternative Script Tree (MAST) merkle root in the commitment, which makes P2QRH a -quantum-resistant version of Taproot transactions. The TapScript itself must however be provided in the witness, -as no script execution is allowed in the attestation. - -In a multisig context, aside from secp256k1 keys, the number of keys provided in the attestation is variable and -must meet the threshold as committed to in the hash computation and revealed in the attestation. - -When the address is generated, all public keys must be known in advance, and they must be sorted, first by key -type, then by public key value, so as to be deterministic. - -The key count does not need to be provided for PQC keys because the key type bitmask and threshold are sufficient -to validate a multisig transaction. - -In a singlesig context, multiple PQC keys can be provided, but the key type bitmask and threshold must still also -be provided to be consistent with the multisig semantics. The threshold will be set as 0x01, and the key type -bitmask will indicate how many keys of each type are present. - -=== Transaction Serialization === - -Following BIP-141, a new transaction serialization format is introduced to include an attestation field after the witness field: - - [nVersion][marker][flag][txins][txouts][witness][attestation][nLockTime] - -* marker: 0x00 (same as SegWit) -* flag: -** 0x02 (indicates the presence of attestation data only) -** 0x03 (indicates the presence of both witness and attestation data) -* attestation: Contains the quantum-resistant public keys and signatures. - -=== Quantum Transaction ID (qtxid) === - -The transaction ID is computed as the HASH256 of the serialized transaction, including the attestation and witness -(if a witness is present). When decoded, this is called the qtxid, which will differ from the txid and wtxid if an -attestation is present. - -=== Attestation Structure === - -The attestation field consists of: - -* key_type_bitmask: A [https://learnmeabitcoin.com/technical/general/compact-size/ compact size] value indicating which key types are present. -* threshold: A compact size value indicating the number of signatures required to spend the output. -* num_pubkeys: The number of public keys (compact size). - -For each public key: - -* key_type: The key type (compact size). Only one bit is used to indicate the key type. -* pubkey_length: compact size length of the public key (compact size). -* pubkey: The public key bytes. - -Then: - -* num_signatures: The number of signatures (compact size). - -For each signature: - -* signature_length: compact size length of the signature. -* signature: The signature bytes. +=== Rationale === -This structure repeats for each input, in order, for flexibility in supporting multisig schemes and various -quantum-resistant algorithms. +Our design to augment Bitcoin with quantum resistance is guided by the following principles: + +'''Minimize changes.''' We should reuse existing Bitcoin code and preserve +existing software behavior, workflows, user expectations and compatibility whenever possible. + +'''Gradual upgrade path.''' We should provide an upgrade path for wallets and exchanges which can be +carried out gradually and iteratively rather than all at once. This is critical as the earlier the ecosystem +begins upgrading to quantum resistance, the lower the number of coins at risk when quantum attacks become practical. + +'''Use standardized post-quantum signature algorithms.''' Standardized algorithms have undergone the most scrutiny and +are likely to be most well supported and well studied going forward. The entire Bitcoin ecosystem will benefit +from using the most popular post-quantum signature algorithms, including leveraging hardware acceleration +instructions, commodity trusted hardware, software libraries and cryptography research. + +'''Provide security against unexpected cryptanalytic breakthroughs.''' Consider the risk +if Bitcoin only supported one PQ signature algorithm, and then following the widespread rollout of CRQCs, a critical +weakness is unexpectedly discovered in this signature algorithm. There would be no safe algorithm available. We believe that +prudence dictates we take such risks seriously and ensure that Bitcoin always has at least two secure signature algorithms built +on orthogonal cryptographic assumptions. In the event one algorithm is broken, an alternative will be available. An added benefit +is that parties seeking to securely store bitcoins over decades can secure their coins under multiple algorithms, +ensuring their coins will not be stolen even in the face of a catastrophic break in one of those signature algorithms. + +Based on these principles, we propose two independent changes that together provide Bitcoin with +full quantum resistance. In this BIP, we introduce a new output type called P2QRH (Pay to Quantum Resistant Hash) so that tapscript +can be used in a quantum resistant manner. In a future BIP, we enable tapscript programs to verify two Post-Quantum (PQ) signature +algorithms, ML-DSA (CRYSTALS-Dilithium) and SLH-DSA (SPHINCS+). It is important to consider these two changes together because P2QRH must +be designed to support the addition of these PQ signature algorithms. The full description of these signatures will be provided in a future BIP. + +==== P2QRH ==== + +P2QRH is simply P2TR with the quantum vulnerable key-spend path removed so that it commits to the root of +the tapleaf merkle tree in the output. This allows P2QRH to reuse the mature and battle tested P2TR, tapleaf +and tapscript code already in Bitcoin. This reduces the implementation burden on wallets, exchanges, and +libraries since they can reuse code they already have. + +Both P2WSH (Pay 2 Witness Script Hash) and P2QRH protect against long-exposure quantum attacks and both provide +the same 256-bit security level. One may ask why not use the existing output type P2WSH instead of add a new one? +The problem with P2WSH is that it only works with pre-tapscript Script and cannot work with tapscript Script. +New protocols and programs in the Bitcoin ecosystem have largely moved to tapscript. Using P2WSH would require turning +back the clock and forcing projects to move from tapscript to pre-tapscript. More importantly, tapscript provides a far +easier and safer upgrade path for adding PQ signatures. Changes to pre-tapscript to enable it to support PQ signatures would likely +require adding tapscript features into pre-tapscript. Even if this was possible, it would represent far more work and +risk than adding a new output type like P2QRH. Tapscript, and thereby a tapscript compatible output such as P2QRH, +is the most plausible and convenient upgrade path to full quantum resistance. + +==== PQ signatures ==== + +By separating P2QRH from the introduction of PQ signatures, relying parties can move from P2TR to P2QRH +without simultaneously having to change from Schnorr signatures to PQ signatures. Simply moving coins from +P2TR to P2QRH protects those coins from long-exposure quantum attacks. Then to gain full quantum resistance, +verification of PQ signatures can be added as an additional tapleaf alongside Schnorr signaturesMatt Corallo, [https://groups.google.com/g/bitcoindev/c/8O857bRSVV8/m/rTrpeFjWDAAJ Trivial QC signatures with clean upgrade path], (2024). +When quantum attacks become practical, users would then be fully protected as the P2QRH output would allow +them to switch to sending their coins using the PQ signature algorithms. This allows the upgrade to quantum +resistance to be largely invisible to users. + +Consider the P2QRH output with three tapscripts: + +* Spend requires a Schnorr signature +* Spend requires a ML-DSA signature +* Spend requires a SLH-DSA signature + +In the event that Schnorr signatures are broken, users can spend their coins using ML-DSA. +If both Schnorr and ML-DSA are broken, the user can still rely on SLH-DSA. +While this pattern allows users to spend their coins securely without revealing the public +keys associated with vulnerable algorithms, the user can compromise their own security if +they leak these public keys in other contexts, e.g. key reuse. + +One intent in supporting Schnorr, ML-DSA, and SLH-DSA in tapscript, is to allow parties to construct outputs such that funds +are still secure even if two of the three the signature algorithms are completely broken. This is motivated by the use case +of securely storing Bitcoins in a cold wallet for very long periods of time (50 to 100 years). + +For PQ signatures we considered the NIST approved SLH-DSA (SPHINCS+), ML-DSA (CRYSTALS-Dilithium), +FN-DSA (FALCON). Of these three algorithms, SLH-DSA has the largest signature size, but is the most conservative +choice from a security perspective because SLH-DSA is based on well studied and time-tested hash-based cryptography. +Both FN-DSA and ML-DSA signatures are significantly smaller than SLH-DSA signatures but are based on newer lattice-based +cryptography. Since ML-DSA and FN-DSA are both similar lattice-based designs, we choose to only support one of them as the +additional value in diversity of cryptographic assumptions would be marginal. It should be noted that ML-DSA and FN-DSA do +rely on different lattice assumptions and it may be that case that a break in one algorithm's assumptions would not necessarily +break the assumptions used by the other other algorithm. + +We also considered SQIsign. While it outperforms the three other PQ signature algorithms by having the smallest signatures, +it has the worst verification performance and requires a much more complex implementation. We may revisit SQIsign separately in the +future as recent research shows massive performance improvements to SQIsign in version 2.0. "[SQIsign] signing is now nearly 20× faster, at 103.0 Mcycles, and verification is more than 6× faster, at 5.1 Mcycles" [https://csrc.nist.gov/csrc/media/Projects/pqc-dig-sig/documents/round-2/spec-files/sqisign-spec-round2-web.pdf SQIsign: Algorithm specifications and supporting documentation Version 2.0 (February 5 2025)]. + +ML-DSA is intended as the main PQ signature algorithm in Bitcoin. It provides a good balance of security, performance +and signature size and is likely to be the most widely supported PQ signature algorithm on the internet. SLH-DSA has a radically +different design and set of cryptographic assumptions than ML-DSA. As such SLH-DSA provides an effective +hedge against an unexpected cryptanalytic breakthrough. + +P2QRH, ML-DSA, and SLH-DSA could be activated simultaneously in a single soft fork or P2QRH could be activated first and then +ML-DSA and SLH-DSA could be independently activated. If at some future point another signature +algorithm was desired it could follow this pattern. + +We consider two different paths for activating PQ signatures in Bitcoin. The first approach is to redefine OP_SUCCESSx opcodes for each +signature algorithm. For ML-DSA this would give us OP_CHECKMLSIG, OP_CHECKMLSIGVERIFY and OP_CHECKMLSIGADD. The second approach is to use a new tapleaf version that changes the OP_CHECKSIG opcodes to support the +new PQ signature algorithms. In both cases, we would need to include as part of the soft fork an increase in the tapscript stack element +size to accommodate the larger signatures and public keys sizes of the PQ signature algorithms. + +The OP_SUCCESSx approach has the advantage of providing a straightforward path to add new signature algorithms in the future. Simply redefine +a set of five OP_SUCCESSx opcodes for the new signature algorithm. This would allow us to activate a single PQ signature at a time, adding +new ones as needed. Additionally this approach allows developers to be very explicit in the signature algorithm type that they wish to verify. +The main disadvantage is that it uses five OP_SUCCESSx opcodes per signature algorithm. Supporting ML-DSA and SLH-DSA would require ten new opcodes. + +Adding PQ signatures via a tapleaf version increase does not introduce any new opcodes and allows previously written tapscript programs to be used with PQ signatures +by simply using the new tapleaf version. Instead of developers explicitly specifying the intended signature algorithm through an opcode, the algorithm +to use must be indicated within the public key or public key hash'''Why not have CHECKSIG infer the algorithm based on signature size?''' Each of the three signature algorithms, Schnorr, ML-DSA, and SLH-DSA, have unique signature sizes. The problem with using signature size to infer algorithm is that spender specifies the signature. This would allow a public key which was intended to be verified by Schnorr to be verified using ML-DSA as the spender specified a ML-DSA signature. Signature algorithms are not often not secure if you can mix and match public key and signature across algorithms.. +The disadvantage of this approach is that it requires a new tapleaf version each time we want to add a new signature algorithm. + +Both approaches must raise the stack element size limit. In the OP_SUCCESSx case, the increased size limit would only be effect for transaction outputs +that use of the new opcodes. Otherwise this stack element size limit increase would be a soft fork. If the tapleaf version is used, then the stack +element size limit increase would apply to any tapscript program with the new tapleaf version. + +To improve the viability of the activation client and adoption by wallets and libraries, a library akin to +libsecp256k1 will be developed. This library, [https://github.com/cryptoquick/libbitcoinpqc libbitcoinpqc], will support the new PQ signature algorithms +and can be used as a reference for other language-native implementations. + +==== PQ signature size ==== + +Post-quantum public keys are generally larger than those used by ECC, depending on the security level. Originally BIP-360 +proposed NIST Level V, 256-bit security, but this was changed to NIST Level I, 128-bit security due to concerns over the +size of the public keys, the time it would take to verify signatures, and being generally deemed "overkill". + +We recognize that the size of ML-DSA (CRYSTALS-Dilithium) and SLH-DSA (SPHINCS+) signatures + public key pairs is a significant concern. +By way of comparison with Schnorr public key + signature pairs, SLH-DSA is roughly 80x larger and ML-DSA is roughly 40x larger. This means to +maintain present transaction throughput, an increase in the witness discount may be desired. + +An increase in the witness discount must not be taken lightly. Parties may take advantage of this discount for purposes other than +authorizing transactions (e.g., storage of arbitrary data as seen with "inscriptions"). An increase in the witness discount would +not only impact node runners but those with inscriptions would have the scarcity of their non-monetary assets affected. + +There was some hope of designing P2QRH such that discounted public keys and signatures could not be repurposed for the storage of +arbitrary data by requiring that they successfully be verified before being written to Bitcoin's blockchain, a.k.a. "JPEG resistance". +Later research Bas Westerbaan (2025), [https://groups.google.com/g/bitcoindev/c/5Ff0jdQPofo jpeg resistance of various post-quantum signature schemes] +provided strong evidence that this was not a feasible approach for the NIST approved Post-Quantum signature algorithms. +It is an open question if Post-Quantum signature algorithms can be designed to provide JPEG resistance. + +==== Raising tapscript's stack element size ==== + +A problem faced by any attempt to add PQ signatures to tapscript is that the stack elements in tapscript cannot be larger than 520 bytes +because the MAX_SCRIPT_ELEMENT_SIZE=520. This is problematic because PQ signature algorithms often have signatures and +public keys in excess of 520 bytes. For instance: -For each input, a separate attestation field is used. To know how many attestation fields are present, implementations -must count the number of inputs present in the transaction. +* ML-DSA public keys are 1,312 bytes and signatures are 2,420 bytes +* SLH-DSA public keys are 32 bytes and signatures are 7,856 bytes -==== Attestation Parsing Example ==== +We will first look at our approach to the problem of PQ signatures and then give our solution for public keys larger than 520 bytes. -Signing for a single input using both secp256k1 Schnorr and FALCON-512: +To keep P2QRH small and simple, we have opted not to raise the stack element size limit as part of P2QRH, but instead make this change when +adding of PQ signatures. That said, we are not strongly opposed to putting this increase in P2QRH. -Number of public keys: +We propose a stack element size limit of 8,000 bytes. We arrive at 8,000 by rounding up from the needed 7,856 bytes. - [key_type_bitmask]: 0x03 - [threshold]: 0x01 - [num_pubkeys]: 0x02 +OP_DUP will duplicate any stack element. Thus, if we allowed OP_DUP to duplicate stack elements of size 8,000 bytes, it would be possible +to write a tapscript which will duplicate stack elements until it reaches the maximum number of elements on stack, i.e. 1000 elements. +An increase from 520 bytes to 8,000 bytes would increase the memory footprint from 520 KB to 8 MB. -Pubkey 1: - [key_type]: 0x01 - [pubkey_length]: 0x20 (32 bytes) - [pubkey]: public_key_secp256k1 +To prevent OP_DUP from creating an 8 MB stack by duplicating stack elements larger than 520 bytes we define OP_DUP to fail on stack +elements larger than 520 bytes. Note this change to OP_DUP is not consensus critical and does not require any sort of fork. This is +because currently there is no way to get a stack element larger than 520 bytes onto the stack so triggering this rule is currently +impossible and would only matter if the stack element size limit was raised. -Pubkey 2: - [key_type]: 0x02 - [pubkey_length]: 0x0701 (1793 bytes) - [pubkey]: public_key_falcon_512 +==== Public keys larger than 520 bytes ==== -Number of signatures: +Turning our attention to public keys larger than 520 bytes. This is not needed for SLH-DSA as its public key is only 32 bytes. +This is a different problem than signatures as public keys are typically pushed onto +the stack by the tapleaf script (redeem script) to commit to public keys in output. The OP_PUSHDATA opcode in tapscript fails if asked to push +more than 520 bytes onto the stack. - [num_signatures]: 0x02 +To solve this issue, for signature schemes with public keys greater than 520 bytes, we use the hash of the public key in the tapleaf script. +We then package the public key and signature together as the same stack element on the input stack. Since the hash of the public key is +only 32 bytes, the tapleaf script can push it on the stack as it does today. Consider the following example with a +OP_CHECKMLSIG opcode for ML-DSA: -Signature 1: - [signature_length]: 0x40 (64 bytes) - [signature]: signature_secp256k1 + +stack = [pubkey||signature] +tapscript = [OP_PUSHDATA HASH256(expected_pubkey), OP_CHECKMLSIG] + -Signature 2: - [signature_length]: 0x0500 (1280 bytes) - [signature]: signature_falcon_512 +1. OP_PUSHDATA HASH256(expected_pubkey) updates the stack to [HASH256(expected_pubkey), pubkey||signature] +2. OP_CHECKMLSIG pops HASH256(expected_pubkey) and pubkey||signature, checks HASH256(expected_pubkey) == pubkey and verifies signature against pubkey. -Note: This contrasts with multisig inputs, where the attestation structure repeats for each public key and signature. +==== Future considerations ==== -=== Signature Algorithms === +Additional follow-on BIPs will be needed to implement PQ signature algorithms, signature aggregation, and full BIP-32 compatibility +(if possible) BIP-32 relies on elliptic curve operations to derive keys from xpubs to support +watch-only wallets, which PQC schemes may not support.. However, until specialized quantum cryptography hardware +is widespread and signature aggregation schemes are thoroughly vetted, P2QRH addresses are an intermediate solution +to quantum threats. -The specific quantum-resistant signature algorithm used cannot be inferred from the length of the public key due to -collisions in length between algorithms. Instead, when each key is revealed in the attestation, the key type bitmask -indicates which algorithm was used. +== Specification == -Supported PQC algorithms and their NIST Level I parameters: +We define the Pay to Quantum Resistant Hash (P2QRH) output structure as follows. -* '''secp256k1 - BIP-340 - Schnorr + X-Only''' -** Key Type 0 -** Public Key Length: 32 bytes -** Signature Length: 64 bytes -** Total Size: 96 bytes -** Cycles to sign: 42,000 (EdDSA) -** Cycles to verify: 130,000 (EdDSA) -* '''FN-DSA-512 - FIPS 206 - FALCON-512:''' -** Key Type 1 -** Public Key Length: 897 bytes -** Signature Length: 667 bytes -** Total Size: 1,564 bytes -** Cycles to sign: 1,009,764 -** Cycles to verify: 81,036 -* '''ML-DSA-44 - FIPS 204 - CRYSTALS-Dilithium Level I:''' -** Key Type 2 -** Public Key Length: 1,312 bytes -** Signature Length: 2,420 bytes -** Total Size: 3,732 bytes -** Cycles to sign: 333,013 -** Cycles to verify: 118,412 -* '''SLH-DSA-SHAKE-128s - FIPS 205 - SPHINCS+-128s:''' -** Key Type 3 -** Public Key Length: 32 bytes -** Signature Length: 7,856 bytes -** Total Size: 7,888 bytes -** Cycles to sign: 4,682,570,992 -** Cycles to verify: 4,764,084 +=== Pay to Quantum Resistant Hash (P2QRH) === -Implementations must recognize the supported algorithms and validate accordingly. +A P2QRH output is simply the root of the tapleaf Merkle tree defined in [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341] +and used as an internal value in P2TR. -A bitmask is used to indicate the algorithm used for each public key and signature pair. The bitmask enumerates based on -the key type as indicated above. This is used in the cryptographic commitment in the hash computation and -revealed in the attestation for each public key when spent. +To construct a P2QRH output we follow the same process as [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341] +to compute the tapscript merkle root. However, instead of the root of the Merkle tree being hashed together with the internal +key in P2QRH the root is hashed by itself using the tag "QuantumRoot" and then set as the witness program. -=== Script Validation === +=== Address Format === -To spend a P2QRH output, the following conditions must be met: +P2QRH uses SegWit version 3 outputs, resulting in addresses that start with bc1r, following +[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP-173]. Bech32 encoding maps version 3 to the +prefix r. -1. The scriptPubKey must be of the form: +Example P2QRH address: -OP_PUSHNUM_3 <32-byte hash> +bc1r... (32-byte Bech32m-encoded tapleaf merkle root) -2. The attestation must include: +=== ScriptPubKey === -* The quantum-resistant public key(s) whose HASH256 concatenated and hashed again matches the in -the scriptPubKey. +The scriptPubKey for a P2QRH output is: -* Valid signatures corresponding to the public key(s) and the transaction data. + OP_PUSHNUM_3 OP_PUSHBYTES_32 -* The key type bitmask and threshold must match the commitment in the scriptPubKey. +Where: -3. For multi-signature schemes, all required public keys and signatures must be provided for that input within the -attestation. Public keys that are not needed or available can be selectively disclosed by including their hash in the -attestation accompanied with an empty signature by providing a 0x00 signature length byte. This works so long as -enough keys to meet the threshold are provided. +* OP_PUSHNUM_3 (0x53) indicates SegWit version 3. +* is the 32-byte tapleaf merkle root. + +==== Script Validation ==== + +A P2QRH output is a native SegWit output (see [[bip-0141.mediawiki|BIP141]]) with version number 3, and a 32-byte witness program. +Unlike taproot this witness program is the tapleaf merkle root. For the sake of comparison we have, as much as possible, copied the +language verbatim from the [[bip-0341.mediawiki|BIP341]] script validation section. + +* Let ''q'' be the 32-byte array containing the witness program (the second push in the scriptPubKey) which represents root of tapleaf merkle tree. +* Fail if the witness stack does not have two or more elements. +* If there are at least three witness elements, and the first byte of the last element is 0x50, this last element is called ''annex'' ''a'' and is removed from the witness stack. The annex (or the lack of thereof) is always covered by the signature and contributes to transaction weight, but is otherwise ignored during taproot validation. +* There must be at least two witness elements left. +** Call the second-to-last stack element ''s'', the script (as defined in [[bip-0341.mediawiki|BIP341]]) +** The last stack element is called the control block ''c'', and must have length ''1 + 32 * m'', for a value of ''m'' that is an integer between 0 and 128, inclusive. Fail if it does not have such a length. +** Let ''v = c[0] & 0xfe'' be the ''leaf version'' (as defined in [[bip-0341.mediawiki|BIP-341]]). To maintain ''leaf version'' encoding compatibility the last bit of c[0] is unused and must be 1 '''Why set the last bit of c[0] to one?''' Consider a faulty implementation that deserializes the ''leaf version'' as c[0] rather than c[0] & 0xfe for both P2TR and P2QRH. If they test against P2QRH outputs and require that last bit is 1, this deserialization bug will cause an immediate error.. +** Let ''k0 = hashTapLeaf(v || compact_size(size of s) || s)''; also call it the ''tapleaf hash''. +** For ''j'' in ''[0,1,...,m-1]'': +*** Let ''ej = c[33+32j:65+32j]''. +*** Let ''kj+1 depend on whether ''kj < ej'' (lexicographically): +**** If ''kj < ej'': ''kj+1 = hashTapBranch(kj || ej)''. +**** If ''kj ≥ ej'': ''kj+1 = hashTapBranch(ej || kj)''. +** Let ''r = hashQuantumRoot(km)''. +** If ''q ≠ r'', fail. +** Execute the script, according to the applicable script rules, using the witness stack elements excluding the script ''s'', the control block ''c'', and the annex ''a'' if present, as initial stack. This implies that for the future leaf versions (non-''0xC0'') the execution must succeed. + +The steps above follow the script path spending logic from [[bip-0341.mediawiki|BIP-341]] with the following changes: +- The witness program is the tapleaf merkle root and not a public key. This means that we skip directly to BIP-341 spend path tapleaf merkle tree validation. +- We compute the tagged tapleaf merkle root r and compare it directly to the witness program q. +- The control block is 1 + 32*m bytes, instead of 33 + 32*m bytes. ==== Sighash Calculation ==== @@ -567,60 +490,91 @@ procedure specified in BIP-341 to maintain compatibility with Taproot signatures If a sighash flag other than DEFAULT is needed, it can be placed in the transaction witness. In this case, it will be the only field in the witness. -==== Signature Verification ==== - -Signature verification is as follows: - -1. Extract the from the scriptPubKey. - -2. For each input: +=== Compatibility with BIP-141 === -* Compute hashed_pubkeys as specified in the Hash Computation section. +By adhering to the SegWit transaction structure and versioning, P2QRH outputs are compatible with existing transaction +processing rules. Nodes that do not recognize SegWit version 3 will treat these outputs as anyone-can-spend but, per +[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP-141], will not relay or mine such transactions. -* Compare the resulting hash to . If they do not match, the script fails. -3. Verify each signature against the corresponding public key and the sighash. +=== Transaction Size and Fees === -4. Ensure that the signature algorithm used matches the expected lengths for NIST Level I security, and is supported by -the implementation. +Equivalent P2QRH and P2TR outputs are always the same size. P2QRH inputs can be slightly larger or smaller than +their equivalent P2TR inputs. Let's consider the cases: -=== Compatibility with BIP-141 === +'''P2TR key-spend''' P2QRH inputs will be larger than P2TR inputs when the P2TR output would have been spent via the key-spend path. +P2QRH quantum resistance comes from removing the P2TR key-spend path. Consequently it cannot make use of taproot's optimization +where P2TR key-spends do not require including a merkle path in the P2TR input. If the Merkle tree only has a single tapleaf, +no Merkle path is needed in the control block giving us a 1 byte control block. -By adhering to the SegWit transaction structure and versioning, P2QRH outputs are compatible with existing transaction -processing rules. Nodes that do not recognize SegWit version 3 will treat these outputs as anyone-can-spend but, per -[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP-141], will not relay or mine such transactions. +P2QRH witness (103 bytes): + +[count] (1 byte), # Number of elements in the witness +[size] signature (1 + 64 bytes = 65 bytes), +tapleaf script = [size] [OP_PUSHBYTES_32, 32 byte public key, OP_CHECKSIG] (1 + 1 + 32 + 1 bytes = 35 bytes), +control block = [size] [control byte] (1 + 1 = 2 bytes) + -=== Usage Considerations === +P2TR key-spend witness (66 bytes): + +[count] (1 byte), # Number of elements in the witness +[size] signature (1 + 64 bytes = 65 bytes) + -==== Transaction Size and Fees ==== +Thus, the P2QRH input would be 103 - 66 = 37 bytes larger than a P2TR key-spend input. -Quantum-resistant signatures are significantly larger than traditional signatures, increasing transaction size and the -fees required. Users and wallet developers should be aware of this and plan accordingly. +If the Merkle tree has more than a single tapleaf, then the Merkle path must be included in +the control block. +P2QRH witness (103+32*m bytes) + +[count] (1 byte), # Number of elements in the witness +[size] signature (64 + 1 bytes = 65 bytes), +tapleaf script = [size] [OP_PUSHBYTES_32, 32 byte public key, OP_CHECKSIG] (34 + 1 bytes = 35 bytes), +control block = [size] [control byte, 32 * m byte Merkle path] (1 + 1 + 32 * m = 2 + 32 * m bytes) + -For example, for CRYSTALS-Dilithium Level I, a single public key is 1,312 bytes, and a signature is 2,420 bytes, resulting in a substantial increase over current -ECDSA or Schnorr signatures. +For a Merkle path of length m, it would add an additional ~32 * m bytes to the P2QRH input. This would +make it 37 + 32 * m bytes larger than a P2TR key-spend inputIf m >= 8, then the compact size will use 3 bytes rather than 1 byte. -==== Performance Impact ==== +Considering a P2QRH output that has a PQ signature tapleaf and a Schnorr tapleaf. The P2QRH witness to spend the Schnorr path +would be 103 + 32 * 1 = 135 bytes. It is unfortunate that we can not use the key-spend optimization for P2QRH inputs, but the key-spend optimization is +exactly what makes P2TR vulnerable to quantum attacks. If spend-key was quantum resistant we wouldn't need P2QRH at all. -Verification of quantum-resistant signatures will be computationally more intensive, and any attestation discount will -also increase storage requirements. Node operators should consider the potential impact on resource usage in the long -term. Developers may need to optimize signature verification implementations, especially by implementing caching for -key generation. +'''P2TR script-spend''' P2QRH inputs will be smaller than equivalent script-spend path P2TR inputs. This is because P2QRH inputs +do not require that the input includes a public key in the witness control block to open the commitment to the tapleaf merkle root. +An equivalent P2QRH input will be 32 bytes smaller than a P2TR script-spend input. -==== Algorithm Selection ==== +=== Performance Impact === -Introducing three quantum-resistant algorithms to the Bitcoin ecosystem provides users with the option to select an -appropriate algorithm for their use case, generally based on the amount of value they wish to secure. Developers can -choose to implement support for multiple algorithms in wallets and on nodes to offer quantum-resistant options. +P2QRH is slightly more computationally performant than P2TR, as the operations to spending a P2QRH output is a strict +subset of the operations needed to spend a P2TR output. -==== Backward Compatibility ==== +=== Backward Compatibility === Older wallets and nodes that have not been made compatible with SegWit version 3 and P2QRH will not recognize these outputs. Users should ensure they are using updated wallets and nodes to use P2QRH addresses and validate transactions using P2QRH outputs. +P2QRH is fully compatible with tapscript and existing tapscript programs can be used in P2QRH outputs without modification. + == Security == +P2QRH outputs provide the same tapscript functionality as P2TR outputs, but without the quantum-vulnerable key-spend +path. This enables users, exchanges and other hodlers to easily move their coins from taproot outputs to P2QRH outputs +and thereby protect their coins from long-exposure quantum attacks. The protection from long-exposure quantum attacks +does not depend on the activation of post-quantum signatures in Bitcoin but does require that users do not expose their +quantum vulnerable public keys to attackers via address reuse or other unsafe practices. + +P2QRH uses a 256-bit hash output, providing 128 bits of collision resistance and 256 bits of preimage resistance. +This is the same level of security as P2WSH, which also uses a 256-bit hash output. + +P2QRH does not, by itself, protect against short-exposure quantum attacks, but such attacks can be mitigated by the future +activation of post-quantum signatures in Bitcoin. With P2QRH hash, these would provide full quantum resistance to P2QRH outputs in Bitcoin. +That said, the protection offered by resistance to long-exposure quantum attacks should not be underestimated. It is likely +that the first CRQCs (Cryptographically Relevant Quantum Computers) will not be able to perform short-exposure quantum +attacks. + + {| class="wikitable" |+ Candidate quantum-resistant signature algorithms ordered by largest to smallest NIST Level V signature size |- @@ -699,6 +653,41 @@ proposed solution] in an Ethereum quantum emergency is quite different from the a hard fork of the chain, reverting all blocks after a sufficient amount of theft, and using STARKs based on BIP-32 seeds to act as the authoritative secret when signing. These measures are deemed far too heavy-handed for Bitcoin. +P2QRH and MAST (Merkelized Abstract Syntax Tree) [https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki BIP-114], +and related BIPs [https://github.com/bitcoin/bips/blob/master/bip-0116.mediawiki BIP-116], [https://github.com/bitcoin/bips/blob/master/bip-0117.mediawiki BIP-117], +share the idea of committing to a Merkle tree of scripts. While MAST was never activated, taproot +[https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341] incorporated this idea of a Merkle tree of +scripts into its design. P2QRH inherits this capability from taproot because P2QRH is simply taproot with the key-spend +path removed. As a result, P2QRH does have the taproot internal key or tweak key, instead P2QRH commits directly to the +Merkle tree of scripts. + +Below we attempt to summarize some of the ideas discussed on the Bitcoin Bitcoin-Dev that relate to P2QRH. + +The idea of a taproot but with the key-spend path removed has been discussed a number of times in the Bitcoin community. +[https://gnusha.org/pi/bitcoindev/CAD5xwhgzR8e5r1e4H-5EH2mSsE1V39dd06+TgYniFnXFSBqLxw@mail.gmail.com/ OP_CAT Makes Bitcoin Quantum Secure] +notes that if we disable the key-spend in taproot and activated CAT [https://github.com/bitcoin/bips/blob/master/bip-0347.mediawik BIP-347], +we could achieve quantum resistance by using Lamport signatures with CAT. Lamport and WOTS (Winternitz One-Time Signatures) built from CAT +are quantum resistant but are one-time signatures. This means that if you sign twice for the same public key, you leak your secret key. +This would require major changes to wallet behavior and would represent a significant security downgrade. +[https://groups.google.com/g/bitcoindev/c/8O857bRSVV8/m/rTrpeFjWDAAJ Trivial QC signatures with clean upgrade path] and +[https://groups.google.com/g/bitcoindev/c/oQKezDOc4us/m/T1vSMkZNAAAJ Re: P2QRH / BIP-360 Update] discusses the idea of +taproot but with the future ability to disable the key-spend path. +The design of P2QRH is partly inspired by these discussions as P2QRH can be understood as P2TR without the key-spend path. + +Commit-reveal schemes such as +[https://gnusha.org/pi/bitcoindev/1518710367.3550.111.camel@mmci.uni-saarland.de/ Re: Transition to post-quantum (2018)] +and [https://groups.google.com/g/bitcoindev/c/LpWOcXMcvk8/m/YEiH-kTHAwAJ Post-Quantum commit / reveal Fawkescoin variant as a soft fork (2025)] +have been proposed as a way to safely spend bitcoins if CRQCs become practical prior to Bitcoin adopting achieving quantum resistance. +The essential idea is to leverage the fact that a CRQC can only learn your private key after a user has revealed their public key. +Thus, Bitcoin could fork in an alternative way to spend an output that would leverage this property. +Spending via commit-reveal would require two steps, first the user's commits on-chain to their public key along with a set of outputs the user wishes +to spend to. Then, in reveal, the user sign and reveals their public key. While CRQC might be able to generate competing signatures it can not produce +a commitment to the user's public key earlier than the user's commitment as it does not learn it until the reveal step. + +Commit-reveal schemes can only be spent from and to outputs that are not vulnerable to long-exposure quantum attacks, such as +P2PKH, P2SK, P2WPKH, etc... To use tapscript outputs with this system either a soft fork could disable the key-spend path of P2TR outputs +or P2QRH could be used here as it does not have a key-spend path and thus is not vulnerable to long-exposure quantum attacks. + == References == * [https://groups.google.com/g/bitcoindev/c/Aee8xKuIC2s/m/cu6xej1mBQAJ Mailing list discussion] @@ -735,4 +724,4 @@ the design of the P2TR (Taproot) output type using Schnorr signatures. Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name "QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as well to those who took the time to review and contribute, including Jeff Bride, Adam Borcany, Antoine Riard, Pierre-Luc -Dallaire-Demers, Ethan Heilman, Jon Atack, Jameson Lopp, Murchandamus, and Vojtěch Strnad. +Dallaire-Demers, Mark Erhardt, Joey Yandle, Jon Atack, Jameson Lopp, Murchandamus, and Vojtěch Strnad. diff --git a/bip-0360/merkletree.png b/bip-0360/merkletree.png new file mode 100644 index 0000000000000000000000000000000000000000..62c73f3139243ce88ef0a0e88f28f5c53d483472 GIT binary patch literal 75700 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%0D4?unJ!OJy zjQlnP(68q9cPH5+Vi_hR(}v4AibgZJHU7~T#jheGk`i8zOai)@;BlX~FGH6PqiKr{ zxOiu)Dj(glk`NZY)!SD5Sdv&#v_v=Rjn&+wCgW))y|7>BA>U%Dud_i#1#HA0*YzBh z=^%E0pOvjg(-bC2c4;x~g`^DmOa{4G9wq&!@LHdaH@n-D_GOaHdvAI#t3T?m__dOf z=i zrDlO)A9)gyX{J$XcjN8X{%r8<&)l=of}5?ywm;Wp|1%TWQw;JWHu3&3qiXW{q+@@9 zxpJ$uDs+b82aJkqj;24_XJ`^up)4PRXri}Rz*E0MVWdI zsB*Z0#RUNoE2Q68uE>OeS3Hd`5FHKp+S+SAvHm430mz3M*j#>%*}^t;Bgw55WF)zj z?qufyfmJ5$j2`%fO{I}RB(x000>=wI8{P)`E%z9bVjj`UXkzO3?#WXlS`~yxzb$y7 zMQF89>Ub#+qvW{U?8fot#O>Z;1x8+JH&gyb;b>X{Kk+UqRbcPs)X-h<#KP{oO5K_| zL%H(^fN5+(&KqF4r4N9h^Pu&shLL(@OeGX_D&81`Sg_@`|6`gfSFcE`Fc;F(Mgte1 z2t=>P5ER^5DIzrrz15s^A7&ZO;66{@7&sF+rX_7UI$ZKo%b4e9iZEZ5lkUv}773Q5 z)w7ZmcQ0&W^DsrxSv>+HScyrH_G$G#&nC=W1a^o(xZfs6n5FzUg5c9s5xIdfH0jV0 zrgGF9X4%pYJ1Sc)z9C1|z{9{?m1x%EkhaL6+zgc?LE}_{ysell*VD_{#C3HGvWe?n zjw8%+7Kpk^nl``UT89&S5lN~R4S>vsbRHTC#oo9kkE+V@Y>MHE0$g7tyVdtYwvrkqW zyHBCH$XaYkA$iuxy4=lHRE7lgEjm>@Q$rM+3HF#5G4_Db7=rI&@b~k?2rgPD)*1zc$c_Ub6>fKP5!*Gbu<=o9M4p6w0N$1`a;_OMv0t( zLy4J0Oz`_*755b;MojCJ!x)cg?o0=yQzQLOKveo zl~3*vd|yMgPl!qPU}rdGr@$95=8v#_q|_gE;Z(qpAn6l=THb@R}>>f zi^BQ$-HVD3*N)x4q^pQqE=b#%6ce`M#f4~{$1|vOEdWM?=rHKP!b^KFO}`FAy!o4$ zuO{No4y9-UZ9ET0U3USJmAEu(epi>bXo7cijXBbF^hDzFw>bcfq9K?}|7FqCZ`kQ% zWmzC>kNJMEw0>OknVFc#%HJ|dc~>S%w>Hxp)ynYc342Um$fO>U68JjLql}Jgs|$U#R_b2t?nWlUX)P|AK6FgzE|Ahk8?Y zXuB5x{`u-Z5>;wt{xvBB2wIPwxdSO~QUuzc=Np zT5liZ+H=|V(y#oR#2fGZAPR&xqU4yZ_=eiT8*BGJ!&*T2_v{E@QG=Txo3+teCIP(W zAWk!kKE*w^`ltu8(3zK4#rk!=`O4A1n?PO4DY~}#>-c{bTW+~*=6D2qmCo}w^YA9J zAAbI%{!$#Vvq^41FGJ_05hMM#1f&z3M&nv}G2;ojchgg$54q(F-`krKw30qfOPZov zyrNS3SiEI)t}Va7xh;H6n9}+pBfDS>RC9Ojk)~k8Q3!>i%rb%_jGF3_gh|5TNh1vw(V-o+Vyn9Js&D5 zns=3s!l_Uk6hqCAGnpTYi-v<2JA(u*Of@+z1(>PCfkPY zhNmg~-irREC-YdM85F0H68=1}qFLB#o+mn=C0F&w8mVcH2kS9SO@VaBdkXiAx6qeT zOqU>*m*IG_c+sFjZ3+jcDtupPxK~m_cH*F*qfFzs2)$ZY3p|c2lSno|OB((W-Vs5R zsO>a)|MM5j#7gm|gA=$O1#R+4Mv_YvrxahZShinmxY|jyg1m^$T-oJGU$I(`$oG~u z(i0}xOJ%nL-CZ6X6Q(RZO55r4-fOodwn}zCW=<@Z^<}7GSH_=}lf<6Uh02pST{tAd zb;C=n{Xh=s-t9rD6LyKR&aoGt{*o!ZX=$0SNC?J?g=G|6@FEb%CR_AN6~LvV|#>D@L3Fr5~|<^i}?hQS0YUDQM_k6QBK}E0ghC#_Q-_c zlzgmQ(@c46a|(ehGZ4{$4^v7kiIVL{rOuXYc4orSc|9zWMt60%>+L@ytC-1h^p6%M zvMhskm8Zae_jy}>VO8Nbb#7blyWly||Hkk^?U?W~Rs~z!b-aIko89>|U&sufUE`s*@o|LuW zNhn*P#jRh4-*Wgz`H5e>u~{Y)TCk(tmMNR_3U}+zU`Xd2jLP3s59-O-Ug*fDbU$)Dx@vdR)1S`4WXX$e731%!>LW|6G-@G-27w#dm?szHo1Qz&wld#hC#3LVD zsrFz{Mn#$M#yqtY6{o5ihEngG3EEj5$#pR#o%LzYb-o1Xu)0p^TG35gm}9{s7SB|l zfft6$w(ToU@vC$fzn1|5Og&|@lcLpEpc(I=E)3%$l6kPiwDCO2KDTgo64c5r-%RoF zzb#g=n6j}^m|jfmocaN>A(y{FjaL3K-}f$j3Fo19w`}6Z!hU3*K95|jICx5#1Tjh` zymPIIU|zF2FIm19$>#9y;g1fO$OpU&kJ9t~cqi^(vbGXX8?GvHiZ;pW_fiO$=ph~- zSUesdQk2<2O2 zs!ds&6N^nwQT>h-1#RBd^6B-`ZbT2N9)!0|r1us>{v8V)GYfaiPJ5NUmZDc|kF?<9 z%AfK^cl8F^vB5T9O@H+Z)_(>{!}C@b;E#C%EMLV#-E#sWJQEW#ccI){V=`40^h9@) z&!vWn2f#3FO8<$u#`rahf5#CQ-}KxPL9!!u*HBxQ$NCT&D~8lYhxALZ7i7Cv2myj1 zijqW{iv135I`=vGs&kcQlYnjFINv5sU0g9&cXKr4|!c$#0)>`&>50fo9F%l4#>JK~O?e#c!LL=h`<`@`wPfmVTKe%59o!@#Ms$43a4kMss%R-qjwy(NE@uWrmYRO zhQr?q3Aeuh#N+dj_x^EW5}V>z|)%vvcs7qd`|Tt5y`bUN8zUXU0bDt zmVt;s9!?cB@Gp*(=}$&eGP-LFqOYS$?3OpDP7{BUGC4aq+NoNO_ZZkVLQHS{%J;Kg z;sz;fdpIAwE|JD-lFS*k5z;AQQp2!)l z61=S4F&{xcOg`*ID;<5V)vgijk4)y#o?bR&KCRumRRO=*x=$gczZddPW9gO4l{gea zpm)Cfsn2MUsay?FRSyb_kXd|YbaUf(gd%0|dambfKa*rnA5Xm)`2S)73Y86q4?Y0h zvbG5%(%=&0dM#*|`dF>PGP;J~13n3F!>S(j0SO!-xv-U;TW^xz>EMNu=NsPK4&}D`hN8 z_EaMpyqZ>!RWpkn@09k~HihYvJdNI-(M?$m!iP_6P&97wFH=Ha95$i1e--1ytLA8i zVohmbt7<<)@p82S@r_OgP9Qpu2kuk`b*f&1K8a^~i|F5ohYeu792a1@aX`0e zxrZHzFhwPKiWw$)T+?^^BX?lz;8s7gtMBhr8*La8&NKgeu$o_#;KC^77m7TZ2)0T zDR2sT+=l|~<_oJZcVAX@AAqT{VT=PyQWl>_c`R?Nx!y@0)Sh{}oKg;7j9tKRLA0fS z_rV;ngGcQT62g4-+HkLtAD-J8-y)RB%~Mge9K|RMdQ}?Ul^`XU{Qd9&xAq*c2XBWr zeaL#S^Spd{j;1&S%e@)JnSWxF+*C?y>3LXDGho@VrEyKWAa`gsSZvp+UFyKdUX-+9UX%@hKIKU#$>=&}4gEsYhAxq6m4E+aA zId->~6<&+X3lm+Jpp2e6-ev5?*P5UF2jmIm%P+Mze{y>bA2r>D2(*(1Xwwr#0@R5A z?k??r3i28jd|Jc!in{Pe+h}uxJu{&lRSWp^V{!1dSB5>aD{aq%Yiq!YhtO%m0z=`W zl1e3`V3(|#P&djJ&Av_AjRGg{RQu28Nze(VxK85mFfEpZ zQB@toxoI<sX zf3`}J?_`Sm(Q9icHOp%X`Wp1YvL)N$TC7Nxt*m9P-{@s4T^3)7J#*f`3)hQ#Lelx- z4at*iS%2~`n0)cNSFRpX&Nzn@I@9X+S90YkM2km(jp0{SZb+_oVEiBpi zkp?%BOeP0>}S*&QV>tLc|OR}n*J%Y{#VH$xp_}^alH*I$~efo|B6Qv*jAqQ zEuX6<;jO@jP@_b1n}YI;V0mL}adDSQEDV59_|m}>-V<3Js&FOW_&9ulwSqT04;!Dz z(w(h%kV?LbCFuNBef($H$-Th-b1u2s6fQ|_QrOt343@eUovBE08;Rk2xeVWa_$X!K zjv#qEx{Lse8W2Bf23x+6JH1$G?;LwX&iBBgLKhnwbU9s39+h$Q1TX#5RujT2X$n|l zn6%)NHS7-%xM0&VDHA&uP2qI&4%HSeW`t=ykBpCq6cvU`_&WlH>5lXiJ#znBGyqyqeFb$Svte;>Y=(zME15DuseVq1DT@XR7_|CBOceRqfCXK2M zs4$b1@19}dW5k$+eA8Y@(lpmL(_gAUt&)?kPF`8A@nG^=Lk4)Jp|&tnfRX>VhgOzr z>iZu3ud(e)nPYT0#=h#CdYH!VYC3{nZ=q)Z*|k(`ADpB&tW8%##lQQ!t9UdHln{U+ zelre+dWGax;z&J@_;)Wpdfa6^&2U8{ADoxto=fnFqulYDcOz)Sdjof-J$>hi^wYE; z>PEWB{>X0T3qc+6{HHAj*X~`Vl?s+2w7jS^_%UOcHxKtiPNdjt^dV#g89@rQMJPOPmOb+ZycW zd-{_)_tu?I*rP{UrkpX(J=c80Ny?@xfs~x}*M|o~iENn~^O(s~sR390gOuU&=tRA; zUygdF0RY^Uv_xdx==+$_NG?3fymm2>#~nO}GX}js{zHWbefm7Qw5QfOd z&PzhlmVC+BNdECINk8d*ld6Iao-ybbXqmrSI~#nIIi)2@Hn)T4_wcVvAny)iQGIbI zpRh)-34ZsNs%1=BMGLWb&;T;0zuS^mH4mLK!&uq!{*A!U*2pSUi8-!@5>t=6F8@1n z*G1FS;91B4S-?s(;QNCfA+TlI==-#Kbi>FhwZnE9oBu{c;rX>bC4n<8ReqyhdN~tM zyJ5Z69yYlZC`Ov~fNl31=H45#&h$xH%WVOVrX=xhYR{$0E?McQF1b1Z?hIkGBt%Xcld)V+{4xw$;fB zFjXw$nk0N1Pb)f>8rdTvK`sAfO#PZ-2VZC9GQam`P;kqH-lIn<_`UuhjR(uq4SGzv z%HZ@Zn&^Fi!v5sG4`q$srdxWpXOLfy@|zj8=En*X+eb>yALOH$+9ot4cYl1Na{H=< zn^~^mt2JFgIr}J-N=|U>at?O+i4ds$)Y2{pg$fVEY=J|bl_^Rr9zKv{xVf{a*gX)L zX|T}BK)ztmgb@*@$r(J*8(hSX8lG`fWU3*i?s!9^+X=TnQ?xhMW z+wd2h=vxOnFI1OBZZhu@(=A4YK2SBTx0#*NXmaQRAQM7%pbR<= z+n}N__N}$`%od@JZzz-1U?0>iD}_o=B^HDi4E{J$K}GRw7QIjHYnD}~gEp8MZK)V= z421CSBBU zKWr-je2;9f|K#*CqxLrCC9%H*%GK-w56&ni%WeSn61v=naZKDLnFq)RJCRV~dF1-E zmud!f5QH!Wa;bBW-Yw!NXJpKXwHijnB!Ttbq4|(0)<+--6q{gFdfh)Ru;m4ZpeLrSsrC zqm}xC;!F2bZ4)at7(QzX82w4ywk}Q~$HW(1GxhvV%>J`1D=0u;JyOE>-P-bNB&9ap zrQ4u)RJ3P!Fp6Ht4iA-AW@mUOriSIzkFK5ZB(SN_U}v$&(3na34Zi;|$j}>qS^y-Lcpr{nl^e zxv?OUYGs{cvbXEuaN~aA6KZjB&86hhfsD;(=4VE3$CXnc72G;v)u3gR#=Ve-@vBzN zjO2zgjSx(R7gt8T8Wjp{^L)7lr{|9Qlz}fnn z?j}(fFoU{;agH*4VQ&*R`H!Fdllj*~NZYOyC($^i9Tf;}xTuM6hN?M96m( zHBq~AmWdY?V6ZdE*gSgovV+d)`6}_Jg6KB~6Dqk^BJ?~>4;v{hg2pxCFa4!nd!@cN zb?Ml;o^`EPN+!Tn1&Q-rk&J4)|1E~vNi)f79BsFviR1ZQe=XsD8bk6|qcI2Lq2I$* zlQux_(tjPv<*%2!HFAbA3OFv)T*r%Qf{%?I6}nh1(s>}h@>~}U6DuLzzCBIKlB*GK zZf0oXWX`D_X%ACN{`PdNAM>0Ta0{;5@@UUkz=n>O(z0BCG!fF;+3?Tw59M_juAfKR zk;3!G1CiS0-Cs#gOXbUb@=){6cG+9SkTsM7%hBjw1%kIzhDZSW`_w_n8 z@?$`iU7o`;uRZw*Suc$*WuKg%jTJ;@S$uzBe+-mr;0r(31-vF#!#@N`4Zcq?x1`I$ zX=Z~%Up+Qe3Di>IxHuv353F-MA~aWbJ4+wlA!-3zRY3-jaZ*$c(3nm(e_-U>vf@sT z!s2dF+}Sv!Ll%dG>slhNENkfJY<*Zimg7Qt3=?VT_6OfMy* zOs635v!O1iC}S)OGgJozOf|%Pt9(rcESq&(;d!WU0?CzOs|7BZ?m_&} z)5bF)mjVe2w(6&jXtCj`FCrG)O6j_C*Q7vh``s_1Xh;9J27oiosDswuYg%~&)g(Of zdLa*ww3KZ*(X*E(8}9U3cBU#+P|U7LjAkD1zEcuBf&E1$NwTPU*k`zVqQH+^Eu7BK#X}vBtlKW13lxMU!+IM4O zQbzVmdW5CDiTN53tU11>MO0L4kRr=NULn`b@{evm_UCo%N=1s~6w@A8C`P(n)0DpG ztKnMyR>~C{KFMaemeUzY7^4OCX&HSs#h{YS7`N(!t5_iE*yHq5;sHfI?Gww?z}q9& zS#N=v;SCehwN1|4>)V}EnJP)QdN8&K`RNLC;wEDeA948?wo0{g5!AiVDV?!a1*AMP zD=hMx;*Q!yL>05Af#0-Jh(?a~2W@VaKhdsAi_{FCMFBy;>la_cy^0w;yq)-lZ z!h}b{-)l3q)!8DxC>q)nh#%d4hh5vK93=Lg5iwqU)ABnWLjAdTMLHHXi22}jaK?z$ zGy>&mqa{AI0Wxkc-sLbJ!JEAhZ%z3a5ZFlSaXrSH4EAOfI^$Y+=^Y-P8&yW}DNyYV za!FGKjkg{2cPGPgPZMG0+B9QjVqhxlWmH!~0*f|Ja~}2sp0{b!L_0_{EC1#oEd_~u zd@$8ZKh}HW19Q8k-nM$4(8A9hbVwR^*u(17+qKf=6Dy?=tyb<$Ho1YO6*j%%hVN@U zdyVQ?$F>fB5$6w%AsX^9+S{(IuTw#sJ*FQ!QF;1an(R{z*{{_EsU5B94WrX(+MT{B z;2XJprpGsmcB-a7aQ>{7yj=W+( zg?9_+=Xs3qxvD)H>*|zuGs{)-Zblzv0$(8Zfls#X_S!M|eeR*PMwmP8R*v-MMo!j- zG1XsJ(F%OH8=buOziD6wNA!95^V%Zn6M$T);fCP*_`X??Ja2x*kAG$W-%b|!wcik@ zNP1TKE{DK#R4cb*7h&D!jLZWxyKg=k^AN&tl=xY}l%ZYld$3AZz*j}*&U-_Lzex%Q zT%>_Yl~M=l{wxVEeHA5<8lU(Vs}QD+c!XkLM%t2D^SwgUVqpV6F~LOT?$z*MlfE|I zwF;!s?XS(0N)T?j;a?D-<$(FROLMQtl!vQ!gygP+YTuwoD{kcG=q!CQ4raJSUs|GC zKPxSq>@cM){PpizwcULz(T89xHwM5E)xVB3Pp(1VoG+Hr8C!&?<6D@X`SX{zj^{zx zBxkx>HG@artz70no%x@Nm?Dn70h79dGwOen6N>gga*QPEhtM*pc;QkM5G;Fj`Y^BMH)2GVvYk)6uds>!-64snnyMhNef{EJo9T=RMJI|+QE z(Eeduc6cNj3RSGe;!)xFC2sY{Au z-cvSUe((rTd=|ondPIvyI@CRA3m9e@T>m-ENYcKh>drotbM~g1T40cXK9h7mR!XSf zXsompGACt|&{9}3UTqr|Fs%W2`)VBjp5YqvB>RN2O9v7>8A)7dfA)dQ0;H6Ob?#m+ zFe{rp!yq^7${+}FwBLx0%ID8f45u#Q8Y3WiyhYS#T{z!1E_ z{7&||4Xtv9WqSHIlXzx&)*$K_kVr2-B>h%9dU2GyH#s+ zG2U8@uc`M4#iPb=D;|6(lIxRd#5t$gcf~<3lZ|jU<{-;d@4G&M5Wj^~H?J}(V?rui zuAU;4_Rq+RGZRj~Kz9&65YQ#f)8y=;eT--eT$z&Os+78hEJQ7mPx!qu1^dzcIu3~; z6V8M00rHf}$dks6LSUaDm-`Abn(A}bZc`fEpU47n&%2x+xh&SRH9YclLUD9uayve} zMuU&RxuUTZ*Ht>GP;qV9_4Iih(WBCcTE@Z*=Zb&+OmNrp;DL6=x?6z?R~`er!t@;( z1l}(>c=1Gt>qazFZNm)xC(T)FS?!$yg_#~wHSP2Fkqp-dky06T>5PQ3JbL3AFbb9o zDHgVGNDdtdy8YqBig`DgP|HoV$?IFE>e6CeHPQdD@N_79U`3uZQ{#-q-w`wnn9}4|5mTQ9(nFe3)kFJ

|sm-~6UzOZnS%B`E~>im!DdaBL9Dkn%sG)qv#EURVTvNZ_` zmu}5|$QWK>hQgD2treQ$YkTVIIsWyf&VuV`{Zp}NI z!?&_!x(!C=+T$(SWw;k!=Z&4IM2X0$pKh=!x)cQqrcYuaprTK*Ml#ES``1Sv3H~@` zKhD_^qa85jbZJ&y+ZnD3yjwZbXaTzAO2Xb&NEu7|?Xxv)fl96>mAp4|34QO_%Bc6T zL3Ym~}uYtTbJ0G9m$|JiHiGEi>IZ%=G z;)NnzhV_KDbqkXCA5Zz7CR`9&@W=)RSta&;Ky#}msYB@y<@DloRa39VHF(ZtD}bL1 zpw})AQY117tw2~C6)F1bo5#u{P@f4?*pT&1FA_t#tyV;OyLg8&0C=+M#fum{Kb3*q zM6rnAib1)4QUOCC48wMzQIWQi!@u7oyqA_9ocWTr!_;Kt_CApy%hfG`iulP$+AxfW z1Q;EN%+x|n{qFgwPUcvI#!G!=CDcyx=}Bb?vgfyV@CW1Mnzk@^!-NT1M@q@36Pm6s zQ|HZDwSYZ#rs4zClKSzy+O)8nEtb3yR!HTg+}Jd0Gu&TcKTX?Zd8*pgqKwx|r!jZx z1B^5gu{<2Uy`=yvUunZ?zrVBX3=^5r`cO4auvYQ$u%{xcUK}IP>FQ-R83*gHa#GEn zI_~!2)+T?$^nD*Ott>vQw@}+TnGhRcl zxtGY}AS@5Y?g{r0ZUNg5m6k=wi|}7BeF>{5di<~Ae1T)C-$tkfM+O_iu?%@9HsG>6nly!=ABWdIk6+{1}q_TjD`tt${}Q7i78NxUot4 z>8)qRcn{N16j37V;r=pLx$Z~3EX~0eQIh3lE-Jqy&dT{&b7a&|^@@4ZyY5*rk__81 zH3W2Y^8ejd?GcBB+o05cf#d%;$V+aa$56lVBo!^+csou>eb@ktr)l zeB~|va=z2QZ<9H59~j-Ia9%`y!mHLm?$-B4K|n8J>UYy&1}@gX8l#&7x4}(!(bI>| zGlx61@^nRVt2T_mvBL#G8>3;0*s4|Js0QU{MMHU!99zRE^n4#1I_h|3VN1fo z{B+8EZ_XzBhIA(=Dp?nZ6MHaJ))Se)^e;XPa5>x97Dg44>MsBAyVsIBrJ8)hBM1fg z!({f|C7gNudG5nES*jdU+@Yl3xvKcap7OAy(aL(^DJ8hmbUoWxcda+Aj6GFyyzFF= z%jl@e*7Ynx!u zQha|_?+b`U`&LOxc1Tn_BcDT7?==TJ&J3J#)9NZNbS~{GT4(rfj$ls9o5%9|ge_Qz zoD|OG9^1p~wr2#}mq}5VHDwo#l@hHZ4P3FU9Bs&%+Fu7!eucb!n`!AulL~)tjK_PV?!1ni-n6x-_<=g|&Hbw=G6@VKaehvoX;iJZ<&8RP!Xd z#wYdcX&Q8<4k_QfQh$#MK8h|kHc5V8Rsg?}_mFlxdY8#Qll}*u)F|;Si|EG9`VB83 z-0A!v4NNPdoOio3IP|xKC}P(iReYB^SweZVfP`AA_0>(qgm~~pc_;>Aym`$)Ziz>> zCK9V%Z|a{lu%p)d4>9w+Uw2E7t`v6~eFPD^5)7KS2(TsKeMC|pdh2uSk#)Il?5{sm zdkWj%!Kc3f>uPv5<%=U6=p}X(S0ce}Qm)Njaz&R7;Nsr2c$fh(i#0QNs~HJ7=lB zI=-aP9?bwbZRf3W&d)41RK(23Ae9i^IXcO%z+&RH@w$N9@l9`xI_t5bwV`%+;d%C7 z^P{(=QX6l#U-Gzn^su8aVrqJp{fo&J7w z?z@BRs0QBi^p_fBoPRU!9PyXVfHj%TT9oK{UYB7v7!%|f&wJZt_GLryHSpoBQwEyK z56vW^aTgYHtGfHGhv{4p+99z{>1NnXG?(JFT=em=jd+FM*7hFn*MZD}_O~09;Code ze@&%>da+~K7S?Y{W3gd;$twS2cdrRadk#_~xS|3nZY57wSph~DTJTxngp>@j6_tOy zg009Ezh?o_Ro@P0AvzLJJIXf#Z!HMx{4GDowD#gnda<3~{+SYolcHF4J^3?)fp278Vpjd4A5k_Y3ehiDv zzW3e$h3z>{YnkcL_tXfNNBFDD-qmL}u)x(x<$AT9jJ2$-a2fxBPnsl`zqMP@Wu-R9|Gmd`h(4Ik!Hf0Wz*sT~$nb|ep zMN5bWAh#q&O2SWum$B&fVOguZq zk;Xky)W?&*(gS6sg}b<&o$Qrh!`9$(M&6PU{*|GMbCH8IYW*8%Bz+c(Kgk{-(@ruRtsXF(4awXkwJBgAW?NZSq+mj0^|K~@jfO#M(eXfLv z$Q|0cd}ZuV_E3$=;P%YPwSr*vV1D`_2SoJ%NDvZQbjZ|xXgx(?fvsdNDFsURU7q(Z z9q3tS)*DWEZaMC^+yRrn_m`rHRoEIhI%CL+)PjC~a?O2;QQ9wv2Y-JAmsNDXh`9@Qa0lz(2PG}5kW+9L)<;YK;5lRqM4D3*WwCV|wD!zoL(ioX<5+ixSi;@hVDPT8In^LiVWU zl$qU#e8Tb}gV_<{nxMWw`r?yKUf!Z$T&@p9v)_dyejg->Hrb%AN)o^&+QbjuU+e?fwJcKF5 z9|VQa66sHpdPmQ%nHfp8?8S%2hGUdyN5Av_@b=11%zZr7i=>M!&i-H>4aWDK7e%k8 z6MWU(tob@V7e%l;+O>k7+vB``P)}yDEvioS2RTW4%+j_>CUhSgK|qqGofC0K z#Z3;K-3uG_>zU58Te=y(y9f0>o|@E0C8E2wi030>mR&;TyXRc-G2~3G7-cTm`Nw44`F$8GzCE2 zzigYhf#hIm8oSIKC6!Jtd8GUK?fc!!#dS1oM}P zlods+(5T>^O~LgfQX#Ubg+{K;(1n4+FANr-uNrs070cai=uy;}*J>yg|IC}y-75js zoJjtoK-T|5(^-Yp&1_+~Efg)q-KDs@ySqavZkys(+>5&wcXxLyP~6?!ZR5I;lmFse z^6ZdgCTp$vzIP^>a_UT7KE`rT_QFvbsI41_tZw05L&BLBCMU=*m%|nUz16;T*OyOY zz{Rh9QGT}hNY%wU8k%}?oPY$&owa(|1fYKUJ);J;1V<-l=d(;qrcPfuYPojsI#(Y` zG)aA)%R17xRg$hb92{+*#yK4PECedf=WA>J=@dj5&Uo_I8K1o1My6B*4PxOu{nDSd z)#TYjX{mKf#fPE*4Ie))=1cC5a!vRsRxon20%u^->v}Z44gqGG-QJPxRLew>XA`8i zt}{o=6JLMtQmqcczfl}}soMU!U>csOvIRFQR)Vstj@q*ICk3aS!dJC@qsP$Hro;|c z+pu!!-R8b*QdWWjDK?tMh~3o7Wc_V5v1|yU7zbDj-JU? zif-WXhyJ4<=*dfrM1hSS?%MCI>LYUDcY@-(H16((CxdXz5K9?6`leEefs(^JRV>OD_V?*iRk-ZLw)zwR`>iwLQ$zWaRr@kIpZ{)^N2c==Paz+J-AxMCeiqK z&Hx9cNwB#=1fvmIMS}dz^b&>Ttif?;kW;3+vbk;|q# zWn8_TI$g7&7Wfxr4}fs~SZ=JzE~}3PxaYZpe3kx@&b>2Z^m&!OkEeBON<6 zliO@YTWo}?Mm<0M9unU~32xhE5C=9hkybnYtn7Png3pwk!@@KxxUt3>eY;!uuAh6M zcl-QR{DIED0{SA)fu2_%>{qpG9=G^mhHv!1 z0>8)h1qUy5m!_wad}{m1s3Tx6{l*`n=t@DFB~o?*QFw4gX|sP9K~6Ssa63MOE)XRY z*}gh_BEYNhjkFPhd7OK_FM}SO)fMYK*;S$V1!8?V3$+eg4(ECDoE>j0$5xeEB>DMj z$^Im+MYF2{I*OTq5ER6P?Oa^_Dp}H4V;bN~s{9R}*8|sol(x9UOE$>Yc%Q)N${I0j zD0@Z__)Q$!F|vZTzS}od@8%ET*WjFN_#7A!)p1%9vQ&0Mmj)5bv7I&+t@DvaEA3ac2O?*SuSAkcfFYBe#5yF_vJ;+ZG zuRy!Hx7Jlr1EH7}GecaYJ4! z{0{nVWbUl4o%)cDHU=8^e7b&MGrV0$Ob)GpoAb?Y6{d_^rgry9*t5K%29k#hqLce# z2P&vUoZ57o(g>2U#%3;criOnhHkz3ezY zZHC5N;%8r$(ipIcKk-B75IK`~+%BFR-dx+&Sl?Ky|FO50e|W61{!UV%-)VVf;ygQ( z>S;^C<%B$Bn@ZvY4!)4qJ1)%U=&{}kYS)KW>rtgRdbBzgyN)I=xi?2gz#-Cpk4nASs@hh>#2LVa!79MEVwdJM%f&wR}LXzV6R0kFJ9@_zCg z+ObPKIh?>^-XZ%B{pbY>K4{1l>&cf_Orwt5n`M^3D@QCN>zgiPEA*Et%@)pQ&rrT* z-vp1%7q=yv1x8}|nUpKmvi*nMd}1bV1H~4n=;-8j$)+c#OeqwE-2 zGd+y zvy&Gi^rH3%ROPMM(kV1<~;&7NauAy=Eg;_#hEF(ia|E%Wb>ATZlm@P9fKWr|9 zbE46cdWIelK~MCgx1KmUK|X#k`xDThI^C?=_E=6@9foDTx%0HXhjO@yO2lanovn$% zka{MOa)EbwiHlJsi=7r61q%K3i~NNSl2?{C@cQ&W_>*Gt*qRPF2KE6G{~QE(YwuW1 zqt6~$g5=BWKZy1FZt+f(pw_O6q*m&SA!olRs2?O=o#U-eHNmcjq?@=*BoCqqy$^Ad zO`;K0zMH2eRP01ZWXl9^m}ni71g;~T+;qgp2Nue8ivYS7hcPTlGd7op7rhrKn!9Oi3u62B+zt&Iu!ykwI>dgp}yiUtQCWI5H=0 zJUCJP(^oT0mb|Ur$z77GB?Xd`xWO2S<^nJ67T0vnSCq(sp;v zupP4#%GaOXe2pjMltbt!N2kSj{*bV2VlDgN^U7qe{*^miCev{=g6?^uo;}_A^rBe% z#B`ir-7%LML0M7DAIZC_-AjAx6rkrzJZChB&aO{4^-mR!Qu+P0o#94{E;vG(W6)dt zid8T`bL8T==jWWhw~1RqDK(vibVHQpq81$VNvv3Q_I!Te-ufF38=Uv6R` zRurY%sJ+ac{XE~^KjQXX`XJWhJ$(H^kn*l;P1Z553x67+l;b3wDOSMvn-&qJ=bkF3 zf@JH}E3L-`@4qI@-&%2ha`AOq)?*0nfW?Ep!a4`@(=E?Lj?htjVVr+d<_z8nVnq=8 z$viGzKIIC{cwndvd7v;1w3BV`39#!=IIRka-ef;~^!ON+Y^R13UHo>%ntoyYjT!!@ z#YcD)q^tklskYwi+Fwj$E?{}089&tLZT8e&ZlGGDi@EC@8MLC!_nv&# zoh4cCym_D}3bItky76<-mwv*k1h&lJ#osT4Jznsr z+vWK^yWHA?gt+2@Jo{;lEH%CZH%Ua!u=YVFHSk45lgdp4J3$~;%YnCu6yL*y=c~Iq z7bnjjkRHZ056<%0sNP*G!}W|3NGda&cf&ATYnpY$FrJWUS68C!JGmB2E_I60vdfq# zpYvps6e{IiVFnZCZ<$Wt1e(f~CwA6DHMc)6UiCy`?k@TxyEr6N_i8Ht{u1pG?dZ{a zG1Oa_D)n|&GyV8UdMy5`*ycL*xD|pmWM}c?`sTb$vdaXv<(-S8I|rRA089 zxJ8>p0t`*+swHv#<44ZLOK{a~n}l~&JM_og;^iW6BZU9vB4{4iU=_k?Gkk zkp1a3WW^1C#)zZc%N69me>$NSKc&XdA{xhA#{Ovplba;Lo^FV#dMc4wuppK-(M`I{ z*9{x~E{GuWmbrEaxbGXb#CD@s$;|KDtzR;KP$sOINfYW>`k!d3Mz}Rf{XSx$9<^^E zQs+x#Dnd`oKqmhl+7h(afv%@Ale?MFVR@IZqe4BYbem-tP1!7_%sDRm7uz>N=(Oum zH&+zd$&7CX*)~0A4RtVYUj5d66=OZ-TqQevW6?%hkqP)JQFlh<1cQEX&-(ylAjm}l zL&Amc#Pi9#iXJ07k5|IstLTGm6#HuUFby?7n=C_Hu~eRC{ZDJiy#>KKK0Nw5`Klr% zPq*q1c5s$#9g1cY_-4CANV49eI)YsvJI7NCzKb_=D&Y8$eYFdQk-^64L!oTwVe5(C z^UxJF)6zeUS7JnkKxaCF6+ z4{5?Cg;Wx!Sg8b1X6v4L6o3c3o7nJv-;+15@b;UtHS8#2YaE_7o0i$?(Kk`J%R|Ha zfb!=-2BvMRlQ#H%;8iv08X@R!@;9Vq)1J+YC!nt2DFKR@YF}}a9Xt#E>wcsMkpyF= zhxXAMzW#t3ArITxBu{rFc-=zE_0CoFyHYUq_anDnw_^q$_0FJbNBA$6UTP z+q-XT@IIz)^bDWJLLk+l#fypnX+~gzZiGsa{T9&Zb3OKioo2fb96Fj z$>*zTGr0eqptuzL3;ebQ^gwzUH`7qMRS9o}~K4hhcVncQ@l@zAXrT)v|D`5W~B(klag% zi_y-Yor~$@G^UC#FGxbCqTwbhHEgiXdbW^}lA=*yox1@ABL9}7?Ho8v8Mj{-FH zcc&1Xf+57c3Sn4O9g(q|?^x_xzioS^s2Mta86?q-r1rM%{y?Ib;8&7)MV}vJa}Y9p zb)OXnw@c9XRAUNI&J-*^PvcS0M@uT^38v>|`)!gfhgoxzTJ9uMU@JhP_aIzQsgGsT ze<2ij>fV$Z7h8`gX)m-vLTCurg(ez%W3CEeD{8+3i^h$!?LMtVf|tdcW3;{zM^srQ zD#anR;vr@HhHKQ;r(A1pj@v?>34C2Ad^a%#-*FV*=h+WeAoP4NW#sP6@(#|s5vZVG zh}Q(s7>VpZeZF>j#87aQgA1#%6`jl}7RXf>6}ml}&kJ)P9rgyBh)}3 z;Ysc8?#Gq*5(Q&HB}{k9p^P;mqo2%cAehKh_1wQ(2Nond&uFnc2JXR^e{PdWMx7h- zm7JkCD*DI4#DoqLIxKCb5#)syoC8ntTqYT<&V^FY;54=MMYVKa=du!mAeg8`cg~(+ zD(4#JNeg8>h)(*>qzyqqdPBYmx96!82@NAZEm;j7)32JO_29w_;Q8{ze;zfKp931Ux&TvrznNJl z%tx%VgPeA=T`PocHa8uu`3Tc-+iCiwD>omhnhsQAWC{PWuY1x0zAA+Oq^Ua*BqqZV z^Nt1oH9h~TQUE}y9{XbPgE53~-q$GXx&F{I?J}LNl~d4=&(~DtB9jwdqCpQJn#`O( zQJO~{rV*?VE<8Hf{T+KuqpU04hy!LOW@|+_qN`mqU^OV7QLX(q5k603ouxv2CMJ;x zA)%&f%jQdFYiutE(@QYg2_qZS!pc=YhbwA}O^36kRr&Jg(jFxN>lN=s35yx< z*gH!N} zf?06D5c2JFurQ3gri#yoAi)_d z`z{VS$<+KV;`eLaxipHnoQlv1rRwJmDw(Q9Cmhn>Zd4R69^-O+bCX`{Y2E0oMA@OD zQ~6!t-fIv~X_v<}YytF^b0=y&ZWqofiAjwn9&3^rSK9IR z48v(B9Mhjx_}IFG4uq$SS@cJGK_uBDN74lUUkf08q@_{v_ed-zqra~|cs1w5aE3i@1UDiPL8;40Vc{=pW3ro1~pugBQIy}=)n zVV z_4oE^@7LH^sKT#5%@^p$Xb$=%EpiuPpC$B5cqmt+-LFY|{_V74=b+SGQ-;3hbtdj)ns&F?cI7)U$VRiQe*N-uTQ;|IeBh%6ztFeA z*J_c;b-%nu=>`#RPs6jDViki{!f`vcxF=ZWaqKp4Te023hxQvCEIS8n?DcGrvc)rg zpv0iJMO83V)NFHRu&fOZM8dNj3?w22Th~N&UiSU6W+n*6rnZ$h0ZVe&B(Pr) zb9J)YAYka=HTh&wA@ALf3=2GDKm-gVlz-eWSXUnMD0j5}0Zw@kW=6gh3q3lXAgs*7FrrtKobvNY@c(;*8$-tQBZy`SerS1Cefs^EkG383C+@H9vp#u&suvXl~!PrpH z4B7GRpb+mwg5tJ={mmh_KprRJMy_O+IfC}juQW*H5-IKFmilj%EuYRluunmxT)x{w*d6trTbXB9U~4Z9ccVsTA@p*3 zxyA|&+I1XnJ)KqB?+zyoVBkRP`Nw$;Zr|j3Ma6=5hvRffXusGPg1Uru_1g5w1%t2T zp$$Ty12ww3DyH5Uq*2D+RN%UZ?5-}EZimyHUVr;&BflX!i=im)xJeIMK?NpBGWJ^T zzOz#SFG;xH$-sie)iBA#h32$OrMLpesx6`41Hz89W-10zkpt~t-M|%lCm!>bG0Yq4 za5Bw;+lpval0=c=u`91|yW3cI38l-(J;y3hHL6}o!4IyUYqb)WR_$Y%Ui`ms!&Z<< zGX#Sm5oeZrJ7k$Pq!tN|g8g1u!**+&6WRcWmH zg0%Fg1o@v(2m(FGP5H*e-QXGKUb+S2$mA#N$hqN0QHf&N;9iphNa&O1odcvIF#`+| z+j8*(45=E0m8D=vx$7H6TeMbDd)b&4-ERBP;W|RL3=G3B`H2@_@I$8To|Pk&He*R6 z1+W8a7g2LB#!#P6r2;MTLujsDnA*tU>M@7s8A&YcXwhV_^7IOuQ9r5$vK;zPxvrzI z8>m9F-9M}iU#TXykOwXzOX8RqSXJdC-%RaB(}>PYKcMJ-@DXOF5|UTZ$;2U%&bUD( zutG%Tt+{f#h#}}XtHUuuVNZOm$L;;s3M;Z?eFV8~@k)fFJ!piBW4^;Jsz#&>9Ex}+ z?byS3SOyPFW_}qUCJSs4veZS%Yo-+y)p)S5+m(7uB)6b@7uBX%Ol)nf!tEi9QosnP znTe1@a<*}hynOl|wq;i;YR}xwbfc)3YDEE;hDmo@4t0)#z?MW7I5~f4d8|K#+VE+3 zPM4yFv{sUtVJU~$oF6f8_=WPJisgoyTI{GB<5p@GIw1Bm*uMLA9Ax%Qlw%ugR=MDXF9T5t;2cm-A)`2e@2%^F?db5V3fLrz`Cfj?e6+zKKLk-mTb}K4? zGdi4pSh+$q4kbZm-&RBjw+O65C`V;~c#zODOI0K9@Jcv6^7_@!53Ny+8-P%4c^)ST zjt%iiJrNYM*H0j$$e5w(5zba7sbIZBA`Zl~gN2T=BA=((R$N#JHs=rcYdVzq{5=Zp zqRE$?7%K3E+y<3>`kvkE77MORi4hLZ!&~P=2)Q_4Fgd@P1JVkf!2Ty!_28H~UVC!n z$?t(aYS)`XH`$z^I%s!D2 zL+YD*?p3Jtodmy?@5dCl-QrfPa%Je11+OPjW!l$()7lBI6&A5&R;wRwUlh-sUt45X z^riM6L2h4}M;NiikR*qr0S;-!K^a2I9kAJGT-)x4l~>m~qx9J!ff8#hEpl;v_Plo- zk`y(%$pj{LiwL|{yAAQ0X)`A(+I);2heMT+NKRG0EUBaVvQG!O!Pe^J4^il%dt&=t zqd6=eGrMMD_*z401)D7%E%GJ7!AKc6+=IIQrd z4JNDvNpAJ}xmT;7UaTIO5|OKMyrTH^*%4@BxT0Pk+>E3JFx;*7;tYqn-7;Ra0uz00 zVBaEsdJPL~sLvO$=WYHM8BFgdT~-*Xc+*;VL5YLu18<%k7IOvsUFw_s`T}T$%U_My~lVFt3x-xzoB-&~bgv-5-Atyx5gLl?2sC-nIMVWCq zrK3W5uHsC&exw|)6SFrL42d<#56FTG2p3c*=q7eifrQo){YAf<`XeQRKiMX}}XMI|Zf6WfWJ#sghNSO$bhECY|8+ zqd@1r-n{t2zh|)AUX{7>oYQ0f_G)j^X=!O#*f}^DnrmvPr|(>oWWTX6Gb;<7xU4hb z;^Gd_CY^X&8Wb+WOE=fnC=Z#kcD{PIQPVIaVU6swy1G7uQy6|InYWy?Y!n9$eZ7#8 zkzr9OpGWssXym{3OqIWH%8wd1DgHGyGRnrv!O_34(A03UiGYZRq)wakZ)HV?>CmT9 zM?q9H0DcNS*WS8vs!)bSqfC7wdm>|am$JBGwLWAng8&8@_j<`Zsnh3`m&u=THJ&!z?dzM+epZzHCvIj& zwd?hM6;`lofcWn0avNvl_L^&PC`>MSh>^bFd;Oq>=hvSt>-`(6ol%);J0C6Qv9z8YnQoo#45>ioCzMMMbalfXBz-BUkdwIgZ!deg+B@#+> zogOhaGgDE`o7K^>Vl?O)%M$P;dggZrwwKiJOuOiQ&suMHUHtFRy~09{`yVng@bK`+ zLd6<2*2}D_YF6j8s!{cz$vVTHPyaQNSI=5Vl~f{E{rcu$JW(L0tcn%>=TG|g8zrCh zCZr(MW*Xbmg-Q%;Y@yr64-*+YV&dZeI$b+pA@}FI*}iY2(LNFB}Yk^-v+*fo2cX|Z%>E34`ESJ z`#?*5j;u6d)6?bLpZZ$K%*@RlpKpH_$*1Ki|oySqMs!pA%X0jMJ^S+wX@Uv!>&^zThRL? z$E>ZDfJjl@c%7d6Yc`+MW-?KivZsqa5pYA9oamIyFXLRlzzK12JqEt7cTi6TxI`^`qOCt=o1rxHtmQ zPBBBfda)F#+y(q^V;v}ow)G>nV~&v&OEpkZL*v$K`Fy!e5>Pf1PP zzPN~KZRPo}yu3WL?Qm(`}<4F%iAX>z{aG|JUl#!$;rE0TYlZ$ zLYQxK+uPf2Zf+>V#7efdj9pz_EiEla*1vTsDf#&`#>V8WZEWBX5YQl8yu4|^pChBA zwav|go14U?>ardlyg+3IT8u_S6y4nH+PR+pe!dn~9Rgb&Lu_ETSilDh-?Yn6M_Yk5DZQjrcdp_=N1q6#-BC zrg{_M!wCXG*XW35TNPE!;Np5Vr3Y|S(m~usSJ;y?uVKQ9 znaGD1P=^-aLq%OxN&}{+gs4&TS-}>X9`+jc=co-VfKfb+spW)b~aqQmCmy1(NKCJ-ZQ$H>U&za+G>k^^EN_A9|wVX}Vj z$Vm9*rM+S%Z%|?3H(OiVe**((xVXbZapdKVe8ASy-jMt0A_aU5gwJ$9WxU=S=H}yb zx;aqT+1aUSZl+>mOMrs?%ItI?KQ=xtBPS=un2e5&{=2^3sS}?7pSVWz&mmYFSIX)wA0`3p4k_}qRdpk3FN2+;!k{XeROeCZJ(chmUBOB2=| zLtLCw5}I|sI$N*DC!CV*O28*6D+zN@RCH^x7(LO`Ti^&TxQUU3}1+TZ)*4Ouqjz$CqLIbT#5%l(GbQQi}t5UkLKx;$kwekv0%N_Rh`)K-t2i(`5cRL%}Z~Fg!LUo~s;+7$8Mi zP+)F$br+6_k(@a7bA{a$1|~zdH9niuW~X>OorZ}?iZX%4{nAj-2h8)~&-)XV78%*l z#OUr`5*_!-O5NG(Lw}E2YGek%hF(X?DGLiwVxL{XW3JVm!DD~@Fjt#zUeh?JHE4nJ zMjkK5v@&(e12I6%s3$A)lP0rBVYie~?@=@)tx_t6C_~6M3wX@NMn?XrskjJ10bSmZ zor42OcXuAh!^Pp{cHb9bL4qV%2}eg(A0MAcVxg>;7cWk`jmY9+DuuER`FtRiew|<> zP%8A!%*0PkDL2_|PSj5dM#xj_OtS!;%9D?ymJsFx+JWt4aq9}qe}eykA^^0;h&I=w&J-l{YEK>vQqWc%;mRI!Pa zE+K&%Xqv3fcGDbq;`0;l120c|*qAI8QpmOg1FV+RvSCUJ-)e#}XAl!0PAv3)hy}CAZ1K4|=yro$Kj##vi>Nrj zLt^wPhYV711a!}r+waLuVN}Dz<$gZQwd-~fNu^`0EI!_bD0sbYKtBuOR`5(jZ!QoP zK+yfaoNoFXz4Cof)+rJ$qyHVYjzlCpqr1?llq=kc_!yCXD=ai!?@|Do{Ks5$ zYRo_?8s%vBcYY;9Ix>Nwt2A7B_v0tOi^YmuX~yCUbR|PG+lhur!QDkxE)oljk&xrTkgNdJH?mLwN%ZEIt7*b%2dg9kJ@{r9>+ zASeJOQaTT0f-4*FO9n@8Tx~52@F>lI;^2HT7p9oDS*A`4s3J;M)_9;cP6KH%k;zv) zU-V2OKo#QHnC3PvmoHzsr>RSDRay#+JAtCD8N=CLz1J~S{yt)w1=mf zs^-90b=OV^*Tz<9m7dHnkZtN{*=gaK2j6}q9gL?tUGK^8Iv)w=Ncw$pQ)EjnSEudh z>|E|}uU`-#5cJ{}6cjxnV`F0jw62aBrVa34U}DIH{>A>a_+$6@CK> z;(r~1YS-BxhDrBf+r2v-8CAI5{&ot$QQAKqRexSZB0OWg+t2Z6!CJEx~|%E~ArBE6p! z7?ai1)y3W1xU;gd8tgW+_V!FGIp;B5F;z3p&)uzNDDFdouOWl32z2+}JMffW@d7&= zIgWXFzGQGj_yEtl)lBXh0kIVivmd!0RDW_a`5iDO)$f;3#afkRE^mun?^$n|eD%)} zOw?-BDKEoR)@$9_G{0eQOjnz}oK8bg@$uE&T;p61;NOC${5J^sSUr28qxD<3}9JpCDdPogIPO3N?oZOh<-15WF8GxgMQ!ZL*-;hmnLI0-`3%e4sz7Z09WubjLFC1!r8EJu@$9OxhP{YD~Tl_X(^CDV0evSOU`FzVHMX`9q`MlbWe2tIWIex2(Y7y$6K`zw%8a`Gm|kaP6wgA ze1Bh->yIIUvH2r_!AjzDQAbz3&lHRjE!`{T5ygC9d3~NXIgn@E=#UA?A@O$_ z>UQ6bDAM2ljVvIHRCF{Y0Rg}5;P9US2HUKD+5%RUMicvrlf~uGG8Omj4F~FW$yeX6 zJmGXdcfaqRYU!gw7JCMQi5IIu*6(l5R_kfDl|R&qlw-3J#H?izLMF2IfqIb2@5bCN zCfcy#ECkpgC*Wpm*IGorf5$BWV?3yo}T z6&)OEEx;d*NL5%CA|oS#GDX72_d`xvrBuD3xVYZ;-KUlq@GJjzS=rbCkmM^ZBhxcB z76}j{z=f6AfoTh*zoE%10MUnI2(0MGn<{`GWYXUQ!n(lJ9HBfk5rfyt5eDd2otJmS ze95czG7XA?!Z1Rl0IdDnMk{$d_R!41pn!C6bo7743P|bQi+zcqLb-}{fSOg%%Z`o! z;a^&-@E`_Mm(^xFDsFBZKpYYf5J-1K>;jV+t%{QmfT+Mg2wK=&X|jm`WH>3Qf8~#6 zGz^TuhzP{!=x9JY&Xr}}_3uRCFFRi57zR5!0})|S85u>lO#S2eIh?L)1(oadQp$vU+(6(|HyQ-Cg)`i@y80Mdbl<;RcOv2|{eLaMIU>%;mz4G+ zaMOFd>Srvhm1AfMv{>nH^v_$`dJ6Eo<^ z0*R9~F|l`Wh<XD5MfLfQg6Qq(cu#Z z`goudSO!`c&+-bHt#WrFLqjX;)TRZ-U}i3k!kQLsIcb^6;T~by`4dwEWMnV)@|@#r zZ%Ij8#$DJiIX3m?{|XC~SJgvROVvk9@6VR&0b-B<$Q&qp06n%N&;S6J_k0N`g@Eim zz18Az1rq?2Hy6;^emRZs$kjIY2W`2I*%>X)VVHa_HBQ^2X)SG^P%dw0If#BxC!eaL zr{myG_bw(2`99{ZY%&Ig)Elnzx-jWSW*1X^u(3LBvHEE%>f=vP2rR{oE+{%=&5^SD zVg^I4u}@KCy1ieu>iHsRiUwe@2AkYWnN4BZ{jdd}GhS!^2hjS{Iw}i|_V<+dv@E%9 za3wQqyo!DmB?||lNq+EfwPx#P6Cv+Ez$G;?Y5PTV3IsXw_>fD^xmg=Iuy7`^qhhAu z;Iq}pVXGvlrV3Cg)!k+LE_E4x1S=|jXqlUF08F4ZUA$th@_!J@(2xWO(?V7E#n>HS ztfoK?l{~1{qw6YgR#DcC^iFb-qd=37jQajE!N(gE(~Qkn;F->8 zoyvs_DB!xvAFa7p@NEW>QBjR#jsQ2ZcX7coP<53{P}bLoGde?P^3QMB<$BYw621G*QSDJW`hWU^qibXT0y#f^ zw4P;=$^vBRL-(8U`=rorDT_f7;eHUJDCJNx_ntxktW)zes|^OiF+GxooJVOFbL>5mT&mo|sCj;yIk$Km2w zEDxd0&H@mawwBK|obKX%wX1VrSFOH|nw}9WC@EgGpQj@Q@RD0m~| zLT@OUe>e%b?ccj)e^*vA0OJ+_?u<=M1Cx?4fxCKqdWuU=9|c@|!#%){*4lm{dU|>S zz7-h$rhZO>fqIh8Y12C}00S^EM@Ps1oc(|P7Jwgs2?mCe;mOHEfD|;^y6PF)7>Rfk z!c%ey5&w{r>tN>``QhM@s0shM8s%utk^?}y141ynjQl#?|pA1#hmfyo4PZx-~K8Q{J!u&_;RjmZ#1 zxQvadEA|PF0d5UMZ}`LnD>H@bWLYeRro(6!@FZZin)v9LI&FA@GB;ifMj*;sBF@n?D@VUlF zJ0;Ds^tFD%H;%FV|B6hS2!+`Hq{Hcc#uvu2P&wA)T|5D`a`( zKbkh}bYM@%_!U5DUG8@p2h~5M9uBhy=a#f1PfErPN0aL<4;2C9WnWWkG``k4e}Cod zV!m-&&30Ztd3keNAZ`-;?$!Qu?$T{?-;7sTBBZyJLn40Zx z|8OwVCgEhxhRyHG*u-k1^~g(1F-mgcFfy^i^tIOa&LfUA3urt8JM3ud zw@9n)umaG=!Tj-WI0O`ew~cI$c)@j@_&@IHUn>IzRcV9Zd8z*4UHdDn{5O=qYIE^J1k;X%)o6@e*YIe*)J?CJ!SvW_ zdc&D@hP6#&U}DOiX`3K~9^keAP51cTTUT~#UG_&XU5~hKUj3UZWq0`XjbAWJ9{{{O z+$qUf?!n85SeL8WzVY#?Vd?qg8+Z)IuQLF9`42dbj`j@?!_(2xnUAMQsH&oAYHI#R zG*ylzzA{_RQ3G>3fOYHX@0Vcz@fjA@>WKgehuIHcH*u+{Ve*uH^Ya?)hn>$S3_K8%+YBCE1mwZV*@P#+_Pgy$@+xG8=K`R(o=rmz z)~nI@bN9;?Y%?Ol<=yT7S~~A|D*yM7H&G}u3Pmz9vXvQytjJc5m63If>^&07PUf+) z%Q*Jl5t-SJ?PHH)WMq%ub-s_Ezj++zeZTMPx?Zo>^L^jOu&-W=6hNLqIPH~y()aX- zMPYjP&UkTgyP-#Xsr`x7`_i(^fl~9hJ5)1fNNudEDqHmSgnduM*RQ@X{WdlEUc8J) zLQXDaYs&*ZMcRc&oTak0WgV`NO26aWkXqhTfeCQ`@c50dPluh0?7ScYIGR4^Fc}7F5Qf%Er zYe#sU;P1BK_J2R`$Y$oDL}Cw-7`xr3t9T9@T?u3lgV-CHIXU;43SHoqPM7zJ4I&ZL z#mPYI-$A_Psk)kBXF58%B#T#IN3{U2^|qNHpKGir!T-G6L%Zwh-&9dO#kuINYA!&SI9{T}_*WM>R}L4oqXluj+5E za%DUdw<1nXO$~A4aJ;SIl@@C4USEac={}_m}eju%dkNR}h6x zaLBK|VM=`^rCS62+}XRu`g>=`Bk*b|Lt`m5MRlsiUfQRnrEFXw)GdDBlOM40kV>M6 zyp@zxXxtnQ?ee9i4UNp@Qo_SYDAGtjd&ToD)qAKZC@PlST>*0vT)0_hU3LKswO)=! z1*X&jguuZn!9bo_Pr9|@B=A#P4THHfyG$V#UznPFa=)f>l0SkbNxJ)M?fPT^Z=SA?ZGsn`hci382uzVuoqy0ZclD(qlYoGu5ab>jrX*&v4YBomB zfFg>PrlDS*g9qZXZ|1IpK1JkOzkK-;ZT2n4)4ZEbBVe}l$+OLj`} zWm8?|OEok(g6en&!z1KVp?v9-*hdTk~PkzZ(}(@eyix|g;gXZ988UG&4ufPhqd-k+y%k19UR1s5&gcS z=Y3l5M~PC^HUjH%m4?FkO&Mr57F;?8tgRBpnt|_-x z#0)={5yN@2n`}awns1HGeo!zmM$5+Wx^S!UlQKn{)7|;;&oECR+-ZF|wVk3@7KRW+ ze|djL>qwidgBhMwg4w$hhaVk^A)&VD*cUkp<;_zWxIXx2n?Igu>hDs(qJA_&H|0ccO#JS^{FsQT zZWcnK)9IV9Z$e&v{I>pAbHNpOi9{lBsFZ+{iOF3PmMH zxm-=O!}Wx4cFL@*D;m@y0lcW;gWe%=Jz>570(iB`WYu8D>EHAHn5rP1AP=9SRLwte z^QFJ^x$VMM&iyyxZxD#>_!~c08=5{RKQ-42AH9bS9)3PmdSlyq*@XX2Bpz{7U62xH z?wR6P`1vKch9Luj%wpEN-U{Qow-snb-z*tEn}&4BmC>ZN`SQl!_7wM2m%gd)Y(j4$;rZxV}PwwLfV-<-Zsm&r*Fv!(n8l%`IGnLb~)M$@V$Fz^}(A}b%tp%6U+R&WUX zO8Fsiq0JGt^Hhm&EJ{;dMi$g*a`3M=$bwfOp0EAehR$=aSFvvvgr|7H*lVlf*x>WG z=SShWFHTM{1a(fK>oVc14%RlZ>TDD=0@jQ<^2sp}utmnk$^f21{o~!y&%~DCmB}K8 zkJV0A%UNcm)YJ$LM==5~8L%`CUkk}%Vvs5-9>)#mMKjm}nrc>rF_1E^A~iF3V`5@L zC4xAk*eD>^GV1xtREnIcO-)b>1=i$q;2#h!vhwn7^ViaMNeR`|5E|Ech6Li>go;eN zWsDc+`PN1^E0bRT%HEkdccpI`?vUq7%1}xcl~Y$IhnN$RuS7}?1ca7g@tfib(FemX>$Y82GB{-`d#pKoZ98 zh52o(`A{M#r#7)^cJ??w6WmFHb|3y#ZAnxJ|2?XAgbQ{d#Kg!)58g1w8ac!^U?^Va z>s<5`+|9^f1U@PcBO!0-CVZ^)jdEwe=gXn9k}N@wd3h4(C=lYRIm+CC0aTky=qTye z1*v8>{q7ExT>3-0JSTbF`0Px~DP%{$#t;f_?0;{M99R8{A|f>FZ-8r+u(!EnVa%9+ z0bAJP;9rY!rIC61nlkl=zw_> z%SW#n7|MbOrI{JuZw+(Uj&B9u7V_A*tC}74-F=_3x$$PQ(8rIV#F~qXxEUJ6-+`;! z_U}|lo#3FR)+S$Cm|-9^fG^I2HWp@8V|i2KE)WqIcu)y_xs7CN)0rM!s$~|NAyVE?>&K z<7dE$^im3hU7NUZ_l6+6>E*}{g1nY0AjPSX{c8FkAnT7ZwZ_9)}cp#RH{&Yh{ zS=}$ZMkL*BzZE)Hru>VA8ZV{?zK}+xX5@u@uXdscCd*oyFWjG(t1h$d&bo{bLfixZ zsDHF5oW2Gq;Q90CU`Rc&8vFGRi=h&H{~v?gA5EIC{R5+~--Rj2D=mF1F-7IK^U~TK z^47dce3q@s16Pn|sTVW?kav~Bg74=~TybfH826WM{2RFS?NU%!?$4o+O!l}10wgm! zS=V2+9i&AiHC13uIzvzB-N28`&h7PT-`^LP%)!-xP|$33;}6snafL=a2sH)-o)o)g{J9~=>yKzF1 zAm=aO{CJhk`p%&B@f99>W;OBCsPU^;6%PJNB9!8uVXu)b^Vny-QO{lf6*zki?!=wL zy>SQkJuO5iU61?An3Ud(S9%T3Tt?I0-{k1L6@rV5%!NG!wQtbog}YxSSn(?%VImwI-7_K5RAHxzPQxL(xW?onrW71HC>=x=mD#dtKB5Z@Oi6wlY^(wi&WY%pEg znscxi{hBvk(IQ_>fk`~*let^>{sVJjocPI?-a>9@`lOT;Eo~Lk zl##yZ(Yl19&4!+Zzwbp86A!$)sgte}VSR(BIjeK-&IU7( z2_Jk_NVtjI)*p97$p`E&KZo={?Xd=$FgW>stMg<=0f1dolgKmq#Z5JxENrA8883{kDV_DRyT zXL}>~KGdNUPK~-6a$R!i% z9}4Q({zL!>(&Tqjd>)}rz8)`N3fU222kEH{v=y|kUp+&)ud)B!ZZ_%076tH9T^4pW znVhOKOo~C{-|QC>yn`ep)Z7?(4w-RkuBL&pSzFfWv8zq{EvJ(M1~7%~F$Dwk++V&; zdEO>7G6D~U7*;3WW)e4Tz>3&1CF!d(z6!D7(vgLv3}=(pmPT#Sc{B#y6LEoP8f-WQ zW+4>QW^MBrSHpZy^C#5t@uuP7T6LC0Fix6_ii#GNlrTJe`04X!0>mJ%;(2=0uaP)N z;ED{U#m4xN0nj4gelOfE>A3(ex7oBjTBPAQj8e@sY_9j*#SUI0x&HKQ`r)_Fo;!oc z0-k(tZ`;QO>}!vC=|6l-P1TvIB!%!;`rnEqd_|i5b)&4TFEcoq8NfVOkQ7Zpv!}67 zll?Mr4eh$WFcZZZby6e}RVTw4k?fi;iZ@!?_CL}k%6|@N_}3F zxmov++4C6NM!J@l=i)TNZF?7M*cU+DmCXHtDjwo~C#TvHvj{EpdEBYsABBy#@sD1AvxxqGdW>GO(I%j8|I=*M@-rh~@iXqWS zY3pconT600zGh680`1U8s=1@T9fKb(=v0x07t62HdE#_4&;fL?3{XN>?%oZli6jF^ z5&#zN<$stKFYP+y?Fx1c%DwEUTXcR3eLdYtoxP(ahbI-&xTw*o?z7(&gjs+2$G4Hz z3!7XPQWrTK?LGIjU+}ku(g>91l*dFzM|}CB%!SD#ga8IgL!9`Hd$*R_SmTAZ0Z;)( z(x@>{izx1KFu=?KU}p-sx*~qR?u9}I8K3!6gG*{+hklTye@4uANHH?@rm40ry%iUS z7T;3O^F_Yp_7ABCKmT;(O#Rk=$Ck*8&dd8H{PIY8L1-IV|CXI?>WhIaI}_gKS**Zy>5%U!2rh&}C*` zKbxSr{%kx(tc}P*|KP7mU#=uh&d|qlmDrwpnJ6U^5bR?b8+{_#Ur)V0W$@85`ppZl z=N~`+EldOhQPR_d&giaN_cNL?LpGGey*888jtrcfVIXma^Ry&`DLKHqUYrFJ(PAhE zfxh*>?e^$RMOciNR~r%0uWd3ge?=#21fWWJlo|0l#67os#32MnEtX>oEwP$lmbz5P zcXPeu;|pTf=;3(8+1l1yD1GiP!!wny-vDn7xCDkYP~G$qvN%7#AD@N)h{bF;;~Kc{ z#XASKPD${b2z(9&MdVW%G58!M$Mud(?TQiSBmVR$&sai@uF;sqMRM}nNGo<0wx*nm z)AT?euVow8Kjz`-t6`}=c5}-jqU}1Wa~~~q<^ukclONv`|;%D}=>;ak|f!|jDw z*!5-nT=&V-y1Kd-5>2i~ynfRL1(v3?Rn^J*qCVGX>&f&PGc*0iWL-qzE_RiR&{Kjf zg4?|Je!X7RS1>^Pw0b7n17QF=DR#`QwDD4jaA|NXTAG)Gl743bO{3qieZ695hZUV> zy9Rc8OM*b)keL>s7J{}bwFTOTd7`Szo1s?dgRa=hF#rDM*qC7S&;!L@7joSZjoY;2en z<1;j*l<82s#sr<^)(Zeqge;Gek??;4|JU?vtSpT(H>EO;VW|h!5Tx+~KJFAGcDNSc zBGv5D_`lPTOY_>>UmL0wz%h=SFdVJ)rY3t$)ZJppEgx3e;II4|WM$uo7s2Y|yOL$00gV)Tnj%Cqb{V{m0hTUi+` zo233=rbQ*)#dJnOERpBqTCHe|)nv!EOk%KPrYg8tfQNJZlKptS+7T-ap4Qa(pHGgP ze{d5Z7$IfXyE$BT6ivDlWInY=+Lo3vF|!6PNr%n1Q|l=poz`d9{Ry}BcNyt9Ld_*V z&0=SM{)@X~O9vAeCCs2bUS~q}w6rk2;s9MYfyN7Wry4F#3Qq;j!alMst!NsNJ-7S2 zY}nNJp-UfL=+3M}sV}S==r=8P@&#=EBI`{(NR|Q>UoD=Re#=a6)z4#_Mk88eUdGNY z%;HE=x~Ka(kGo?4BmdTw*xoBJ)i~W5+~#)$%Eu24hjo>HAhZ$XmU0jbwY0S04sOiO z`liw@D&>SgXcnmSv<3FR`C-KF%1A`4Ot=ZO0~bM|h=_#XOcYhkZLVS0?fDQYU{KZaHL(+$Du1^-xq`Du0H6liWy(S+N0mn= zY-9X&CsE0N-2ylj10u=?fI4WeUDP7wt%qv`3^H*gE<97#)_~z`uZ|Rf^-pnc{COOM zcRb&x|2NOU^6m0CTB)JLqPZYC%G5}$z2vzjpex*H&^R6FzGrsG1bh68Z`uPMzcOEt zaX2OitViHRsd}sUaFqux%Z;R`omgrQ2$nQ9o=JT z=>Y^|fDAz*ReA7<=H7Tpmg2N19GOFy3vE)iCMCtnNWZ#~%*mNXqNa)nqArzCzXcPZc5WV8?5Hd|q> ze<~4Y#;0#j*a<0qOV~WRY$Dz`gZ#GI|86#itG+k>9?l?r{A764CR-Q<3{E{UkDu4-sKFd2giDD&ZiIRs&Ys>w}+!13v$*BA9 zQPs%l_D+v@ETp`im%0iTQeQngf{L4=mbqG7y@6b4V9LleFfd`(jOKiu%gVx*6H}e4 zkVBD_JVmXiMr zZ3-5eodw1e5D**{p_a9kM_SNXDaj`$~N%Gl|S z>4w&M{pcQOU~x|zek`YGqX4N3zC=jCH9%(~-c~cy@S#N)??YW#S&TTzppJVx7$v{i zuHGTe=(ixt3oI)7<3Xf>kIwI344wG7%2{uku%tt)G|f3h~+MhcgALKtn_=I#^mmC5FnCrdXyCF4MHdG z5vmQ;{7H>2;^(U=IL^arnPr$*c)VN_ag^uM5O-z(1+hFnRaKSr_}f5Hz{aD=7PD%TcxFsXxOqoN>oi;_yXq+ZI~L3hW4&U$uFGB5ervR(Xb(9?`cC4&-YT9k|U4S3C M7q6u9CEoh}A6o_^^#A|> literal 0 HcmV?d00001 diff --git a/bip-0360/merkletree.svg b/bip-0360/merkletree.svg new file mode 100644 index 0000000000..a3dcb37937 --- /dev/null +++ b/bip-0360/merkletree.svg @@ -0,0 +1,1874 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + P2QRH Witness (input) + + + + + + + + + + + + annex + 50 + + + + Control byte + Script + tapleaf B + Initial stack + + + + + Merkle path (32*m bytes) + Control block + Witness Program + SegWit version 3 + tapleaf version + + tapleaf version + 1 + { + { + P2QRH scriptPubkey (output) + How the tapleaf Merkle Root is computed: + + + OP_PUSHNUM3 + tapleaf Merkle root + + tapleaf Merkle root + + tagged_hashQuantumRoot + + tagged_hash Tapleaf + + tagged_hash TapBranch + + tagged_hash TapBranch + + tagged_hash TapBranch + + tagged_hash TapBranch + + + + + + tapleaf + A + + tapleaf version + + + + + tapleaf + B + + tapleaf version + + + + + tapleaf + C + + tapleaf version + + + + + tapleaf + D + + tapleaf version + + + + + tapleaf + E + + + + + + + + + + + + + tagged_hash Tapleaf + + + tagged_hash Tapleaf + + + tagged_hash Tapleaf + + + + + tagged_hash Tapleaf + + + + + From 4c5e836a1ebe6b0cfb61251ec18f0a308c58ff3f Mon Sep 17 00:00:00 2001 From: Hunter Beast Date: Mon, 7 Jul 2025 09:28:32 -0600 Subject: [PATCH 067/131] Update changelog and acknowledgements with the new developments in BIP-360. (#24) --- bip-0360.mediawiki | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki index 66a28a08f4..58a3bb971e 100644 --- a/bip-0360.mediawiki +++ b/bip-0360.mediawiki @@ -703,6 +703,7 @@ or P2QRH could be used here as it does not have a key-spend path and thus is not To help implementors understand updates to this BIP, we keep a list of substantial changes. +* 2025-07-07 - P2QRH is now a P2TR with the vulnerable key-spend path disabled. Number of PQ signature algorithms supported reduced from three to two. PQ signature algorithm support is now added via opcodes or tapleaf version. * 2025-03-18 - Correct inconsistencies in commitment and attestation structure. Switch from merkle tree commitment to sorted vector hash commitment. Update descriptor format. * 2025-03-12 - Add verification times for each algorithm. 256 -> 128 (NIST V -> NIST I). Add key type bitmask. Clarify multisig semantics. * 2025-02-23 - More points of clarification from review. Update dead link. @@ -722,6 +723,8 @@ This document is inspired by [https://github.com/bitcoin/bips/blob/master/bip-03 the design of the P2TR (Taproot) output type using Schnorr signatures. Much gratitude to my co-founder, Kyle Crews for proofreading and editing, to David Croisant, who suggested the name -"QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. Thank you as +"QuBit", and Guy Swann for pointing out the earlier name for the attestation, "quitness", was imperfect. The +attestation was later discarded when Ethan Heilman joined as co-author, whom I'm incredibly grateful to for +transforming this BIP into something far more congruent with existing Bitcoin design. Thank you as well to those who took the time to review and contribute, including Jeff Bride, Adam Borcany, Antoine Riard, Pierre-Luc -Dallaire-Demers, Mark Erhardt, Joey Yandle, Jon Atack, Jameson Lopp, Murchandamus, and Vojtěch Strnad. +Dallaire-Demers, Mark Erhardt, Joey Yandle, Jon Atack, Armin Sabouri, Jameson Lopp, Murchandamus, and Vojtěch Strnad. From f0123ea9dd5c8bc5f62a4c78ed0d3706dce24bb7 Mon Sep 17 00:00:00 2001 From: jbride Date: Mon, 7 Jul 2025 19:04:01 -0600 Subject: [PATCH 068/131] Small typo fix to p2qrh related documentation. --- .../rust/docs/stack_element_size_performance_tests.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc b/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc index d7c2dd40be..99383853be 100644 --- a/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc +++ b/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc @@ -297,7 +297,7 @@ $ cmake -B build \ $ cmake --build build -j$(nproc) ----- -. Check that ASan is statically linked to the _bench_bitcoin_ exeutable: +. Check that ASan is statically linked to the _bench_bitcoin_ executable: + ----- $ nm build/bin/bench_bitcoin | grep asan | more From c10cd6c04053041043a2dcd86efd81aa790e8995 Mon Sep 17 00:00:00 2001 From: jbride Date: Mon, 7 Jul 2025 19:06:27 -0600 Subject: [PATCH 069/131] p2qrh: add test vector and reference code to bip0360 --- bip-0360.mediawiki | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bip-0360.mediawiki b/bip-0360.mediawiki index 58a3bb971e..ea77de9a17 100644 --- a/bip-0360.mediawiki +++ b/bip-0360.mediawiki @@ -643,7 +643,16 @@ security level V provides 256-bit security. == Test Vectors and Reference Code == -TBD +Test vector data for creation of P2QRH UTXOs can be found [[bip-0360/ref-impl/rust/tests/data/p2qrh_construction.json|here]]. +Rust code that executes on this test vector data is found [[bip-0360/ref-impl/rust/tests/p2qrh_construction.rs|here]]. + +These test vectors build off of the test vectors for BIP341 (Taproot). +One important distinction is that the P2QRH test vectors do not include keypath spend scenarios. + +Also included are test vectors for [[bip-0360/ref-impl/rust/tests/p2qrh_spend.rs|spending of P2QRH UTXOs]]. +One of these tests demonstrates a tapleaf tapscript that requires a secp256k1 signature to spend the P2QRH UTXO +(modeled after one of the extremely valuable examples provided by [https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature learnmeabitcoin]. +Similar to BIP341 test vectors, all signatures are created with an all-zero (0x0000...0000) BIP340 auxiliary randomness array. == Related Work == From ac8e24fa584392f0e74de3d24089a70fd2136b73 Mon Sep 17 00:00:00 2001 From: jbride Date: Wed, 9 Jul 2025 07:40:21 -0600 Subject: [PATCH 070/131] p2qrh: spend functionality moved out of test and into a library for re-use purposes --- .../stack_element_size_performance_tests.adoc | 4 +- bip-0360/ref-impl/rust/src/data_structures.rs | 18 ++- bip-0360/ref-impl/rust/src/lib.rs | 135 +++++++++++++++++- bip-0360/ref-impl/rust/tests/p2qrh_spend.rs | 132 +++-------------- 4 files changed, 166 insertions(+), 123 deletions(-) diff --git a/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc b/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc index 99383853be..4c7f786939 100644 --- a/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc +++ b/bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc @@ -253,13 +253,15 @@ $ cmake \ -DWITH_ZMQ=ON \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DBUILD_BENCH=ON + +$ cmake --build build -j$(nproc) ----- * Bench tests are conducted similar to the following : + ----- $ export PREIMAGE_SIZE_BYTES=8000 -$ ./build/bin/bench_bitcoin --filter=VerifyP2WSHBench -min-time=5000 +$ ./build/bin/bench_bitcoin --filter=VerifySHA256Bench -min-time=5000 ----- == Failure Analysis diff --git a/bip-0360/ref-impl/rust/src/data_structures.rs b/bip-0360/ref-impl/rust/src/data_structures.rs index b92b6d1b08..32a8ec4b0b 100644 --- a/bip-0360/ref-impl/rust/src/data_structures.rs +++ b/bip-0360/ref-impl/rust/src/data_structures.rs @@ -11,16 +11,6 @@ pub struct TestVectors { pub test_vector_map: HashMap, } -impl TestVectors { - fn new() -> Self { - Self { - version: 0, - test_vectors: Vec::new(), - test_vector_map: HashMap::new(), - } - } -} - impl<'de> Deserialize<'de> for TestVectors { fn deserialize(deserializer: D) -> Result where @@ -232,4 +222,12 @@ impl ScriptTreeHashCache { pub fn set_branch_hash(&mut self, branch_id: u8, hash: String) { self.branch_hashes.insert(branch_id, hash); } +} + +#[derive(Debug, Clone)] +pub struct P2qrhReturnDetails { + pub tx_hex: String, + pub tapscript_sighash: Vec, + pub p2wpkh_sig_bytes: Vec, + pub derived_witness_vec: Vec, } \ No newline at end of file diff --git a/bip-0360/ref-impl/rust/src/lib.rs b/bip-0360/ref-impl/rust/src/lib.rs index fbc00078ca..29b2ee9c20 100644 --- a/bip-0360/ref-impl/rust/src/lib.rs +++ b/bip-0360/ref-impl/rust/src/lib.rs @@ -1,9 +1,140 @@ pub mod data_structures; pub mod error; +use log::info; use std::io::Write; -use std::collections::HashMap; use bitcoin::hashes::{sha256, Hash}; +use bitcoin::sighash::{EcdsaSighashType, Prevouts, TapSighash}; +use bitcoin::secp256k1::{Message, Secp256k1, SecretKey}; +use bitcoin::{ Amount, TxOut, sighash::TapSighashType, transaction, ScriptBuf, WPubkeyHash, Txid, + OutPoint, + blockdata::witness::Witness, + sighash::SighashCache, + taproot::{LeafVersion, TapLeafHash}, + transaction::Transaction, +}; + +use data_structures::P2qrhReturnDetails; + +// Given a p2qrh UTXO, spend to p2wpkh +pub fn p2qrh_to_p2wpkh_tx( + input_tx_id_bytes: Vec, + input_tx_index: u32, + input_script_pubkey_bytes: Vec, + input_control_block_bytes: Vec, + spend_pubkey_hash_bytes: Vec, + input_leaf_script_bytes: Vec, + input_script_priv_key_bytes: Vec +) -> P2qrhReturnDetails { + + let mut txid_little_endian = input_tx_id_bytes.clone(); + txid_little_endian.reverse(); + + // vin: Create TxIn from the input utxo + // Details of this input tx are not known at this point + let input_tx_in = bitcoin::TxIn { + previous_output: OutPoint { + txid: bitcoin::Txid::from_slice(&txid_little_endian).unwrap(), // bitcoin::Txid expects the bytes in little-endian format + vout: input_tx_index, + }, + script_sig: ScriptBuf::new(), // Empty for segwit transactions - script goes in witness + sequence: transaction::Sequence::MAX, // Default sequence, allows immediate spending (no RBF or timelock) + witness: bitcoin::Witness::new(), // Empty for now, will be filled with signature and pubkey after signing + }; + + let spend_wpubkey_hash = WPubkeyHash::from_byte_array(spend_pubkey_hash_bytes.try_into().unwrap()); + let spend_output: TxOut = TxOut { + value: Amount::from_sat(15000), + script_pubkey: ScriptBuf::new_p2wpkh(&spend_wpubkey_hash), + }; + + // The spend tx to eventually be signed and broadcast + let mut unsigned_spend_tx = Transaction { + version: bitcoin::transaction::Version::TWO, + lock_time: bitcoin::locktime::absolute::LockTime::ZERO, + input: vec![input_tx_in], + output: vec![spend_output], + }; + + // Create SighashCache + // At this point, sighash_cache does not know the values and type of input UTXO + let mut tapscript_sighash_cache = SighashCache::new(&mut unsigned_spend_tx); + + // Create the leaf hash + let leaf_version = LeafVersion::TapScript; + let leaf_script = ScriptBuf::from_bytes(input_leaf_script_bytes.clone()); + let leaf_hash: TapLeafHash = TapLeafHash::from_script(&leaf_script, leaf_version); + + /* prevouts parameter tells the sighash algorithm: + 1. The value of each input being spent (needed for fee calculation and sighash computation) + 2. The scriptPubKey of each input being spent (ie: type of output & how to validate the spend) + */ + let prevouts = vec![TxOut { + value: Amount::from_sat(20000), + script_pubkey: ScriptBuf::from_bytes(input_script_pubkey_bytes.clone()), + }]; + info!("prevouts: {:?}", prevouts); + + let spending_tx_input_index = 0; + + // Compute the sighash + let tapscript_sighash: TapSighash = tapscript_sighash_cache.taproot_script_spend_signature_hash( + spending_tx_input_index, // input_index + &Prevouts::All(&prevouts), + leaf_hash, + TapSighashType::All + ).unwrap(); + + info!("sighash: {:?}", tapscript_sighash); + + let spend_msg = Message::from(tapscript_sighash); + + // Signing: Sign the sighash using the secp256k1 library (re-exported by rust-bitcoin). + let secp = Secp256k1::new(); + let secret_key = SecretKey::from_slice(&input_script_priv_key_bytes).unwrap(); + + // Spending a p2tr UTXO thus using Schnorr signature + // The aux_rand parameter ensures that signing the same message with the same key produces the same signature + let p2wpkh_signature: bitcoin::secp256k1::schnorr::Signature = secp.sign_schnorr_with_aux_rand( + &spend_msg, + &secret_key.keypair(&secp), + &[0u8; 32] // 32 zero bytes of auxiliary random data + ); + let mut p2wpkh_sig_bytes: Vec = p2wpkh_signature.serialize().to_vec(); + p2wpkh_sig_bytes.push(EcdsaSighashType::All as u8); + + let p2wpkh_sig_hex = hex::encode(p2wpkh_sig_bytes.clone()); + info!("p2wpkh_signature: {:?}", p2wpkh_sig_hex); + + let mut derived_witness: Witness = Witness::new(); + derived_witness.push(hex::decode("03").unwrap()); + derived_witness.push(serialize_script(&p2wpkh_sig_bytes)); + derived_witness.push(serialize_script(&input_leaf_script_bytes)); + derived_witness.push(serialize_script(&input_control_block_bytes)); + + let derived_witness_vec: Vec = derived_witness.iter().flatten().cloned().collect(); + + let derived_witness_hex = hex::encode(derived_witness_vec.clone()); + info!("derived_witness_hex: {:?}", derived_witness_hex.clone()); + + // Update the witness data for the tx's first input (index 0) + *tapscript_sighash_cache.witness_mut(spending_tx_input_index).unwrap() = derived_witness; + + // Get the signed transaction. + let signed_tx_obj: &mut Transaction = tapscript_sighash_cache.into_transaction(); + + // Reserialize without witness data and double-SHA256 to get the txid + let signed_txid_obj: Txid = signed_tx_obj.compute_txid(); + let tx_hex = bitcoin::consensus::encode::serialize_hex(&signed_tx_obj); + info!("tx_hex: {:?}", tx_hex); + + return P2qrhReturnDetails { + tx_hex, + tapscript_sighash: tapscript_sighash.as_byte_array().to_vec(), + p2wpkh_sig_bytes, + derived_witness_vec: derived_witness_vec, + }; +} // https://learnmeabitcoin.com/technical/upgrades/taproot/#examples @@ -50,4 +181,4 @@ fn compact_size(n: u64) -> Vec { result.extend_from_slice(&n.to_le_bytes()); result } -} \ No newline at end of file +} diff --git a/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs b/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs index 653ea3dac9..4c6e5a70ff 100644 --- a/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs +++ b/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs @@ -1,23 +1,9 @@ -use log::{debug, info}; -use once_cell::sync::Lazy; - -use bitcoin::sighash::{EcdsaSighashType, Prevouts, TapSighash}; -use bitcoin::hashes::Hash; -use bitcoin::secp256k1::{Message, Secp256k1, SecretKey}; -use bitcoin::ecdsa::Signature; -use bitcoin::{ Amount, TxOut, sighash::TapSighashType, transaction, ScriptBuf, WPubkeyHash, - OutPoint, - blockdata::witness::Witness, - sighash::SighashCache, - taproot::{LeafVersion, TapLeafHash}, - transaction::Transaction, -}; - -use p2qrh_ref::{ - data_structures::{TestVector, TestVectors}, - serialize_script, -}; +use log::info; +use bitcoin::blockdata::witness::Witness; +use p2qrh_ref::{ p2qrh_to_p2wpkh_tx, serialize_script }; + +use p2qrh_ref::data_structures::P2qrhReturnDetails; /* 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. @@ -52,14 +38,18 @@ fn test_script_path_spend_simple() { } -// https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature +// Inspired by: https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature +// Spends from a p2qrh 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 input_tx_id_bytes = + let input_tx_id_bytes: Vec = hex::decode("d1c40446c65456a9b11a9dddede31ee34b8d3df83788d98f690225d2958bfe3c").unwrap(); + // The input index of the funding tx + let input_tx_index: u32 = 0; + // OP_PUSHBYTES_32 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0 OP_CHECKSIG let input_leaf_script_bytes: Vec = hex::decode("206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac").unwrap(); @@ -83,96 +73,18 @@ fn test_script_path_spend_signatures() { // Changed from c0 to c1 control byte to reflect p2qrh specification: The parity bit of the control byte is always 1 since P2QRH does not have a key-spend path. let test_witness_bytes: Vec = hex::decode("034101769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f0122206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac21c1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap(); - let mut txid_little_endian = input_tx_id_bytes.clone(); - txid_little_endian.reverse(); - - - // vin: Create TxIn from the input utxo - // Details of this input tx are not known at this point - let input_tx_in = bitcoin::TxIn { - previous_output: OutPoint { - txid: bitcoin::Txid::from_slice(&txid_little_endian).unwrap(), // bitcoin::Txid expects the bytes in little-endian format - vout: 0, - }, - script_sig: ScriptBuf::new(), // Empty for segwit transactions - script goes in witness - sequence: transaction::Sequence::MAX, // Default sequence, allows immediate spending (no RBF or timelock) - witness: bitcoin::Witness::new(), // Empty for now, will be filled with signature and pubkey after signing - }; - - let spend_wpubkey_hash = WPubkeyHash::from_byte_array(spend_pubkey_hash_bytes.try_into().unwrap()); - let spend_output: TxOut = TxOut { - value: Amount::from_sat(15000), - script_pubkey: ScriptBuf::new_p2wpkh(&spend_wpubkey_hash), - }; - - // The spend tx to eventually be signed and broadcast - let mut unsigned_spend_tx = Transaction { - version: bitcoin::transaction::Version::TWO, - lock_time: bitcoin::locktime::absolute::LockTime::ZERO, - input: vec![input_tx_in], - output: vec![spend_output], - }; - - // Create SighashCache - // At this point, sighash_cache does not know the values and type of input UTXO - let mut tapscript_sighash_cache = SighashCache::new(&mut unsigned_spend_tx); - - // Create the leaf hash - let leaf_version = LeafVersion::TapScript; - let leaf_script = ScriptBuf::from_bytes(input_leaf_script_bytes.clone()); - let leaf_hash: TapLeafHash = TapLeafHash::from_script(&leaf_script, leaf_version); - - /* prevouts parameter tells the sighash algorithm: - 1. The value of each input being spent (needed for fee calculation and sighash computation) - 2. The scriptPubKey of each input being spent (ie: type of output & how to validate the spend) - */ - let prevouts = vec![TxOut { - value: Amount::from_sat(20000), - script_pubkey: ScriptBuf::from_bytes(input_script_pubkey_bytes.clone()), - }]; - info!("prevouts: {:?}", prevouts); - - // Compute the sighash - let tapscript_sighash: TapSighash = tapscript_sighash_cache.taproot_script_spend_signature_hash( - 0, // input_index - &Prevouts::All(&prevouts), - leaf_hash, - TapSighashType::All - ).unwrap(); - - assert_eq!(tapscript_sighash.as_byte_array().as_slice(), test_sighash_bytes.as_slice(), "sighash mismatch"); - info!("sighash: {:?}", tapscript_sighash); - - let spend_msg = Message::from(tapscript_sighash); - - // Signing: Sign the sighash using the secp256k1 library (re-exported by rust-bitcoin). - let secp = Secp256k1::new(); - let secret_key = SecretKey::from_slice(&input_script_priv_key_bytes).unwrap(); - - // Spending a p2tr UTXO thus using Schnorr signature - // The aux_rand parameter ensures that signing the same message with the same key produces the same signature - let p2wpkh_signature: bitcoin::secp256k1::schnorr::Signature = secp.sign_schnorr_with_aux_rand( - &spend_msg, - &secret_key.keypair(&secp), - &[0u8; 32] // 32 zero bytes of auxiliary random data + let result: P2qrhReturnDetails = p2qrh_to_p2wpkh_tx(input_tx_id_bytes, + input_tx_index, + input_script_pubkey_bytes, + input_control_block_bytes, + spend_pubkey_hash_bytes, + input_leaf_script_bytes, + input_script_priv_key_bytes ); - let mut p2wpkh_sig_bytes: Vec = p2wpkh_signature.serialize().to_vec(); - p2wpkh_sig_bytes.push(EcdsaSighashType::All as u8); - - assert_eq!(p2wpkh_sig_bytes, test_p2wpkh_signature_bytes, "p2wpkh_signature mismatch"); - let p2wpkh_sig_hex = hex::encode(p2wpkh_sig_bytes.clone()); - info!("p2wpkh_signature: {:?}", p2wpkh_sig_hex); - - let mut derived_witness: Witness = Witness::new(); - derived_witness.push(hex::decode("03").unwrap()); - derived_witness.push(serialize_script(&p2wpkh_sig_bytes)); - derived_witness.push(serialize_script(&input_leaf_script_bytes)); - derived_witness.push(serialize_script(&input_control_block_bytes)); - - let derived_witness_vec: Vec = derived_witness.iter().flatten().cloned().collect(); - assert_eq!(derived_witness_vec, test_witness_bytes, "derived_witness mismatch"); + assert_eq!(result.tapscript_sighash.as_slice(), test_sighash_bytes.as_slice(), "sighash mismatch"); + assert_eq!(result.p2wpkh_sig_bytes, test_p2wpkh_signature_bytes, "p2wpkh_signature mismatch"); + assert_eq!(result.derived_witness_vec, test_witness_bytes, "derived_witness mismatch"); - let derived_witness_hex = hex::encode(derived_witness_vec); - info!("derived_witness_hex: {:?}", derived_witness_hex); } + From fa7bdad56fd4a9fdf0cacef38cb36c0da37fecb5 Mon Sep 17 00:00:00 2001 From: jbride Date: Wed, 9 Jul 2025 11:29:40 -0600 Subject: [PATCH 071/131] p2qrh: first draft of end-to-end p2qrh spend scenario --- .../ref-impl/rust/docs/p2qrh-end-to-end.adoc | 45 ++++++++++++++ .../rust/examples/p2qrh_construction.rs | 22 +++++++ .../ref-impl/rust/examples/p2qrh_spend.rs | 40 +++++++++++++ bip-0360/ref-impl/rust/src/data_structures.rs | 54 ++++++++++++++++- bip-0360/ref-impl/rust/src/lib.rs | 59 +++++++++++++++---- .../ref-impl/rust/tests/p2qrh_construction.rs | 51 +++++----------- bip-0360/ref-impl/rust/tests/p2qrh_spend.rs | 4 +- 7 files changed, 225 insertions(+), 50 deletions(-) create mode 100644 bip-0360/ref-impl/rust/docs/p2qrh-end-to-end.adoc create mode 100644 bip-0360/ref-impl/rust/examples/p2qrh_construction.rs create mode 100644 bip-0360/ref-impl/rust/examples/p2qrh_spend.rs diff --git a/bip-0360/ref-impl/rust/docs/p2qrh-end-to-end.adoc b/bip-0360/ref-impl/rust/docs/p2qrh-end-to-end.adoc new file mode 100644 index 0000000000..6e628de171 --- /dev/null +++ b/bip-0360/ref-impl/rust/docs/p2qrh-end-to-end.adoc @@ -0,0 +1,45 @@ + += P2QRH End-to-End Scenario + +== Fund P2QRH UTXO + +----- +$ export BITCOIN_NETWORK=regtest \ + && export P2QRH_ADDR=$( cargo run --example p2qrh_construction | jq -r '.bech32m_address' ) \ + && echo $P2QRH_ADDR + +$ b-reg -named generatetoaddress 1 $P2QRH_ADDR 1 +$ b-reg -generate 110 + +$ export P2QRH_DESC=$( b-reg getdescriptorinfo "addr($P2QRH_ADDR)" | jq -r '.descriptor' ) \ + && echo $P2QRH_DESC +$ b-reg scantxoutset start '[{"desc": "'''$P2QRH_DESC'''"}]' +----- + +== Spend P2QRH UTXO + +----- +$ export RAW_P2QRH_SPEND_TX=$( cargo run --example p2qrh_spend | jq -r '.tx_hex' ) \ + && echo $RAW_P2QRH_SPEND_TX +$ b-reg testmempoolaccept '["'''$RAW_P2QRH_SPEND_TX'''"]' +----- + + +== Import P2QRH address into bitcoin core wallet + +NOTE: currently fails with: "message": "Cannot import descriptor without private keys to a wallet with private keys enabled" + +----- +$ b-reg -rpcwallet=$W_NAME walletpassphrase $WPASS 120 +$ echo $P2QRH_ADDR +$ export P2QRH_DESC=$( b-reg getdescriptorinfo "addr($P2QRH_ADDR)" | jq -r '.descriptor' ) \ + && echo $P2QRH_DESC + +# Set as non-active address (because can't generate subsequent p2qrh addresses yet) +$ b-reg importdescriptors '[{ + "desc": "'''$P2QRH_DESC'''", + "timestamp": "now", + "active": false, + "label": "p2qrh" +}]' +----- diff --git a/bip-0360/ref-impl/rust/examples/p2qrh_construction.rs b/bip-0360/ref-impl/rust/examples/p2qrh_construction.rs new file mode 100644 index 0000000000..d3cb4e7348 --- /dev/null +++ b/bip-0360/ref-impl/rust/examples/p2qrh_construction.rs @@ -0,0 +1,22 @@ +use bitcoin::taproot::TapNodeHash; +use p2qrh_ref::create_p2qrh_utxo; +use p2qrh_ref::data_structures::P2qrhUtxoReturn; +use bitcoin::hashes::Hash; +use hex; + +fn main() -> P2qrhUtxoReturn { + let p2qrh_utxo_return: P2qrhUtxoReturn = p2qrh_script_path_utxo_construction(); + p2qrh_utxo_return +} + +// Inspired by: https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature +fn p2qrh_script_path_utxo_construction() -> P2qrhUtxoReturn { + + let merkle_root_bytes= hex::decode("858dfe26a3dd48a2c1fcee1d631f0aadf6a61135fc51f75758e945bca534ef16").unwrap(); + let merkle_root: TapNodeHash = TapNodeHash::from_byte_array(merkle_root_bytes.try_into().unwrap()); + + let p2qrh_utxo_return: P2qrhUtxoReturn = create_p2qrh_utxo(merkle_root); + + return p2qrh_utxo_return; +} + diff --git a/bip-0360/ref-impl/rust/examples/p2qrh_spend.rs b/bip-0360/ref-impl/rust/examples/p2qrh_spend.rs new file mode 100644 index 0000000000..0052ee13d6 --- /dev/null +++ b/bip-0360/ref-impl/rust/examples/p2qrh_spend.rs @@ -0,0 +1,40 @@ +use p2qrh_ref::{ p2qrh_to_p2wpkh_tx }; + +use p2qrh_ref::data_structures::P2qrhSpendDetails; + +// Inspired by: https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature +fn main() -> P2qrhSpendDetails { + + let input_tx_id_bytes: Vec = + hex::decode("d1c40446c65456a9b11a9dddede31ee34b8d3df83788d98f690225d2958bfe3c").unwrap(); + + // The input index of the funding tx + let input_tx_index: u32 = 0; + + // OP_PUSHBYTES_32 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0 OP_CHECKSIG + let input_leaf_script_bytes: Vec = + hex::decode("206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac").unwrap(); + + // Modified from learnmeabitcoin example + // Changed from c0 to c1 control byte to reflect p2qrh specification: The parity bit of the control byte is always 1 since P2QRH does not have a key-spend path. + let input_control_block_bytes: Vec = + hex::decode("c1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap(); + + let input_script_pubkey_bytes: Vec = + hex::decode("5120f3778defe5173a9bf7169575116224f961c03c725c0e98b8da8f15df29194b80") + .unwrap(); + let input_script_priv_key_bytes: Vec = hex::decode("9b8de5d7f20a8ebb026a82babac3aa47a008debbfde5348962b2c46520bd5189").unwrap(); + + let spend_pubkey_hash_bytes: Vec = hex::decode("0de745dc58d8e62e6f47bde30cd5804a82016f9e").unwrap(); + + let result: P2qrhSpendDetails = p2qrh_to_p2wpkh_tx(input_tx_id_bytes, + input_tx_index, + input_script_pubkey_bytes, + input_control_block_bytes, + spend_pubkey_hash_bytes, + input_leaf_script_bytes, + input_script_priv_key_bytes + ); + + return result; +} diff --git a/bip-0360/ref-impl/rust/src/data_structures.rs b/bip-0360/ref-impl/rust/src/data_structures.rs index 32a8ec4b0b..4352b2ea8c 100644 --- a/bip-0360/ref-impl/rust/src/data_structures.rs +++ b/bip-0360/ref-impl/rust/src/data_structures.rs @@ -224,10 +224,60 @@ impl ScriptTreeHashCache { } } -#[derive(Debug, Clone)] -pub struct P2qrhReturnDetails { +fn serialize_hex(bytes: &Vec, s: S) -> Result +where + S: serde::Serializer, +{ + s.serialize_str(&hex::encode(bytes)) +} + +fn deserialize_hex<'de, D>(d: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let s = String::deserialize(d)?; + hex::decode(s).map_err(serde::de::Error::custom) +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct P2qrhSpendDetails { pub tx_hex: String, + #[serde(serialize_with = "serialize_hex")] + #[serde(deserialize_with = "deserialize_hex")] pub tapscript_sighash: Vec, + #[serde(serialize_with = "serialize_hex")] + #[serde(deserialize_with = "deserialize_hex")] pub p2wpkh_sig_bytes: Vec, + #[serde(serialize_with = "serialize_hex")] + #[serde(deserialize_with = "deserialize_hex")] pub derived_witness_vec: Vec, +} + +impl std::process::Termination for P2qrhSpendDetails { + fn report(self) -> std::process::ExitCode { + if let Ok(json) = serde_json::to_string_pretty(&self) { + println!("{}", json); + } else { + println!("{:?}", self); + } + std::process::ExitCode::SUCCESS + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct P2qrhUtxoReturn { + pub script_pubkey: String, + pub bech32m_address: String, + pub bitcoin_network: bitcoin::Network, +} + +impl std::process::Termination for P2qrhUtxoReturn { + fn report(self) -> std::process::ExitCode { + if let Ok(json) = serde_json::to_string_pretty(&self) { + println!("{}", json); + } else { + println!("{:?}", self); + } + std::process::ExitCode::SUCCESS + } } \ No newline at end of file diff --git a/bip-0360/ref-impl/rust/src/lib.rs b/bip-0360/ref-impl/rust/src/lib.rs index 29b2ee9c20..a84700e746 100644 --- a/bip-0360/ref-impl/rust/src/lib.rs +++ b/bip-0360/ref-impl/rust/src/lib.rs @@ -1,20 +1,59 @@ pub mod data_structures; pub mod error; -use log::info; +use log::{debug, info}; use std::io::Write; use bitcoin::hashes::{sha256, Hash}; use bitcoin::sighash::{EcdsaSighashType, Prevouts, TapSighash}; use bitcoin::secp256k1::{Message, Secp256k1, SecretKey}; -use bitcoin::{ Amount, TxOut, sighash::TapSighashType, transaction, ScriptBuf, WPubkeyHash, Txid, - OutPoint, +use bitcoin::{ Amount, TxOut, WPubkeyHash, Txid, + Address, Network, OutPoint, blockdata::witness::Witness, - sighash::SighashCache, - taproot::{LeafVersion, TapLeafHash}, - transaction::Transaction, + Script, ScriptBuf, + sighash::{SighashCache, TapSighashType}, + taproot::{LeafVersion, TapLeafHash, TapNodeHash}, + transaction::{Transaction, Sequence} }; +use bitcoin::p2qrh::P2qrhScriptBuf; + +use data_structures::{P2qrhSpendDetails, P2qrhUtxoReturn}; + +pub fn create_p2qrh_utxo(derived_merkle_root: TapNodeHash) -> P2qrhUtxoReturn { + + /* commit (in scriptPubKey) to the merkle root of all the script path leaves. ie: + This output key is what gets committed to in the final P2QRH address (ie: scriptPubKey) + */ + let script_buf: P2qrhScriptBuf = P2qrhScriptBuf::new_p2qrh(derived_merkle_root); + let script: &Script = script_buf.as_script(); + let script_pubkey = script.to_hex_string(); + + let mut bitcoin_network: Network = Network::Bitcoin; + + // Check for BITCOIN_NETWORK environment variable and override if set + if let Ok(network_str) = std::env::var("BITCOIN_NETWORK") { + bitcoin_network = match network_str.to_lowercase().as_str() { + "regtest" => Network::Regtest, + "testnet" => Network::Testnet, + "signet" => Network::Signet, + _ => { + debug!("Invalid BITCOIN_NETWORK value '{}', using default Bitcoin network", network_str); + Network::Bitcoin + } + }; + } + + + // 4) derive bech32m address and verify against test vector + // p2qrh address is comprised of network HRP + WitnessProgram (version + program) + let bech32m_address = Address::p2qrh(Some(derived_merkle_root), bitcoin_network); -use data_structures::P2qrhReturnDetails; + return P2qrhUtxoReturn { + script_pubkey, + bech32m_address: bech32m_address.to_string(), + bitcoin_network, + }; + +} // Given a p2qrh UTXO, spend to p2wpkh pub fn p2qrh_to_p2wpkh_tx( @@ -25,7 +64,7 @@ pub fn p2qrh_to_p2wpkh_tx( spend_pubkey_hash_bytes: Vec, input_leaf_script_bytes: Vec, input_script_priv_key_bytes: Vec -) -> P2qrhReturnDetails { +) -> P2qrhSpendDetails { let mut txid_little_endian = input_tx_id_bytes.clone(); txid_little_endian.reverse(); @@ -38,7 +77,7 @@ pub fn p2qrh_to_p2wpkh_tx( vout: input_tx_index, }, script_sig: ScriptBuf::new(), // Empty for segwit transactions - script goes in witness - sequence: transaction::Sequence::MAX, // Default sequence, allows immediate spending (no RBF or timelock) + sequence: Sequence::MAX, // Default sequence, allows immediate spending (no RBF or timelock) witness: bitcoin::Witness::new(), // Empty for now, will be filled with signature and pubkey after signing }; @@ -128,7 +167,7 @@ pub fn p2qrh_to_p2wpkh_tx( let tx_hex = bitcoin::consensus::encode::serialize_hex(&signed_tx_obj); info!("tx_hex: {:?}", tx_hex); - return P2qrhReturnDetails { + return P2qrhSpendDetails { tx_hex, tapscript_sighash: tapscript_sighash.as_byte_array().to_vec(), p2wpkh_sig_bytes, diff --git a/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs b/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs index baac428251..1cf173a768 100644 --- a/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs +++ b/bip-0360/ref-impl/rust/tests/p2qrh_construction.rs @@ -1,15 +1,16 @@ use std::collections::HashSet; -use bitcoin::{Address, Network, ScriptBuf, Script}; -use bitcoin::taproot::{LeafVersion, TapTree, ScriptLeaves, TapLeafHash, TaprootMerkleBranch}; -use bitcoin::p2qrh::{P2qrhBuilder, P2qrhScriptBuf, P2qrhControlBlock, P2qrhSpendInfo }; +use bitcoin::{Address, Network, ScriptBuf}; +use bitcoin::taproot::{LeafVersion, TapTree, ScriptLeaves, TapLeafHash, TaprootMerkleBranch, TapNodeHash}; +use bitcoin::p2qrh::{P2qrhBuilder, P2qrhControlBlock, P2qrhSpendInfo }; use bitcoin::hashes::Hash; use hex; use log::debug; use once_cell::sync::Lazy; -use p2qrh_ref::data_structures::{TVScriptTree, TestVector, Direction, TestVectors}; +use p2qrh_ref::data_structures::{TVScriptTree, TestVector, Direction, TestVectors, P2qrhUtxoReturn}; use p2qrh_ref::error::P2QRHError; +use p2qrh_ref::create_p2qrh_utxo; // This file contains tests that execute against the BIP360 script-path-only test vectors. @@ -160,7 +161,7 @@ fn process_test_vector_p2qrh(test_vector: &TestVector) -> anyhow::Result<()> { panic!("finalize failed: {:?}", e); }); - let derived_merkle_root = spend_info.merkle_root.unwrap(); + let derived_merkle_root: TapNodeHash= spend_info.merkle_root.unwrap(); // 2) verify derived merkle root against test vector let test_vector_merkle_root = test_vector.intermediary.merkle_root.as_ref().unwrap(); @@ -180,7 +181,7 @@ fn process_test_vector_p2qrh(test_vector: &TestVector) -> anyhow::Result<()> { // TO-DO: Investigate why the ordering of script leaves seems to be reverse of test vectors. // 3) Iterate through leaves of derived script tree and verify both script leaf hashes and control blocks - for (i, derived_leaf) in script_leaves.enumerate() { + for derived_leaf in script_leaves { let version = derived_leaf.version(); let script = derived_leaf.script(); @@ -220,42 +221,20 @@ fn process_test_vector_p2qrh(test_vector: &TestVector) -> anyhow::Result<()> { } - /* commit (in scriptPubKey) to the merkle root of all the script path leaves. ie: - This output key is what gets committed to in the final Taproot address (ie: scriptPubKey) - */ - let script_buf: P2qrhScriptBuf = P2qrhScriptBuf::new_p2qrh(derived_merkle_root); - let script: &Script = script_buf.as_script(); - let script_pubkey = script.to_hex_string(); + let p2qrh_utxo_return: P2qrhUtxoReturn = create_p2qrh_utxo(derived_merkle_root); + assert_eq!( - script_pubkey, + p2qrh_utxo_return.script_pubkey, *test_vector.expected.script_pubkey.as_ref().unwrap(), "Script pubkey mismatch" ); - debug!("just passed script_pubkey validation. script_pubkey = {}", script_pubkey); - - let mut bitcoin_network: Network = Network::Bitcoin; - - // Check for BITCOIN_NETWORK environment variable and override if set - if let Ok(network_str) = std::env::var("BITCOIN_NETWORK") { - bitcoin_network = match network_str.to_lowercase().as_str() { - "regtest" => Network::Regtest, - "testnet" => Network::Testnet, - "signet" => Network::Signet, - _ => { - debug!("Invalid BITCOIN_NETWORK value '{}', using default Bitcoin network", network_str); - Network::Bitcoin - } - }; - } + debug!("just passed script_pubkey validation. script_pubkey = {}", p2qrh_utxo_return.script_pubkey); - - // 4) derive bech32m address and verify against test vector - // p2qrh address is comprised of network HRP + WitnessProgram (version + program) - let bech32m_address = Address::p2qrh(Some(derived_merkle_root), bitcoin_network); - debug!("derived bech32m address for bitcoin_network: {} : {}", bitcoin_network, bech32m_address.to_string()); + let bech32m_address: String = p2qrh_utxo_return.bech32m_address; + debug!("derived bech32m address for bitcoin_network: {} : {}", p2qrh_utxo_return.bitcoin_network, bech32m_address); - if bitcoin_network == Network::Bitcoin { - assert_eq!(bech32m_address.to_string(), *test_vector.expected.bip350_address.as_ref().unwrap(), "Bech32m address mismatch."); + if p2qrh_utxo_return.bitcoin_network == Network::Bitcoin { + assert_eq!(bech32m_address, *test_vector.expected.bip350_address.as_ref().unwrap(), "Bech32m address mismatch."); } Ok(()) diff --git a/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs b/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs index 4c6e5a70ff..fb2aab1986 100644 --- a/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs +++ b/bip-0360/ref-impl/rust/tests/p2qrh_spend.rs @@ -3,7 +3,7 @@ use bitcoin::blockdata::witness::Witness; use p2qrh_ref::{ p2qrh_to_p2wpkh_tx, serialize_script }; -use p2qrh_ref::data_structures::P2qrhReturnDetails; +use p2qrh_ref::data_structures::P2qrhSpendDetails; /* 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. @@ -73,7 +73,7 @@ fn test_script_path_spend_signatures() { // Changed from c0 to c1 control byte to reflect p2qrh specification: The parity bit of the control byte is always 1 since P2QRH does not have a key-spend path. let test_witness_bytes: Vec = hex::decode("034101769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f0122206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac21c1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap(); - let result: P2qrhReturnDetails = p2qrh_to_p2wpkh_tx(input_tx_id_bytes, + let result: P2qrhSpendDetails = p2qrh_to_p2wpkh_tx(input_tx_id_bytes, input_tx_index, input_script_pubkey_bytes, input_control_block_bytes, From 3ab1e3e258afb271f858092c42c471b0aa830836 Mon Sep 17 00:00:00 2001 From: jbride Date: Fri, 11 Jul 2025 11:51:16 -0600 Subject: [PATCH 072/131] p2qrh: first successfull fund, spend and mine in bitcoin core. Need to determine if compact size length needs to prefix script and control block (as part of witness stack) --- .../ref-impl/rust/docs/p2qrh-end-to-end.adoc | 178 +++++++++++++++++- .../rust/examples/p2qrh_construction.rs | 1 - .../ref-impl/rust/examples/p2qrh_spend.rs | 82 ++++++-- bip-0360/ref-impl/rust/src/lib.rs | 63 ++++--- bip-0360/ref-impl/rust/tests/p2qrh_spend.rs | 24 ++- 5 files changed, 282 insertions(+), 66 deletions(-) diff --git a/bip-0360/ref-impl/rust/docs/p2qrh-end-to-end.adoc b/bip-0360/ref-impl/rust/docs/p2qrh-end-to-end.adoc index 6e628de171..8ee5db41ea 100644 --- a/bip-0360/ref-impl/rust/docs/p2qrh-end-to-end.adoc +++ b/bip-0360/ref-impl/rust/docs/p2qrh-end-to-end.adoc @@ -1,31 +1,197 @@ +:scrollbar: +:data-uri: +:toc2: +:linkattrs: -= P2QRH End-to-End Scenario += P2QRH End-to-End Tutorial + +:numbered: + +This tutorial is inspired from the link:https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature[script-path-spend-signature] example of the _learnmeabitcoin_ tutorial for p2tr. + +The tutorial is customized to create, fund and spend from a P2QRH UTXO (consisting of a single leaf taptree) to a P2WPKH address. + +Execute in Bitcoin Core `regtest` mode. + +== Pre-reqs + +=== Bitcoin Core + +TO-DO + +=== Shell Environment + +. *b-reg* command line alias: ++ +Configure an alias to the `bitcoin-cli` command that connects to your customized bitcoin-core node running in `regtest` mode. +. *jq*: ensure json parsing utility is installed and available via your $PATH. +. *awk* : standard utility for all Linux distros (often packaged as `gawk`). + +=== Bitcoin Core Wallet + +This tutorial assumes that a bitcoin core wallet is available. +For example, the following would be sufficient: + +----- +$ export W_NAME=regtest \ + && export WPASS=regtest + +$ b-reg -named createwallet \ + wallet_name=$W_NAME \ + descriptors=true \ + passphrase="$WPASS" \ + load_on_startup=true +----- == Fund P2QRH UTXO +. View (hard-coded) tapscript used in single leaf taptree: ++ +----- +$ b-reg decodescript 206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac | jq -r '.asm' + +6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0 OP_CHECKSIG ----- ++ +NOTE: This script includes a 32-byte x-only public key. +Subsequently, it is not of standard type P2PK. +As a standalone script, this script would be considered _non-standard_. +However, as the script of a tapleaf, the script is considered _standard_. +Tapscript relaxes many script standardness rules. + +. Generate a P2QRH scripPubKey and address given a taptree as defined in link:https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature[learnmeabitcoin tutorial] : ++ +----- +$ export BITCOIN_ADDRESS_INFO=$( cargo run --example p2qrh_construction ) \ + && echo $BITCOIN_ADDRESS_INFO | jq -r . + $ export BITCOIN_NETWORK=regtest \ - && export P2QRH_ADDR=$( cargo run --example p2qrh_construction | jq -r '.bech32m_address' ) \ - && echo $P2QRH_ADDR + && export P2QRH_ADDR=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.bech32m_address' ) \ + && export FUNDING_SCRIPT_PUBKEY=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.script_pubkey' ) \ + && echo -en "$P2QRH_ADDR\n$FUNDING_SCRIPT_PUBKEY\n" +----- -$ b-reg -named generatetoaddress 1 $P2QRH_ADDR 1 -$ b-reg -generate 110 +. fund this P2QRH address with the coinbase reward of a newly generated block: ++ +----- +$ export COINBASE_REWARD_TX_ID=$( b-reg -named generatetoaddress 1 $P2QRH_ADDR 1 | jq -r '.[]' ) \ + && echo $COINBASE_REWARD_TX_ID +----- ++ +NOTE: Sometimes Bitcoin Core does not immediately respond. If so, wait a few seconds and try the above command again. +. view summary of all txs that have funded P2QRH address ++ +----- $ export P2QRH_DESC=$( b-reg getdescriptorinfo "addr($P2QRH_ADDR)" | jq -r '.descriptor' ) \ && echo $P2QRH_DESC $ b-reg scantxoutset start '[{"desc": "'''$P2QRH_DESC'''"}]' ----- +. grab txid of first tx with unspent funds: ++ +----- +$ export FUNDING_TX_ID=$( b-reg scantxoutset start '[{"desc": "'''$P2QRH_DESC'''"}]' | jq -r '.unspents[0].txid' ) \ + && echo $FUNDING_TX_ID +----- + +. Set FUNDIN_UTXO_INDEX env var (used later to correctly identify funding UTXO when generating the spending tx) ++ +----- +$ export FUNDING_UTXO_INDEX=0 +----- + +. view details of funding UTXO to the P2QRH address: ++ +----- +$ export FUNDING_UTXO=$( b-reg getrawtransaction $FUNDING_TX_ID 1 | jq -r '.vout['''$FUNDING_UTXO_INDEX''']' ) \ + && echo $FUNDING_UTXO | jq -r . +----- + == Spend P2QRH UTXO + +. Determine value (in BTC) of funding utxo: ++ +----- +$ export FUNDING_UTXO_AMOUNT_SATS=$(echo $FUNDING_UTXO | jq -r '.value' | awk '{printf "%.0f", $1 * 100000000}') \ + && echo $FUNDING_UTXO_AMOUNT_SATS +----- + +. Referencing the funding tx (via $FUNDING_TX_ID and $FUNDING_UTXO_INDEX), create the spending tx: ++ ----- $ export RAW_P2QRH_SPEND_TX=$( cargo run --example p2qrh_spend | jq -r '.tx_hex' ) \ && echo $RAW_P2QRH_SPEND_TX +----- + +. Inspect the spending tx: ++ +----- +$ b-reg decoderawtransaction $RAW_P2QRH_SPEND_TX +----- + +. Test standardness of the spending tx by sending to local mempool of p2qrh enabled Bitcoin Core: + +.. Generate additional blocks. ++ +This is necessary if you have only previously generated 1 block. ++ +----- +$ b-reg -generate 110 +----- ++ +Otherwise, you may see an error from bitcoin core such as the following: ++ +_bad-txns-premature-spend-of-coinbase, tried to spend coinbase at depth 1_ + +.. Execute: ++ +----- $ b-reg testmempoolaccept '["'''$RAW_P2QRH_SPEND_TX'''"]' ----- +. Submit tx: ++ +----- +$ export P2QRH_SPENDING_TX_ID=$( b-reg sendrawtransaction $RAW_P2QRH_SPEND_TX ) \ + && echo $P2QRH_SPENDING_TX_ID +----- ++ +NOTE: Should return same tx id as was included in $RAW_P2QRH_SPEND_TX + +== Mine P2QRH Spend TX + +. View tx in mempool: ++ +----- +$ b-reg getrawtransaction $P2QRH_SPENDING_TX_ID 1 +----- ++ +NOTE: There will not yet be a field `blockhash` in the response. + +. Mine 1 block: ++ +----- +$ b-reg -generate 1 +----- + +. Obtain `blockhash` field of mined tx: ++ +----- +$ export BLOCK_HASH=$( b-reg getrawtransaction $P2QRH_SPENDING_TX_ID 1 | jq -r '.blockhash' ) \ + && echo $BLOCK_HASH +----- + +. View tx in block: ++ +----- +$ b-reg getblock $BLOCK_HASH | jq -r .tx +----- + +== TO-DO -== Import P2QRH address into bitcoin core wallet +=== Import P2QRH address into wallet NOTE: currently fails with: "message": "Cannot import descriptor without private keys to a wallet with private keys enabled" diff --git a/bip-0360/ref-impl/rust/examples/p2qrh_construction.rs b/bip-0360/ref-impl/rust/examples/p2qrh_construction.rs index d3cb4e7348..c799b372d6 100644 --- a/bip-0360/ref-impl/rust/examples/p2qrh_construction.rs +++ b/bip-0360/ref-impl/rust/examples/p2qrh_construction.rs @@ -19,4 +19,3 @@ fn p2qrh_script_path_utxo_construction() -> P2qrhUtxoReturn { return p2qrh_utxo_return; } - diff --git a/bip-0360/ref-impl/rust/examples/p2qrh_spend.rs b/bip-0360/ref-impl/rust/examples/p2qrh_spend.rs index 0052ee13d6..1d019b234c 100644 --- a/bip-0360/ref-impl/rust/examples/p2qrh_spend.rs +++ b/bip-0360/ref-impl/rust/examples/p2qrh_spend.rs @@ -1,39 +1,83 @@ use p2qrh_ref::{ p2qrh_to_p2wpkh_tx }; use p2qrh_ref::data_structures::P2qrhSpendDetails; +use std::env; +use log::{info, error}; // Inspired by: https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature fn main() -> P2qrhSpendDetails { - let input_tx_id_bytes: Vec = - hex::decode("d1c40446c65456a9b11a9dddede31ee34b8d3df83788d98f690225d2958bfe3c").unwrap(); + let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error + + // FUNDING_TX_ID environment variable is required + let funding_tx_id: String = env::var("FUNDING_TX_ID") + .unwrap_or_else(|_| { + error!("FUNDING_TX_ID environment variable is required but not set"); + std::process::exit(1); + }); + + // FUNDING_UTXO_AMOUNT_SATS environment variable is required + let funding_utxo_amount_sats: u64 = env::var("FUNDING_UTXO_AMOUNT_SATS") + .unwrap_or_else(|_| { + error!("FUNDING_UTXO_AMOUNT_SATS environment variable is required but not set"); + std::process::exit(1); + }) + .parse::() + .unwrap_or_else(|_| { + error!("FUNDING_UTXO_AMOUNT_SATS must be a valid u64 integer"); + std::process::exit(1); + }); + + let funding_tx_id_bytes: Vec = hex::decode(funding_tx_id.clone()).unwrap(); // The input index of the funding tx - let input_tx_index: u32 = 0; + // Allow override via FUNDING_UTXO_INDEX environment variable + let funding_utxo_index: u32 = env::var("FUNDING_UTXO_INDEX") + .ok() + .and_then(|s| s.parse::().ok()) + .unwrap_or(0); - // OP_PUSHBYTES_32 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0 OP_CHECKSIG - let input_leaf_script_bytes: Vec = - hex::decode("206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac").unwrap(); + info!("Funding tx id: {}, utxo index: {}", funding_tx_id, funding_utxo_index); + + // FUNDING_SCRIPT_PUBKEY environment variable is required + let funding_script_pubkey_bytes: Vec = env::var("FUNDING_SCRIPT_PUBKEY") + .map(|s| hex::decode(s).unwrap()) + .unwrap_or_else(|_| { + error!("FUNDING_SCRIPT_PUBKEY environment variable is required but not set"); + std::process::exit(1); + }); // Modified from learnmeabitcoin example // Changed from c0 to c1 control byte to reflect p2qrh specification: The parity bit of the control byte is always 1 since P2QRH does not have a key-spend path. - let input_control_block_bytes: Vec = + let p2qrh_control_block_bytes: Vec = hex::decode("c1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap(); + info!("P2QRH control block size: {}", p2qrh_control_block_bytes.len()); + + let leaf_script_priv_key_bytes: Vec = hex::decode("9b8de5d7f20a8ebb026a82babac3aa47a008debbfde5348962b2c46520bd5189").unwrap(); + + // OP_PUSHBYTES_32 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0 OP_CHECKSIG + let leaf_script_bytes: Vec = + hex::decode("206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac").unwrap(); + + let leaf_script_pubkey_hash_bytes: Vec = hex::decode("0de745dc58d8e62e6f47bde30cd5804a82016f9e").unwrap(); - let input_script_pubkey_bytes: Vec = - hex::decode("5120f3778defe5173a9bf7169575116224f961c03c725c0e98b8da8f15df29194b80") - .unwrap(); - let input_script_priv_key_bytes: Vec = hex::decode("9b8de5d7f20a8ebb026a82babac3aa47a008debbfde5348962b2c46520bd5189").unwrap(); + // OUTPUT_AMOUNT_SATS env var is optional. Default is FUNDING_UTXO_AMOUNT_SATS - 5000 sats + let output_amount_sats: u64 = env::var("OUTPUT_AMOUNT_SATS") + .ok() + .and_then(|s| s.parse::().ok()) + .unwrap_or(funding_utxo_amount_sats.saturating_sub(5000)); - let spend_pubkey_hash_bytes: Vec = hex::decode("0de745dc58d8e62e6f47bde30cd5804a82016f9e").unwrap(); - let result: P2qrhSpendDetails = p2qrh_to_p2wpkh_tx(input_tx_id_bytes, - input_tx_index, - input_script_pubkey_bytes, - input_control_block_bytes, - spend_pubkey_hash_bytes, - input_leaf_script_bytes, - input_script_priv_key_bytes + let result: P2qrhSpendDetails = p2qrh_to_p2wpkh_tx( + funding_tx_id_bytes, + funding_utxo_index, + funding_utxo_amount_sats, + funding_script_pubkey_bytes, + p2qrh_control_block_bytes, + leaf_script_pubkey_hash_bytes, + leaf_script_bytes, + leaf_script_priv_key_bytes, + output_amount_sats ); return result; diff --git a/bip-0360/ref-impl/rust/src/lib.rs b/bip-0360/ref-impl/rust/src/lib.rs index a84700e746..a5c3cd65c3 100644 --- a/bip-0360/ref-impl/rust/src/lib.rs +++ b/bip-0360/ref-impl/rust/src/lib.rs @@ -57,16 +57,18 @@ pub fn create_p2qrh_utxo(derived_merkle_root: TapNodeHash) -> P2qrhUtxoReturn { // Given a p2qrh UTXO, spend to p2wpkh pub fn p2qrh_to_p2wpkh_tx( - input_tx_id_bytes: Vec, - input_tx_index: u32, - input_script_pubkey_bytes: Vec, - input_control_block_bytes: Vec, - spend_pubkey_hash_bytes: Vec, - input_leaf_script_bytes: Vec, - input_script_priv_key_bytes: Vec + funding_tx_id_bytes: Vec, + funding_utxo_index: u32, + funding_utxo_amount_sats: u64, + funding_script_pubkey_bytes: Vec, + p2qrh_control_block_bytes: Vec, + leaf_script_pubkey_hash_bytes: Vec, + leaf_script_bytes: Vec, + leaf_script_priv_key_bytes: Vec, + output_amount_sats: u64, ) -> P2qrhSpendDetails { - let mut txid_little_endian = input_tx_id_bytes.clone(); + let mut txid_little_endian = funding_tx_id_bytes.clone(); txid_little_endian.reverse(); // vin: Create TxIn from the input utxo @@ -74,16 +76,16 @@ pub fn p2qrh_to_p2wpkh_tx( let input_tx_in = bitcoin::TxIn { previous_output: OutPoint { txid: bitcoin::Txid::from_slice(&txid_little_endian).unwrap(), // bitcoin::Txid expects the bytes in little-endian format - vout: input_tx_index, + vout: funding_utxo_index, }, script_sig: ScriptBuf::new(), // Empty for segwit transactions - script goes in witness sequence: Sequence::MAX, // Default sequence, allows immediate spending (no RBF or timelock) witness: bitcoin::Witness::new(), // Empty for now, will be filled with signature and pubkey after signing }; - let spend_wpubkey_hash = WPubkeyHash::from_byte_array(spend_pubkey_hash_bytes.try_into().unwrap()); + let spend_wpubkey_hash = WPubkeyHash::from_byte_array(leaf_script_pubkey_hash_bytes.try_into().unwrap()); let spend_output: TxOut = TxOut { - value: Amount::from_sat(15000), + value: Amount::from_sat(output_amount_sats), script_pubkey: ScriptBuf::new_p2wpkh(&spend_wpubkey_hash), }; @@ -95,13 +97,9 @@ pub fn p2qrh_to_p2wpkh_tx( output: vec![spend_output], }; - // Create SighashCache - // At this point, sighash_cache does not know the values and type of input UTXO - let mut tapscript_sighash_cache = SighashCache::new(&mut unsigned_spend_tx); - // Create the leaf hash let leaf_version = LeafVersion::TapScript; - let leaf_script = ScriptBuf::from_bytes(input_leaf_script_bytes.clone()); + let leaf_script = ScriptBuf::from_bytes(leaf_script_bytes.clone()); let leaf_hash: TapLeafHash = TapLeafHash::from_script(&leaf_script, leaf_version); /* prevouts parameter tells the sighash algorithm: @@ -109,13 +107,17 @@ pub fn p2qrh_to_p2wpkh_tx( 2. The scriptPubKey of each input being spent (ie: type of output & how to validate the spend) */ let prevouts = vec![TxOut { - value: Amount::from_sat(20000), - script_pubkey: ScriptBuf::from_bytes(input_script_pubkey_bytes.clone()), + value: Amount::from_sat(funding_utxo_amount_sats), + script_pubkey: ScriptBuf::from_bytes(funding_script_pubkey_bytes.clone()), }]; info!("prevouts: {:?}", prevouts); let spending_tx_input_index = 0; + // Create SighashCache + // At this point, sighash_cache does not know the values and type of input UTXO + let mut tapscript_sighash_cache = SighashCache::new(&mut unsigned_spend_tx); + // Compute the sighash let tapscript_sighash: TapSighash = tapscript_sighash_cache.taproot_script_spend_signature_hash( spending_tx_input_index, // input_index @@ -130,31 +132,30 @@ pub fn p2qrh_to_p2wpkh_tx( // Signing: Sign the sighash using the secp256k1 library (re-exported by rust-bitcoin). let secp = Secp256k1::new(); - let secret_key = SecretKey::from_slice(&input_script_priv_key_bytes).unwrap(); + let secret_key = SecretKey::from_slice(&leaf_script_priv_key_bytes).unwrap(); // Spending a p2tr UTXO thus using Schnorr signature // The aux_rand parameter ensures that signing the same message with the same key produces the same signature - let p2wpkh_signature: bitcoin::secp256k1::schnorr::Signature = secp.sign_schnorr_with_aux_rand( + let signature: bitcoin::secp256k1::schnorr::Signature = secp.sign_schnorr_with_aux_rand( &spend_msg, &secret_key.keypair(&secp), &[0u8; 32] // 32 zero bytes of auxiliary random data ); - let mut p2wpkh_sig_bytes: Vec = p2wpkh_signature.serialize().to_vec(); - p2wpkh_sig_bytes.push(EcdsaSighashType::All as u8); + let mut sig_bytes: Vec = signature.serialize().to_vec(); + sig_bytes.push(EcdsaSighashType::All as u8); - let p2wpkh_sig_hex = hex::encode(p2wpkh_sig_bytes.clone()); - info!("p2wpkh_signature: {:?}", p2wpkh_sig_hex); + let p2wpkh_sig_hex = hex::encode(sig_bytes.clone()); + info!("signature: {:?}", p2wpkh_sig_hex); let mut derived_witness: Witness = Witness::new(); - derived_witness.push(hex::decode("03").unwrap()); - derived_witness.push(serialize_script(&p2wpkh_sig_bytes)); - derived_witness.push(serialize_script(&input_leaf_script_bytes)); - derived_witness.push(serialize_script(&input_control_block_bytes)); + derived_witness.push(serialize_script(&sig_bytes)); + derived_witness.push(serialize_script(&leaf_script_bytes)); + derived_witness.push(serialize_script(&p2qrh_control_block_bytes)); let derived_witness_vec: Vec = derived_witness.iter().flatten().cloned().collect(); let derived_witness_hex = hex::encode(derived_witness_vec.clone()); - info!("derived_witness_hex: {:?}", derived_witness_hex.clone()); + info!("derived_witness_hex (