§ 06

§ 06 · Script

OP_CHECKXMSSSIG

Pearl's post-quantum signature check, opcode 0xde

OP_CHECKXMSSSIG is the one opcode Pearl added to Bitcoin’s Script. It checks an XMSS signature: a signature built only from hash functions, which are believed to stay secure even against large quantum computers.

It’s an insurance policy. Schnorr signatures on secp256k1 protect every Pearl coin today, but a working quantum computer could break them. A Taproot address can carry an XMSS check as a hidden backup script, ready to use if that day comes (though the address’s Schnorr key path stays open too). The opcode exists and works; this page also covers how far Pearl’s wallet goes in using it.

What is XMSS, in short?

A one-time signature, multiplied. A Winternitz one-time key can sign exactly one message using nothing but hash chains. XMSS makes 32 of them (on Pearl) and ties their public keys together in a Merkle tree, whose root is the long-term public key. Each signature uses one leaf and includes the path that proves the leaf belongs to the tree.

The catch: it’s stateful. The signer must never use a leaf twice, and when all 32 are used, the key is spent. The XMSS page covers the scheme in depth.

Hash function
SHAKE256
n = 32 bytes
Winternitz w
16
67 hash chains per one-time key
Tree height
5
32 signatures per key
Public key
64 bytes
Merkle root + public seed
Signature
2,340 bytes
5 × 468 on the stack
Opcode
0xde
222; tapscript only

Pearl’s code names the parameter set “XMSS-SHAKE256_5_256 (not in RFC 8391)”: the RFC’s standard sets have taller trees.

The 2,340-byte XMSS signature
Field Size Description
index 4 Which of the 32 one-time keys was used.
randomness r 32 Per-signature randomness mixed into the message hash.
WOTS signature 67 × 32 2,144 bytes: one value from each of the 67 Winternitz hash chains.
authentication path 5 × 32 160 bytes: the sibling hashes from that leaf up to the root.

What does the opcode do?

Size
1 byte (0xde)
Type
Tapscript opcode
Format
[sig1 sig2 sig3 sig4 sig5 pubkey] → [true]
  1. Tapscript only

    Anywhere else, it’s an invalid opcode. (On Pearl, every script that runs is tapscript anyway.)
  2. Pop the public key

    The top item must be the 64-byte XMSS public key.
  3. Pop five pieces

    The next five items are the signature, sig1 deepest. Each must be exactly 468 bytes. Any wrong length fails the script.
  4. Charge the budget

    1,000 is taken from the input’s signature budget (50 plus the witness size). A Schnorr check costs 50.
  5. Compute the message

    The BIP-342 tapscript sighash, always with the default sighash type: the same message an OP_CHECKSIG in this leaf would sign.
  6. Verify

    Join the pieces and verify. Valid: push true. Invalid: the script fails immediately. Unlike OP_CHECKSIG, it never pushes false.
node/txscript/opcode.go Go
const numSigChunks = 5
const sigChunkSize = xmss.SignatureLen / numSigChunks // 468 bytes = 2340 / 5
…
// XMSS_SHAKE256_5_256 verification is capped at 67 * 16 + 5 hashes
if err := vm.tapscriptCtx.tallyOpCost(1000); err != nil {
	return err
}
…
valid := xmss.Verify(pk, msg, sig)
if !valid {
	str := "invalid XMSS signature"
	return scriptError(ErrNullFail, str)
}

The 520-byte limit on stack items is why the signature arrives in five pieces. Run de alone, with an empty stack, and Pearl’s engine fails trying to pop the key; in Bitcoin’s tapscript the same byte is OP_SUCCESS222 and the script would pass.

How does Pearl’s wallet use it?

Only when asked. getnewaddress … pq=true makes a quantum-safe address like this:

  1. Two keys from one seed

    The usual Schnorr key at m/86’/808276’/0’/branch/index, and a second key at m/222’/808276’/0’/branch/index. 222 is 0xDE, the opcode’s byte.
  2. XMSS seeds

    The second key’s 32-byte private key goes through HKDF-SHA256 with the label “XMSS-SEED-EXPANSION”, giving a 64-byte private seed and a 32-byte public seed. XMSS key generation runs from those.
  3. One leaf

    The leaf script is 40 ‖ the 64-byte XMSS public key ‖ de: 66 bytes.
  4. Tweak

    The Schnorr key is tweaked with that leaf’s hash, exactly as on the Taproot tweak page.

The result is an ordinary prl1p… Taproot address, not a P2MR one. Here is the real example the research for this site produced with Oyster, from the public test phrase “abandon … about” (index 3):

Value
Schnorr internal key P (m/86’/808276’/0’/0/3) a93c92e3e66d37d57328f72b9705a8d76abaa0aff97c4cd9a3bc147bc3894f1b
PQ key (m/222’/808276’/0’/0/3), HKDF input c8d6edf779a83c7faef392035015191b634a85dc198c9e123f164872b86c2870
XMSS public key (64 bytes) 5e70da755554f576…ce2f0df31994e54b25ee8f8
Leaf hash = tree root 4d136994bb1cfe36b7b495d9bda4de40afe915112882d7b4730bf90fea75a91a
Output key Q b9cacae9a3006236c709e93e003a649f38ac20966a00dd3de5a80c1acbf5837d
Address (pq=true) prl1ph89v46drqp3rd3cfaylqqwnynuu2cgykdgqd60094qxp4jl4sd7ssg6v5j
Same P with no leaf, for comparison prl1prmdvgxfgzmqzq5dj58enw6y7c55wpsfdpr0af7t79x65z6gmms8q4qa93j

The leaf changes the tweak, so the address differs from the plain one, but nobody can tell from outside that it has a backup path.

What would an XMSS spend look like?

It would be a Taproot script-path spend with seven witness items: the five signature pieces, the 66-byte leaf, and a 33-byte control block (leaf version and parity, then P). Adding up the bytes:

1+5×(3+468)+(1+66)+(1+33)=2,457 bytes1 + 5 \times (3 + 468) + (1 + 66) + (1 + 33) = 2{,}457 \text{ bytes}

That’s about 615 vbytes of witness, so a one-input, two-output XMSS spend would be roughly 750 vbytes, around five times a Schnorr payment. Its budget, 50 + 2,457 = 2,507, easily covers the 1,000-unit check. These are estimates from the rules; no such spend has been observed.

Can I use it today?

Partly, and it’s worth being precise:

  • Consensus is ready. Any node running v1.5.2 verifies OP_CHECKXMSSSIG in any tapscript leaf, Taproot or P2MR.
  • The wallet commits, but doesn’t sign. Oyster can create pq addresses, but a search of the v1.5.2 code found no xmss.Sign caller outside tests. Coins at pq addresses are spent by the Schnorr key path, like any other. The XMSS leaf is an emergency exit that wallet software doesn’t yet open.
  • It’s opt-in and rare. The Pearl Desktop Wallet never asks for pq addresses, change addresses never include the leaf, and the default is plain BIP-86.
  • Restoring is untested. Reading the code, a fresh restore from 12 words may not rescan pq addresses. See the note on the mnemonic page.

The codex

Suggested

Up and down arrows move through the results, Enter opens one, Escape closes. Anywhere on the site, slash or Command K opens this search, and the square brackets [ and ] go to the previous and next page.