Constraint Mistakes
Errors in circuit constraints.
Underconstrained signals
Signals that do not appear in any constraint let provers choose arbitrary values. This breaks the entire proof.
Missing boolean constraints
Treating a signal as boolean without constraining it to 0 or 1. Field elements have many other values.
Forgetting to constrain array indices
Array lookups where the index is not constrained to valid range.
Incomplete Merkle proof verification
Not constraining every step of Merkle path or getting left/right ordering wrong.
Arithmetic Mistakes
Finite field arithmetic errors.
Field overflow assumptions
Assuming arithmetic works like integers. Field arithmetic wraps at the modulus.
Division by zero
Not checking that denominators are non-zero before division.
Square root non-uniqueness
Field elements have two square roots. Not specifying which one is expected.
Bit decomposition reconstruction mismatch
Decomposing to bits but not constraining that bits reconstruct to original value.
Cryptographic Primitive Mistakes
Errors using hashes and signatures.
Unconstrained hash inputs
Hash inputs that are not fully constrained allow hash manipulation.
Partial signature verification
Verifying only part of a signature or not including the message.
Non-deterministic nullifier derivation
Nullifiers that can be computed multiple ways for the same underlying item.
Invalid curve point acceptance
Not validating that public keys are valid points on the curve.
Setup and Verification Mistakes
Errors in proof system setup and verification.
Single-party trusted setup
Using setup parameters generated by one party. That party can create fake proofs.
Reusing proving keys across circuits
Using the same proving key for different circuits.
Public input ordering mismatch
Public inputs ordered differently between prover and verifier.
Missing replay protection
Proofs that can be replayed to repeat an action.
Application Integration Mistakes
Errors connecting ZK proofs to applications.
Proof not bound to action
Proof proves something but does not specify what action it authorizes.
Not storing used nullifiers
Accepting proofs without recording their nullifiers.
Client-generated proofs without validation
Accepting proofs from clients without validating the public inputs make sense.
Performance and Implementation Mistakes
Errors causing inefficiency or bugs in production.
Unnecessary constraint multiplication
Using multiplications in constraints where additions suffice.
No witness generation timeout
Witness computation without time limits can hang indefinitely.
Inconsistent endianness
Mixing big and little endian in bit operations.
Memory exhaustion on large inputs
Circuits that allocate based on input size without limits.
Debug code in production circuits
Leaving console logs or debug constraints in deployed circuits.
Hardcoded test values
Test private keys or constants left in production code.
Testing and Auditing Mistakes
Errors in verification and quality assurance.
Only testing happy path
Testing only valid proofs without testing rejection of invalid ones.
No formal verification
Relying solely on manual review for critical circuits.
Insufficient test coverage for edge cases
Not testing boundary values and special cases.
Not testing across proof systems
Assuming circuit behaves identically across Groth16, PLONK, etc.
Ignoring compiler warnings
Dismissing Circom or other compiler warnings as noise.
Key Recommendations
If in doubt, add more constraints. Under-constrained circuits are the most dangerous bugs.
Use formal verification for critical circuits. Manual review alone is insufficient.
Keep circuit complexity low. Simpler circuits are easier to audit and prove.