Guide
Under-constrained circuits
The failure where the proof is valid and the statement is false. Zero-knowledge systems fail quietly, and the verifier agrees.
In short
- A circuit is a set of constraints, not a program. A missing constraint does not cause an error; it permits a value that should have been impossible.
- The result is a valid proof of a false statement. Nothing reverts, nothing looks wrong, and the verifier contract is correct to accept it.
- Soundness and completeness fail in opposite directions. A completeness bug blocks honest users and is found immediately; a soundness bug admits dishonest ones and may never be noticed.
- The reviewer pool for this is a fraction of the Solidity pool, and the tooling is a decade younger. That is why the work costs what it does.
A circuit is not a program
Ordinary code describes steps. A circuit describes conditions that must hold, and the proving system searches for values satisfying all of them. The output is a proof that such values exist, and the verifier checks the proof rather than re-running anything.
That inversion is where the difficulty lives. In ordinary code, forgetting a check means a bad input reaches the next line and something downstream usually misbehaves. In a circuit, forgetting a constraint means the set of acceptable values is larger than intended, and every value in that larger set produces a proof the verifier will accept as valid.
In plain terms: the bug is not something the system does wrong. It is something the system was never told to forbid.
Why nothing looks broken
The verifier is correct. The proof is genuine. The mathematics holds.
What has happened is that the statement being proved is weaker than the one the designers believed they had written. The circuit proves that the constraints were satisfied, and if those constraints do not pin down the behaviour, the proof carries less meaning than the system relies on.
There is no revert, no failed transaction and no anomalous event. A system accepting these proofs sees a stream of valid operations. Monitoring built on failure signals sees nothing at all, because nothing fails.
In plain terms: a proof verifying is not the same as a proof being about what you think it is about. Everything downstream treats those as identical.
How constraints go missing
Unconstrained intermediate signals. A value computed during the circuit but never tied to anything the constraints check. The prover may assign it freely, and a free variable in the middle of a computation usually means the output can be steered.
Missing range checks. Field arithmetic wraps at the field modulus rather than overflowing as integers do. A value intended to be a small number, unconstrained, may be enormous, and a sum that should be impossible becomes arithmetically fine inside the field.
Under-constrained division and inverses. Division is expressed as multiplication by an inverse, and the inverse has to be constrained to actually be one. Without that, a prover can supply a value that satisfies the stated relation while meaning something else entirely.
Non-deterministic witnesses. Where more than one witness satisfies the constraints for a given public input, the prover chooses which, and the choice may be the difference between an honest operation and a double spend.
In plain terms: each of these is a question the circuit forgot to ask, and the prover is the party that benefits from it never being asked.
Soundness and completeness
Two properties, and they fail in opposite directions. The distinction decides which bugs you find in testing and which you find in production.
Completeness means every honest operation can produce a proof. A completeness failure blocks legitimate users, surfaces during integration, and gets fixed before launch because it is loud.
Soundness means no dishonest operation can produce one. A soundness failure admits operations that should have been impossible, and it produces no complaint from anyone — the party exploiting it is satisfied, and nobody else can tell.
In plain terms: a completeness bug announces itself and a soundness bug does not. Testing finds the first reliably and the second only if someone deliberately looks for it, which is the entire argument for a review by someone who reads the constraints rather than the behaviour.
The parts around the circuit
A circuit sits inside a system, and the surrounding pieces carry their own assumptions.
The trusted setup, where the scheme requires one, generates parameters whose secret inputs must be destroyed. If any participant retained theirs, they can forge proofs indefinitely and the forgery is undetectable. A ceremony is sound if at least one participant was honest, which is why they are run with many participants and published in detail — a setup nobody can verify is a soundness assumption resting on a promise.
The verifier contract is ordinary on-chain code with ordinary risks: a verifying key that can be replaced by a privileged role, a public-input encoding that differs from what the circuit expects, a proof accepted without checking which circuit it belongs to.
Nullifiers and replay. A system proving a thing happened once needs a value preventing the same proof being used twice, and that value has to be bound to the right inputs and recorded in a way an upgrade cannot reset.
And randomness. Where a protocol depends on an unpredictable value, its source is a trust assumption of the same weight as any oracle.
Why this review costs more
Three structural reasons, and none of them is opportunistic pricing.
The reviewer pool is small. Reading constraint systems is a different skill from reading Solidity, closer to applied cryptography than to software engineering, and the number of people who can do it competently is a fraction of the number who can review a contract.
The tooling is young. Contract review has a decade of static analysers, fuzzers and invariant frameworks behind it. Circuit tooling is improving quickly and still leans far harder on a person reasoning about what the constraints permit.
And the failure mode resists testing. A soundness bug does not appear in a test suite unless someone constructs the malicious witness that exploits it, which requires already suspecting it exists.
In plain terms: if you are quoted the same figure for a circuit as for an equivalent contract, that is worth a question.
What to ask of your own system
Five questions. Your circuit engineers will have views on all of them.
Which signals are computed but not constrained, and what would a prover gain by choosing them freely?
Where do we assume a value is small, and is that assumption expressed as a range check or only in our heads?
Is every witness for a given public input unique, and if not, what does the choice change?
If the scheme needed a trusted setup, whose ceremony was it, how many participants, and is the transcript published?
Can the verifying key be replaced, and by whom? That is an access-control question wearing cryptographic clothes.
Questions
Does a passing test suite tell us the circuit is sound?
It tells you the circuit is complete: honest inputs produce proofs. Soundness is the claim that dishonest inputs cannot, and a test suite only demonstrates that for the dishonest inputs somebody thought to write.
Does using an established proving framework remove this risk?
It removes a layer of it. The proving system and its implementation are far better reviewed than any individual circuit, so the residual risk concentrates in the constraints you wrote, which is exactly where under-constraint lives.
Can monitoring detect an under-constrained circuit being exploited?
Generally no, and this is the class where that answer is cleanest. Exploitation produces valid proofs and successful transactions. Where it shows up at all, it shows up as an economic discrepancy — a supply that does not reconcile — rather than as a security event.
Is formal verification the answer here?
It is a strong tool for this class, because the question is whether the constraints imply the intended property, which is the shape of question formal methods address. It does not remove the need for someone to state what the intended property is, and getting that statement wrong is its own failure.
The work behind this
ZK and cryptography audit
Zero-knowledge circuits, proving systems and custom cryptography reviewed by people who read the maths.
Formal verification
Mathematical proof that a critical property holds for every reachable state, not just the tested ones.
L1 and L2 infrastructure audit
Consensus, client code, validator economics, sequencers and proof systems.
Related reading
Guide
What audits a bridge protocol needs
A bridge is several systems that have to agree, and most of them are not the contracts. What to commission, what each engagement covers, and the order that makes each one cheaper than the last.
Guide
Bridge trust assumptions
The highest aggregate losses in the industry, and mostly not contract bugs. A bridge is an agreement between systems that cannot check each other.
Guide
How protocols lose money
The defect classes that actually cost funds, organised by what the attacker is doing rather than by what the bug is called.