Why Taproot Is Quantum-Vulnerable

Taproot's key-path spend exposes public keys on-chain, creating a quantum attack surface that no amount of post-quantum scripting can fix. BIP-360's P2MR removes the vulnerability at the root.

What Taproot Does

Taproot (BIP-340/341/342), activated on Bitcoin in November 2021, introduced two major innovations. First, it replaced ECDSA with Schnorr signatures for the key-path spend, enabling signature aggregation and improved privacy. Second, it introduced a Merkleized Alternative Script Tree (MAST) that allows complex spending conditions to be committed to a single on-chain hash, with only the branch used in a spend revealed at transaction time.

A Taproot output (P2TR) encodes a 32-byte “tweaked” public key directly in the scriptPubKey:

P2TR output: OP_1 <32-byte tweaked public key>

This tweaked key is derived from an internal public key combined with the Merkle root of the script tree. There are two spending paths: the key path (provide a valid Schnorr signature for the tweaked key) and the script path (reveal one script branch from the Merkle tree and satisfy it). The key path is the fast, private, compact option. The script path is the fallback for complex conditions.

The Key-Path Problem

The quantum vulnerability: the tweaked public key is always visible on-chain in the scriptPubKey, from the moment the output is created. Unlike P2PKH or P2WPKH outputs (where only a hash of the public key appears on-chain), P2TR outputs expose the actual public key — in a form that can be reversed to the internal key.

A quantum computer running Shor’s algorithm can derive the private key from this exposed public key. With the private key, the attacker can spend the output through the key path — regardless of what scripts exist in the script tree.

This creates a paradox for post-quantum security: you could write a perfectly secure Dilithium signature check in a Taproot script leaf, creating what appears to be a quantum-resistant spending condition. But an attacker with a CRQC would simply ignore your script entirely and spend through the key path. The quantum-resistant script is inside a quantum-vulnerable container.

Critically, this is not a timing vulnerability like P2PKH (where the public key is only exposed when you spend). P2TR outputs are vulnerable from the moment they are created. The attacker has unlimited time to compute the private key — no race condition, no mempool front-running required.

Dilithium in Taproot: False Security

When the BTQ project first added Dilithium opcodes to its scripting language, they were available in all script execution contexts — including Taproot tapscript. This seemed logical: if you have quantum-resistant signature verification, why not use it everywhere?

The problem became apparent during security review. Allowing Dilithium opcodes in Taproot tapscript provides a false sense of security. A user might construct a P2TR output with a script leaf containing an OP_CHECKSIGDILITHIUM check and believe their funds are quantum-safe. They are not. The key-path bypass makes the Dilithium script irrelevant.

The fix was to explicitly disable all five Dilithium opcodes in the Tapscript execution context, following the same pattern used for OP_CHECKMULTISIG (which is also disabled in tapscript). Any attempt to execute a Dilithium opcode in a P2TR script now fails with a specific error message:“Dilithium opcodes are not available in tapscript (P2TR is quantum-vulnerable).”

The Sigop DoS Discovery

The investigation into Dilithium-in-Taproot was triggered by a separate vulnerability reported by the pseudonymous security researcher masato83. The issue: Bitcoin’s sigop counting function (GetTransactionSigOpCost) did not count Dilithium opcodes, meaning they did not contribute toward the per-block sigop limit.

While 80,000 unique Dilithium signatures cannot physically fit in a block (each is 2,420 bytes), a script can duplicate signatures already on the stack:

<sig> <pubkey>

OP_2DUP OP_CHECKSIGDILITHIUMVERIFY

OP_2DUP OP_CHECKSIGDILITHIUMVERIFY

OP_2DUP OP_CHECKSIGDILITHIUMVERIFY

... (repeated)

Each OP_2DUP copies the signature and key without adding data to the block, while each OP_CHECKSIGDILITHIUMVERIFY performs a full Dilithium verification (~1.5ms). Without sigop counting, a block could contain scripts forcing thousands of Dilithium verifications, creating a denial-of-service vector where block validation takes far longer than expected.

The fix was straightforward: add all four Dilithium signature opcodes to the sigop counting function, applying the same counting rules as their ECDSA equivalents. Single-sig opcodes count as 1 sigop; multi-sig opcodes use the same N-of-M counting logic. This brings Dilithium operations under the existing resource control framework.

The OP_SUCCESSx Bypass

While investigating the sigop issue, the BTQ team discovered a more critical vulnerability. In BIP-342’s tapscript rules, opcodes in the range 0xbb–0xfe are designated asOP_SUCCESSx — opcodes reserved for future soft-fork upgrades. Any tapscript containing an OP_SUCCESSx opcode unconditionally succeeds without validation.

The Dilithium opcodes were assigned values 0xbb through 0xbf — squarely within the OP_SUCCESSx range. This meant that any Taproot script containing a Dilithium opcode would automatically succeed, regardless of whether the signature was valid, present, or even the right type. Anyone could spend any Taproot output containing a Dilithium opcode in its script tree.

The fix narrowed the OP_SUCCESSx range from “0xbb to 0xfe” to “0xc0 to 0xfe”, explicitly excluding the Dilithium opcode range. Combined with disabling Dilithium opcodes in tapscript entirely, this eliminated both the bypass vulnerability and the false-security risk. The discovery underscores why post-quantum modifications to Bitcoin’s consensus rules require exhaustive analysis of interaction effects — opcode assignment is not just a numbering exercise.

BIP-360 and Pay-to-Merkle-Root

Disabling Dilithium in Taproot is the correct short-term fix, but it leaves a gap: there is no script-tree output type where Dilithium signatures can be used with genuine quantum resistance. You can use Dilithium in legacy-style P2PKH scripts, but you lose Taproot’s privacy benefits (unrevealed branches) and efficiency (compact key-path spends).

The long-term solution comes from BIP-360, authored by Hunter Beast. BIP-360 proposes Pay-to-Merkle-Root (P2MR) — a new SegWit version 2 output type that takes everything valuable from Taproot and removes the quantum-vulnerable element.

The key insight: remove the key path entirely. Instead of committing to a tweaked public key (which exposes the key on-chain), P2MR commits only to the Merkle root of the script tree:

P2TR (v1): OP_1 <tweaked-pubkey> ← public key exposed, quantum-vulnerable

P2MR (v2): OP_2 <script-tree-root> ← no public key, quantum-resistant

With no public key on-chain, there is no key-path bypass. The only way to spend a P2MR output is through the script path — revealing one branch of the Merkle tree and satisfying its conditions. If that branch contains a Dilithium signature check, the output is genuinely quantum-resistant: the public key only appears at spend time (in the witness), and the signature scheme is immune to Shor’s algorithm.

P2MR in Practice

The BTQ project implemented P2MR as described in BIP-360, making it the first UTXO chain to ship a production quantum-resistant script tree output type. The implementation includes:

  • New address format: bc1z... on mainnet (SegWit version 2, bech32m encoding). The “z” prefix visually distinguishes P2MR addresses from Taproot’s bc1p....
  • Compact control blocks: P2MR control blocks are 1 + 32*m bytes (where m is the Merkle path depth). P2TR control blocks are 33 + 32*m bytes because they include the 32-byte internal public key. P2MR saves 32 bytes per spend.
  • Dilithium opcodes re-enabled: All five Dilithium opcodes work inside P2MR tapscript. They remain disabled in P2TR tapscript. The execution context determines which opcodes are available.
  • No key path: Witness stacks with fewer than 2 elements are rejected. This enforces the script-path-only rule at the consensus level.
  • Parity bit enforcement: The control block parity bit must be 1, per the BIP-360 specification.

The implementation was validated with 15 test groups covering output format, script path spending, key path rejection, cross-tree spend prevention, control block format validation, address encoding, and multi-input transactions. Every successful spend was mined into a block and verified at the consensus level — not just mempool acceptance.

Implications for Bitcoin

The Taproot quantum vulnerability is not theoretical — it is a direct consequence of the P2TR output format. Every Taproot output on the Bitcoin blockchain today exposes a public key that a future quantum computer could use to derive the private key and steal the funds. As of early 2026, the amount of bitcoin held in Taproot outputs continues to grow.

For Bitcoin Core, the path forward likely involves adopting something similar to BIP-360’s P2MR, whether through that specific proposal or an evolved version. The engineering is straightforward: it is a SegWit version 2 output type that requires no changes to the existing Taproot infrastructure — P2TR continues to work for anyone who uses it, and P2MR adds a new quantum-resistant option.

What the BTQ implementation demonstrates is that P2MR is not just a specification — it can be built, tested, and deployed in a Bitcoin-compatible codebase. The vulnerabilities discovered along the way (sigop DoS, OP_SUCCESSx bypass, false security of Dilithium-in-Taproot) are exactly the kind of findings that justify implementing PQC on a separate network first. These issues are far cheaper to discover in a fork than in Bitcoin mainnet.

Latest Dispatches