Why does a missing constraint not look like a bug?
Because the system behaves correctly at every step. A constraint system defines what a valid witness is. If a constraint is absent, witnesses that should have been rejected satisfy the system, the prover produces a proof for one of them, and the verifier checks that proof and accepts. Nothing has malfunctioned. The proof is valid; the statement it proves is not the statement the author intended.
This is what separates circuit bugs from the software defects most review processes are built around. A memory error crashes. A logic error returns a wrong value somebody eventually notices. An under-constrained circuit returns a correct answer to the wrong question, and there is no runtime symptom to observe, no exception to log and no anomalous output to detect in monitoring.
What does the review actually have to do?
It has to establish that the constraint system expresses the intended statement and nothing weaker. That is a specification problem rather than a code-reading problem: the reviewer needs the intended statement written down precisely enough to be compared against the constraints, which is work that often has not been done before the audit starts.
The discipline is therefore closer to formal specification than to the line-by-line reading that smart contract review grew out of, and the pool of people who can do it well remains very small. For anyone planning a launch, that is a scheduling constraint as much as a budget one.
How do designs reduce what has to be audited?
By keeping expensive, hard-to-verify machinery out of the circuit in the first place. The recurring cost in recursive proof systems is that the verifier must be expressed as a circuit, the verifier hashes, and hashing inside a circuit is expensive. Symphony, a lattice-based folding scheme, avoids embedding a cryptographic hash function inside the circuits being verified, which addresses both the performance cost and the security awkwardness of modelling a hash inside the proven statement.
NeutronNova approaches the same problem from the other side by making the recursive verifier small: three group scalar multiplications and a constant number of hash computations, leaving witness commitment as the dominant cost. In a recursive setting the verifier runs inside the next circuit, so its size sets the floor on recursion overhead, and three scalar multiplications is a small floor. A smaller verifier circuit is also a smaller thing to get wrong.
| Source of risk | Why it is hard to catch | What reduces it |
|---|---|---|
| Missing constraint | Produces a valid proof of a false statement; no runtime symptom | A written specification the constraints can be checked against |
| Hash inside the verified circuit | Large circuit to review, and a hash modelled inside the proven statement | Schemes that keep the hash out, as Symphony does |
| Recursion overhead | The verifier becomes part of the next circuit, so its bugs compound | A minimal recursive verifier; NeutronNova needs three scalar multiplications |
| What a signature commits to | Looks academic in a report, becomes an incident under a bridge | Bind expiration and reference block explicitly; the Miden review found both missing |
| Prover-chosen inputs | The proof is valid for state the prover selected | Pin the reference block; read current state, not prover-supplied state |
| Field and scheme choice | Constrains the whole system around it after launch | Constructions that work for arbitrary parameters, as ReedWeave does for m |
What did a real audit of this kind of system find?
OpenZeppelin's review of the Miden smart contract library, written in Rust and MASM and audited between 18 May and 30 June 2026, reported sixty issues, of which fifty were resolved and four partially resolved: eleven medium, seventeen low and thirty-two notes. No critical or high findings in a library of that size is the result the client wanted.
The informative part is the shape rather than the count. The medium band is dominated by authorisation and access control rather than arithmetic or memory safety: transfer policies registered as reserved that can never be activated, ownership transfers and role assignments permanently restricted to version-one account identifiers, authority-gated setters that turn out to be permissionless in one pairing of components, account authentication that does not bound the transaction fee deducted, and repeated unauthorised consumption of input notes draining an account through fees alone.
Two findings concern what a signature actually commits to, and those are the ones to carry away: a signed transaction summary that binds neither expiration nor reference block, and a foreign procedure invocation reading state from a prover-chosen reference block rather than the current one. Zero client-reported issues were logged, meaning the findings came from the review rather than from problems the team already knew about.
What should you ask a team that ships a circuit?
- Where is the intended statement written down, and in what form was it given to the reviewers?
- What is inside the verified circuit that does not need to be, starting with hashes?
- What does a signature in this system commit to, and does that include expiration and a reference block?
- Which inputs to a proof are chosen by the prover rather than read from current state?
- If the scheme is recursive, how large is the verifier circuit, since it becomes part of the next one?
- Were any findings client-reported, or did the review surface all of them?
The last question is a cheap signal about process. A review that finds everything itself is telling you the team was not already tracking known problems, which is better than it sounds, because the alternative is a report that counts issues the team had queued anyway.
Questions
- What is an under-constrained circuit?
- A constraint system that accepts witnesses it should reject. Because the proof it produces is genuinely valid for that system, the verifier accepts it correctly, and the result is a valid proof of a statement that is not true — with no error, no exception and no runtime symptom.
- Why is reviewing a circuit harder than reviewing a contract?
- Because there is nothing to observe. A contract bug eventually produces a wrong value or a crash; a missing constraint produces a correct answer to the wrong question. Establishing that the constraints express the intended statement is a specification exercise, and the pool of people who do it well is very small.
- What kinds of finding actually turn up in audits of proof systems?
- In the Miden library review, the medium band was dominated by authorisation rather than arithmetic: permissionless setters, role assignments locked to one account version, unbounded transaction fees, and two findings about what a signature commits to — a summary binding neither expiration nor reference block, and state read from a prover-chosen reference block.
- How does circuit design reduce audit surface?
- By keeping costly machinery out of the proven statement. Symphony avoids embedding a cryptographic hash inside the verified circuits, and NeutronNova keeps the recursive verifier down to three group scalar multiplications and a constant number of hashes, which both shrinks recursion overhead and shrinks what has to be reviewed.