How the competition works
A verifier is a script that checks a zero-knowledge proof (here, a Groth16 proof), so coins move only if the proof is valid. The leaderboard ranks verifiers by the total bytes they put on chain, after a correctness gate, and lower wins. Bitcoin Cash limits how much each input (each coin a transaction spends) may contain and compute, so entries are split into chains of inputs or transactions.
The rules
Score. An entry’s score is every on-chain byte: the locking scripts (the code a coin is locked to), the unlocking scripts (what spends it) and the rest of each serialized transaction. Zero bytes added only as padding, to buy compute, count too. Bytes are what users pay in fees.
Correctness gate. To be ranked, an entry must accept valid proofs and reject tampered ones; one that fails stays listed but is disqualified. It is also checked against BCH’s consensus rules (what a valid block may contain) and relay rules (what nodes pass on by default), and the leaderboard shows which it meets.
Passing tests does not prove a verifier sound, so every entry carries a review status (details in the soundness review):
- reviewed: an independent review of the exact shipped artifact found no gaps.
- unreviewed: the author’s or maintainer’s claim, with no open finding; it still ranks.
- withdrawn or archived: withdrawn by its author, held over a finding, or superseded; these leave the ranking (withdrawn entries also leave the list).
- baseline, component, demo: third-party reference verifiers, partial sub-steps and the harness self-test, not ranked submissions.
The #1 entry may not run on BCH. Builds that ignore the per-input limits are still listed: they mark the byte floor, the smallest size reached so far and the target to beat. Today the smallest entry is 4.6 KB, in one input that would need the compute budget of about 688 inputs, so it cannot run on BCH.
Limits we grade against
Op-cost is the VM’s count of computation; each input may spend an amount set by its own length.
| limit | value | rule |
|---|---|---|
| Unlocking script per input | 10,000 B | consensus and relay |
| Op-cost budget per input | (41 + unlocking length) × 800, about 8M at 10,000 B | consensus and relay |
| Op-cost per hash digest iteration | 64 (consensus), 192 (relay) | consensus and relay |
| Transaction size | 100,000 B | relay |
| Locking script (pay-to-script) | 201 B | relay |
Op-cost includes the body bytes of each OP_DEFINE (which stores a reusable function), as Bitcoin Cash Node charges them. We patch the libauth library until bitauth/libauth#166 ships, and checked the result on a real node (node check).
Other VMs we also report
We also grade three other rule sets:
- bch-spec: an experimental libauth mode with 100,000 B inputs and a density base of 10,000 B, so every input gets at least 8M op-cost however short it is. Its entries wear a
bch-specbadge and get their own crown. - Larger inputs only: each bch-spec entry is also graded with 100,000 B inputs under consensus rules (the relay grade assumes the same 100,000 B cap), but with the base kept at 41, as in an existing transaction-format proposal, so every input still pays for compute with its own bytes.
- Limits disabled: a reference VM that runs single-input builds too big for any input. They chart the byte floor but cannot run on chain.
Which limits to raise compares what each change would save.
A chain, not a single input
A full Groth16 check needs far more compute than one input’s budget, so a BCH-native entry splits it into steps. Each step is an input that stays under the limits, does part of the work and passes its result on. The steps can be inputs of one transaction, a chain of transactions, or a mix.
Details and sources
One transaction, many inputs: each input reads its neighbours’ scripts through transaction introspection, so the steps check each other in the same transaction.
A chain of transactions: each step carries the running state forward in a CashToken NFT commitment. The commitment holds only 128 bytes, so it stores a hash256 of the state; the next spender re-supplies the state and the contract checks it against the hash before running its part.
Grouped: a few transactions of many inputs each, linked by NFT hand-offs, so a graph larger than one standard transaction stays relayable.
The cost of splitting
On BN254, the byte floor is 4.6 KB, but the smallest verifier that fits today’s limits is 28 KB across 3 inputs, ~6.0× larger. That gap is the price of today’s per-input limits, and closing it is the competition.
Details and sources
Where the extra bytes go: zero padding that buys each input its op-cost budget (an input’s budget grows with its length); function prologues (the shared OP_DEFINE code) shipped again in every input that needs them; and state that is re-supplied and re-hashed at every step. Smaller single-input builds also trade bytes for compute: the fewest bytes come with the most op-cost, so no packaging could fit the byte floor under today’s budget.
Why Groth16
Groth16 has the smallest proofs and the cheapest verification of the widely used proof systems, so when every byte of the verifier is scored it is the natural first target. Its costs are a trusted setup for every circuit and pairing cryptography that a large quantum computer would break; see other proof systems and beyond Groth16.
Details and sources
Bitcoin Cash has no pairing opcode, so the whole verifier is written in Script: field arithmetic up through the F_p¹² tower, the Miller loop and the final exponentiation. The 2025 and 2026 upgrades make this practical: big integers for 256-bit modular arithmetic, loops to collapse repeated work, and functions (OP_DEFINE/OP_INVOKE) so field operations are not inlined everywhere. Entries cover two curves, BN254 (32-byte field elements) and BLS12-381 (48-byte); compare within a curve.
Submitting
Submissions are open: send a pull request to the benchmark with your compiled bytecode, following CONTRIBUTING.md and the claims sheet. Your contract source can stay private; the bytecode and a description of the construction must be public.
Details and sources
The code: zk-verifier-bench, the harness that grades each entry (this site reads its output); groth16_cashscript, the verifier contracts and chunk generators; and the CashScript fork with reusable functions used to compile them.