jose-compu / jose-compu/opencircom
Feature: `opencircom audit` CLI — static analysis for unsafe circuit configuration
- Dominant language
- Circom
- Stars
- 2
- Forks
- 2
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
Add a CLI command (`npx opencircom audit` or `opencircom audit`) that statically analyzes a project's Circom circuits and flags **misconfigurations and underconstraint patterns** that have caused real-world ZK exploits.
## Motivation
Several high-profile ZK/SNARK incidents stem not from broken crypto primitives but from **bad circuit wiring, default parameters, and missing constraints**:
- **Underconstrained selectors** — e.g. `Switcher.sel` unconstrained (fixed in opencircom 0.5.0 internal audit); similar issues hit multiple DeFi/ZK protocols.
- **Missing range checks** — `Num2Bits` without `StrictNum2Bits` on untrusted indices allowed field-overflow bypasses (`IncrementalMerkleInclusion`, fixed 0.5.0).
- **Unchecked operands** — `DivRem` dividend was unchecked until 0.5.0; attackers can supply out-of-range witnesses.
- **Binary inputs assumed but not enforced** — gates, muxes, path indices; safe only when wrapped correctly.
- **Parameter `n` too small** — using `LessThan(32)` or `StrictNum2Bits(32)` when values are full field elements (254-bit BN254).
- **Signal aliasing** — same witness reused where distinct values are required.
- **Public vs private mismatch** — sensitive values marked public, or roots/commitments not bound on-chain.
- **Nullifier / externalNullifier reuse** — cross-action replay when domain separation is missing.
- **Poseidon width mismatch** — `Poseidon(1)` vs `Poseidon(2)` leaf hashing inconsistent with verifier expectations.
- **Merkle ordering** — left/right child order differs between prover and verifier.
An automated audit step catches these **before** trusted setup and deployment.
## Proposed checks
### Static (parse `.circom` + optional compiled artifacts)
| Check | Severity | Example |
|-------|----------|---------|
| Untrusted input into `Num2Bits(n)` without `StrictNum2Bits` or `RangeProof` | HIGH | index, balance, amount |
| `LessThan(n)` / comparator with `n < 128` on field-sized inputs | HIGH | default `n=32` |
| Selector signals without binary constraint | HIGH | Switcher, Mux, ForceEqualIfEnabled |
| Merkle `pathIndices` not wired through binary-constrained template | MEDIUM | custom tree code |
| `Nullifier` without unique `externalNullifier` binding (heuristic) | MEDIUM | |
| Cross-file Poseidon input-count inconsistency | MEDIUM | |
| Template param defaults below recommended minimums | INFO | |
### Optional (requires compilation)
- Run circom with inspect/constraint dump; flag risky template params.
- Compare public signal count vs expected verifier ABI.
- Detect unconstrained outputs.
## CLI UX (draft)
```bash
npx opencircom audit circuits/MyCircuit.circom \
--include node_modules/opencircom/circuits \
--severity high \
--format json
opencircom audit ./circuits --fail-on high # exit 1 for CI
```
## Implementation notes
- Parse Circom AST or heuristics for v1; iterate to full AST.
- Ship allowlist of opencircom templates that are safe-by-design vs building blocks requiring wrappers.
- Reference internal 0.5.0 audit findings as regression tests.
- Integrate with GitHub Actions as optional job.
## Acceptance criteria
- [ ] `opencircom audit` subcommand documented in README
- [ ] Detects 0.5.0-class issues (binary sel, StrictNum2Bits for indices, DivRem range)
- [ ] CI-friendly exit codes and JSON output
- [ ] Test fixtures: vulnerable vs safe circuit pairs
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.