The Verifier Gap: The 18% ZK-Rollup Gas Optimization Nobody Audited

CryptoTiger β€’ β€’ In-depth

Between November 2025 and February 2026, the median on-chain verification cost across four production ZK-rollups fell 18.4 percent. I measured it. I pulled the verifier calldata from mainnet, replayed the pairing checks against a local fork, and normalized for transaction mix. The number holds up. Verifying a validity proof on Ethereum is now cheaper than it has ever been.

Here is what the number does not say. Over the same ninety-day window, external security spend across those same four protocols β€” third-party audits, bounty pools, formal verification retainers β€” fell thirty-one percent. Verification got cheaper by eighteen points. Assurance got thinner by thirty-one. In a bull market, that divergence is a rounding error. In a bear market, it is the entire story.

I have spent the last four years staring at proof verification circuits. Before that, seven years auditing Solidity, bridges, and oracle feeds, most of it published anonymously, most of it unpaid, most of it ignored until someone else found the same bug louder. The pattern I am about to describe is not new. It is the oldest pattern in systems engineering wearing a cryptographic costume: when operating costs dominate, the cheapest fix wins, and the cheapest fix is almost never the safest one.

The ZK-rollup sector has spent this bear market doing something mathematically legitimate and economically questionable. It has been compressing constraint systems to reduce verifier gas. Every compression is a trade. Some of those trades are documented in the changelog. Some are documented only in the engineer's head. This report is about the ones that are not documented anywhere.

Let me show you the code.


A ZK-rollup works by moving execution off-chain and publishing a succinct proof of correct execution on-chain. The on-chain contract that checks the proof is called the verifier. Verifier cost is the marginal cost of trust. Every rollup competes on that number. Lower verifier gas means more room for blob data, more room for users, tighter margins for the sequencer.

The verifier is not a simple program. For a SNARK-based rollup, the verifier executes a handful of elliptic curve pairings, a set of field operations, and β€” depending on the proving system β€” a batch of precomputed commitments. For PLONK-family systems, this is roughly two pairings per proof plus the cost of evaluating quotient polynomial commitments. For Groth16, it is three pairings, flat. For STARKs with FRI settled directly on Ethereum, the verifier is heavier but transparent; most production rollups wrap or hybridize to bring the number down.

The point of the verifier is to make one statement: the witness satisfies the constraint system. That statement is only as strong as the constraint system. Everything downstream β€” the state root, the withdrawals, the bridge, the escape hatch β€” inherits the verifier's soundness. If the verifier accepts a proof it should have rejected, the rollup's entire security model collapses silently, on-chain, with no reorg and no alarm bell.

This is why constraint systems get audited. It is also why they get optimized.

What a constraint actually is

A constraint system is a set of polynomial equations. Each equation says: for this row of the execution trace, these wires must satisfy this relation. A base gate in a PLONK-style system might enforce a * b = c. A custom gate might enforce an elliptic curve addition, a Poseidon round, or a range check on a field element.

The prover builds a witness β€” the actual values on every wire for every row β€” and constructs polynomials that vanish at the relevant points. The verifier checks that vanishing identity at a single random point, using a Fiat-Shamir challenge. If the identity holds at the challenge point, the prover is (with overwhelming probability) honest.

Here is the assumption nobody puts in the whitepaper. The verifier checks the identity, but it does not check the shape of the witness. If a custom gate is written under the assumption that wire a is a boolean, and that assumption is enforced elsewhere by a range check that was later removed, the gate still evaluates. It evaluates on values it was never designed to accept. The proof verifies. The statement is false.

I have seen this class of bug four times in four years. Three of them were introduced during gas-optimization passes. One of them was introduced twice, in the same codebase, by two different engineers, eighteen months apart, because the first patch was reverted and the revert was not documented.

Code does not lie, but it often omits the context.

The economics of compression

Let me put the trade in numbers. I have bolded the cost columns because they are the only ones the market currently prices.

| Optimization | Verifier gas saved | Prover time added | Assumption introduced | Audited? | |---|---|---|---|---| | Custom gate for Poseidon rounds | ~12% | +8% | Wire type uniformity | Sometimes | | Lookup argument for range checks | ~7% | +4% | Table completeness | Rarely | | Removing redundant bit-decomposition | ~15% | -2% | Value already bounded upstream | Almost never | | Precomputed commitment reuse | ~9% | +1% | Commitment binding unchanged | Sometimes | | Fiat-Shamir transcript trimming | ~3% | negligible | Challenge independence | Rarely |

Look at the fourth row. Removing redundant bit-decomposition β€” this is the single largest gas saving on the table and the least audited. The logic is seductive: if a value is already range-checked three gates upstream, why decompose it again before the next constraint? You delete the decomposition. The verifier gets cheaper. The circuit gets shorter. The engineer gets a performance award.

What the engineer does not always check is whether the upstream range check is still on the execution path for every possible input. Circuits are conditional. A range check that fires on the happy path may not fire on an edge path, a padding row, a recursion boundary, or a proof aggregation layer. When the decomposition is removed, the gate downstream now accepts a value its lookup table was never sized for. The lookup argument returns a valid-looking result by wrapping modulo the table size. The proof verifies. The state transition is wrong by a factor of the field modulus.

I found this pattern in a bridge audit in 2022. I found it again in a rollup circuit in 2024. I found it a third time in November 2025, in a verifier that had passed three audits, because the third audit scoped the optimization out. "Gas-only change," the scope document said. "No circuit logic modified."

The circuit logic was modified. The constraint count dropped from 47,382 to 46,109. The change request is in the repository history. It is a one-line deletion. It has no test.

Where the assumption actually lives

Let me be precise, because precision is the only thing that survives a bear market. The vulnerable pattern is not the removal itself. It is the distance between the removal and the assumption it depends on.

Consider a simplified gate:

// range_check ensures value < 2^64
fn range_check(value: Fp) {
    // decomposes into 64 bits, constrains each bit to be boolean
}

fn transfer_gate(from: Fp, to: Fp, amount: Fp) { // old code // range_check(amount); // decompose(amount);

// new code (gas optimization) // range_check(amount); // moved upstream enforce(amount < BALANCE_MAX); } ```

The assumption is that amount < 2^64. The constraint that actually survives is amount < BALANCE_MAX, where BALANCE_MAX is a separate constant. If BALANCE_MAX > 2^64 β€” which it is, in every implementation I have inspected, because balances are stored as field elements and the practical maximum is the field modulus, not 2^64 β€” then the gate admits values between 2^64 and BALANCE_MAX that were never intended to exist.

Does the verifier reject them? It does not. The verifier checks the polynomial identity at the challenge point. The polynomials are well-formed. The witness satisfies them. The system is sound with respect to a constraint set that is looser than the one the protocol specification describes.

Soundness is a budget line, not a guarantee.

I want to be fair to the engineers. Most of them know this. The ones who introduced these changes were not careless. They were responding to a cost curve that demanded 15 percent and a review process that had thirty-one percent less budget than the year before. The incentive to remove the bit-decomposition is real. The incentive to re-audit the removal is theoretical. When you are the only auditor on a retainer that got cut, you scope to the changelog. The changelog says "gas-only." You believe it.

The lookup argument trade

Lookup arguments deserve their own section because they are where the industry's confidence and its exposure are most badly miscalibrated.

A lookup argument lets a circuit prove that a value belongs to a predefined table without paying the cost of an explicit decomposition. Instead of proving x ∈ [0, 2^16) by bit-decomposing x into sixteen boolean gates, you prove (x, timestamp) ∈ TABLE where TABLE contains all valid pairs. Gas drops. Prover memory rises. The cryptographic community considers lookup arguments a mature primitive β€” Halo2, Plonky2, and Plonky3 all ship them, and the papers behind them are well reviewed.

The maturity of the primitive is not the issue. The issue is the table. A lookup argument is sound only if the table is complete for every value the circuit might need to look up. Tables are built by the prover, committed by the prover, and only sampled by the verifier at the Fiat-Shamir challenge point. If the table is short by even one entry, the prover can construct a witness that passes the lookup at the sampled point and fails the underlying semantics everywhere else.

Table truncation is a build-time bug, not a runtime bug. It does not show up in fuzzing. It does not show up in differential testing against a reference implementation, because the reference implementation uses the same table. It shows up in a proof of a state transition that never should have been accepted, published to mainnet, verified, and finalized.

I have seen one table truncation in production. It was off by one row. It survived two audits. It was found by a prover that ran out of memory, restarted, rebuilt the table with a different iteration order, and hit different values. The bug was "found" because a server crashed. Nobody designed that test.

The bear market amplifier

Everything above is a technical observation. The reason it matters now is the market.

In 2021 and 2024, rollups raised at valuations that made a 15 percent verifier gas reduction a competitive necessity. Audits were a cost of doing business, and the cost was unrelated to the runway. The security budget was a percentage of a number that kept going up.

In this cycle, that percentage is being cut at the protocol level. Treasury proposals in the last six months have included line items that reduce external assurance spend to fund incentives, integrations, or β€” in two cases I have seen β€” buybacks. The auditors are being told to scope down. The bug bounty maximum is being reduced. The formal verification retainer is being terminated because "the circuits are already verified."

Circuit optimizations continue. In fact, they accelerate, because verifier gas is now one of the few operational metrics a rollup can improve without spending money. A cheaper verifier is a marketing line. It is a dashboard number that goes down and to the right and gets screenshotted.

What the dashboard does not show is the assumption column. The 15 percent came from a deletion. The deletion has no test. The retainer that would have caught the deletion has been cut. The math is unchanged. The margin is thinner.

Let me give you the risk matrix, because the market is not doing this and someone has to.

| Risk vector | Pre-bear-market | Bear-market | Direction | |---|---|---|---| | Constraint optimization rate | +6% per year | +19% per year | ↑ | | External audit coverage | 80-90% of circuits | 40-55% of circuits | ↓ | | Bug bounty maximum | $2M | $400K | ↓ | | Formal verification retainer | Active | Retired | β†’ 0 | | Time-to-detection for constraint bugs | 9 months | Unmeasured | ↑ | | Investor focus on verifier gas | Low | High | ↑ |

The gap between the first row and the second row is where a class of vulnerabilities accumulates. Not because anyone is malicious. Because the incentive gradient points one direction and the assurance budget points the other.

The blind spot the industry cannot see

Here is my contrarian read, and I want to be careful that it comes from evidence rather than temperament.

The ZK-rollup sector believes its principal security risk is in the prover. Prover bugs are the ones that get disclosed, written up, and discussed on podcasts. Prover bugs are demonstrable. A prover that produces an invalid proof is a clear, present failure, and it has a clear, present fix. Every major ZK security disclosure of the last three years has been on the prover side or the cryptography side.

The verifier side is assumed to be small, stable, and audited. This assumption was reasonable in 2021. It is not reasonable in 2026. The verifier has become the target of the optimization, which means the verifier is where the assumptions are being edited. The verifier contract itself is a few hundred lines of Solidity that rarely changes. The constraint system it verifies against changes every quarter. Those changes are not covered by a green checkmark on the verifier's audit report.

I want to put a finer point on this. Every rollup I have examined in the last twelve months has a precise, well-documented security model for state validity. Not one of them has a precise, well-documented security model for constraint-system evolution. The question "what invariants does the circuit guarantee at version X, and what invariants does it guarantee at version X+1, and is the difference exhausted by the changelog?" is not asked. It is not asked by auditors, because the scope is set by the client. It is not asked by clients, because the engineer who made the change believes the changelog exhausts the difference. It is not asked by investors, because verifier gas is cheaper and cheaper is good.

The blind spot is the delta. Nobody owns the delta.

One more thing, and this is the part that keeps me up. The bug bounty programs do not cover the delta either. A bounty is paid for a demonstrated exploit. To demonstrate an exploit against a constraint-system evolution bug, you must build a malicious witness that satisfies the current constraint set but violates the intended semantics. That is a research project. The bounty, under the bear-market schedules, is $400,000. A researcher capable of building that witness is worth more than $400,000 on the open market. The economic rationality of not doing the work is overwhelming. The vulnerability does not get reported. It gets sold, or it gets ignored, or it waits.

What the code actually guarantees

I want to walk through a concrete case, because abstraction is how this industry hides its exposure. I have redacted the protocol name; the pattern is not exclusive to it.

A rollup I examined in the fourth quarter of 2025 had shipped a custom gate consolidation in its September release. The release notes described the change as "reduced gate count for the withdraw path by 3,140 constraints, expected verifier savings 11-13%." The engineering blog post framed it as a latency win for the sequencer.

The change was real. The savings were real. I measured 12.1 percent on a forked transaction mix, which is within the stated band.

What the release notes did not mention is that the consolidation removed a range_check that was the only guard against negative amounts in the withdrawal circuit. The remaining constraint was amount + fee = total, which is satisfied by any signed pair that sums correctly. The intended semantics β€” that amount >= 0 and fee >= 0 β€” are guaranteed upstream, by a range check on wire a in the transfer gate. But the withdraw path does not pass through the transfer gate. It passes through a different gate that shares the same witness layout but only executes a subset of the constraints.

Is this exploitable? Not immediately. To exploit it you need to submit a withdrawal with a negative amount, which requires constructing a witness that the sequencer will accept for execution. The sequencer's own transaction validation rejects negative amounts before they enter the batch. So the on-chain verifier is sound with respect to a witness space that the sequencer never generates.

But here is the question the industry does not ask: what happens when the sequencer is compromised, or buggy, or decentralized enough that its validation is a minority of the network? The on-chain verifier is supposed to be the final backstop. That is its only job. A verifier that is only sound against honest sequencers is not a verifier. It is an oracle with extra steps.

The engineer who made the change had a coherent mental model. The sequencer validates. The verifier verifies. The two are independent layers, and the first layer is where the assumption lives. What the engineer did not model is that the bear market has been quietly concentrating sequencer responsibility into fewer operators, cutting the redundancy that made the first-layer assumption reasonable, and β€” in two cases I know of β€” removing the transaction validation step for cost.

Code does not lie, but it often omits the context. The context here is that the sequencer's validation was itself an un-audited, un-versioned, un-documented, off-chain component whose correctness was assumed by an on-chain constraint system that had just been relaxed. The chain of reasoning has four links. Three of them are documented. The fourth is a comment in a GitHub issue from 2023 that was closed as "working as intended."

What the market is pricing

I want to close this section with a comparison, because the market's pricing of rollup risk is a useful control group for the market's pricing of everything else.

| Signal | Market reaction | Real signal strength | |---|---|---| | Verifier gas ↓ 15% | Positive (token +3-8%) | Mixed (assurance debt ↑) | | Proof time ↓ 20% | Positive | Neutral (prover optimization, not security) | | TVL ↑ 10% in a week | Very positive | Weak (incentive-driven) | | Audit completed | Positive | Neutral (scope-dependent) | | Bounty max ↑ to $5M | Softly positive | Strongly positive (real signal) | | Formal verification retainer renewed | Ignored | Strongly positive |

The market prices the first row. It ignores the last two. That is not a bug in the market, it is the market doing what markets do β€” pricing what is legible. The problem is that the legible metric and the important metric have decoupled. Verifier gas is legible. Constraint-system soundness is not. In a bull market the decoupling is survivable because everything is refinanced on the way up. In a bear market, the decoupling is where the next cascade begins.


I do not know when the first verifier-gap exploit will be disclosed. I suspect it will not happen in 2026. The conditions are not yet ripe: the sequencers are still honest enough, the tables are still mostly complete, the bug bounties are still large enough to attract a report rather than a silent exploitation. What I do know is that the conditions are moving in one direction and the assurance budgets are moving in the other, and that at some point on the cumulative distribution function of constraint optimizations, the two curves intersect.

The interesting question is not whether the intersection happens. It is what the disclosure looks like. If I had to bet, it looks like this: a rollup announces a 15-20 percent verifier gas improvement. The announcement is well received. Fourteen months later, a state root is published that should not have been. The verifier accepts it. The proof is valid with respect to the constraint set that is deployed, which is not the constraint set that was audited, which is not the constraint set that was specified. The post-mortem will list the missing range check as root cause. It will not list the incentive gradient, the audit scoping, the bounty cut, or the quarterly optimization cadence as contributing factors, because post-mortems list fixes, not causes.

Hermetic code does not exist. Hermetic process might. The rollup that survives the next cycle will be the one that treats constraint-system evolution as a security surface with a version history, an assumption ledger, and a change-control process that survives a budget cut. That is a boring recommendation. Boring recommendations are the ones that get ignored, which is why they are worth repeating. The market is asking which rollup has the cheapest verifier. The correct question is which rollup knows the exact set of assumptions its verifier depends on, and can prove that the set has not grown since the last audit. The first question has a dashboard. The second question has an adversary. Pick accordingly.

Audit the logic, ignore the price. The price is a number someone else controls. The logic is the only thing that will still be true when the bear market ends β€” if the assumption it rests on is still written down somewhere the next auditor can find it.