Zero-knowledge security
Zero-knowledge circuit audits — the proof, not just the contract
Most AI auditors stop at your Solidity. AuditAid audits the circuit, prover, and verifier end-to-end — the threat a contract-only review structurally cannot see. It is the first AI system to cover ZK circuit soundness across Circom, Noir, Halo2, and zkVMs.
- Models the malicious prover
- Confirmed by counterexample, not guesswork
- Circuit · prover · verifier in one pass
- Runnable proof-of-concept for every Critical
What we find
The bug classes that actually break zero-knowledge systems
ZK exploits don't look like reentrancy. They live in the gap between what a circuit intends to prove and what it actually constrains — and in the binding between a proof and the context it's spent in. These are the classes AuditAid reasons about explicitly.
Under-constrained signals
The signature ZK bug: a witness value the prover can set freely because no constraint pins it down. We pair every signal against its constraints and confirm a finding by non-uniqueness — two valid witnesses for the same public input — not by a hunch.
The off-chain gap
Checks enforced in the witness generator (JavaScript, Rust, Go) but never re-asserted inside the circuit. A malicious prover skips the generator entirely, so anything not constrained in-circuit is unprotected. We map every off-chain assumption back to its in-circuit constraint — or flag its absence.
Proof replay & forgery
Pairing-equation completeness, public-input binding, and chain / contract / recipient binding. We model whether a valid proof for one context can be replayed in another, including nullifier reuse and missing domain separation.
zkVM program-ID substitution
For SP1 and RISC0, we verify the verifier is bound to the exact program/image ID it should accept. A verifier that checks a proof is valid but not which program produced it will accept a proof from an attacker's substituted program.
Verifier ⇄ circuit drift
The deployed Solidity verifier, the verification key, and the circuit must describe the same statement. We cross-check the on-chain verifier against the circuit's public-input layout so a key/circuit mismatch can't silently widen what gets accepted.
Soundness vs. completeness
We separate "honest proofs fail" (completeness, a liveness bug) from "dishonest proofs pass" (soundness, a fund-loss bug) and prioritize accordingly, with concrete field values for every soundness break.
Coverage
Proof systems and languages we audit
One pipeline spans the modern proving stack — from Groth16 pairings to STARK/FRI and zkVM program binding.
Proof systemsGroth16PLONKUltraHonkFFLONKHalo2Plonky2STARK / FRISP1RISC0
LanguagesCircomNoirHalo2 (Rust)Cairo
How the ZK engine works
From the prover's freedom to a confirmed counterexample
1. Model the malicious prover
We start from the prover's freedom, not the happy path: what can an adversary who controls witness generation make the verifier accept?
2. Constrain-check the whole statement
Every public input and intermediate signal is traced to the constraints that bind it. Unbound or partially-bound values become candidate findings.
3. Confirm by counterexample
Candidate soundness bugs are confirmed with concrete witnesses and minimized field values — and a formal SMT proof where the structure allows it.
4. Cross-check the stack
Circuit, prover, verifier, verification key, and rollup contracts are audited together so cross-layer bugs don't fall through the seams.
Why not a Solidity-only auditor or a static tool?
Auditing the proof requires modeling the prover
A Solidity-only auditor sees the verifier call but not the statement it proves — under-constrained signals and off-chain gaps live in the circuit and witness generator, out of its reach. Narrow formal/static tools (e.g. Veridise Picus, Trail of Bits Circomspect) catch specific patterns but don't reason about the whole statement or the verifier binding. AuditAid models the malicious prover across the full stack and confirms soundness breaks with concrete field values.
Zero-knowledge audit FAQ
What is a zero-knowledge circuit audit?
A ZK circuit audit reviews the circuit, prover, and verifier for soundness and completeness bugs — primarily under-constrained signals, off-chain checks that aren't enforced in-circuit, and proof replay/forgery — rather than just the Solidity that calls the verifier. AuditAid audits the full stack in one pass.
Which proof systems and languages does AuditAid support?
Proof systems: Groth16, PLONK, UltraHonk, FFLONK, Halo2, Plonky2, STARK/FRI, SP1, and RISC0. Languages: Circom, Noir, Halo2 (Rust), and Cairo. It covers circuits, provers, verifiers, and the rollup contracts around them.
How is this different from Picus or Circomspect?
Tools like Veridise Picus and Trail of Bits Circomspect are narrow formal/static analyzers for specific patterns. AuditAid is an AI auditing pipeline that reasons about the whole statement end-to-end — circuit, prover, and verifier — and confirms soundness findings with concrete counterexamples, not just pattern matches.
Why can't a Solidity-only auditor find ZK bugs?
Solidity-only review sees the verifier call but not the statement it proves. Under-constrained signals and off-chain gaps live in the circuit and witness generator, which a contract-level audit structurally cannot inspect. Auditing the proof requires modeling the malicious prover.
Do I get a proof-of-concept for ZK findings?
Yes. For confirmed soundness breaks, AuditAid provides concrete field values and a minimized counterexample (two distinct valid witnesses for the same public input), with a formal SMT proof where the circuit structure supports it.
How much does a ZK circuit audit cost?
The same transparent formula as every AuditAid audit: priced on effective in-scope lines of code (roughly $0.28–$0.30 per line, $50 minimum), with documentation as free context. You see the quote before you pay.