Skip to content

adamreynolds-io/compact-zkir-lint

Repository files navigation

compact-zkir-lint

Your Compact circuit compiled fine. Your tests pass. But the proof server rejects your transaction.

compact-zkir-lint tells you why before your users do.

npx compact-zkir-lint -r contracts/src/artifacts/
  addLiquidity (v2, k=13): 1 error(s)
    instructions: 343  inputs: 5  constrain_bits: 12  cond_select: 8
    guarded regions: 3 (max depth 2)  proof payload: ~384KB
    ERROR [DIV-001] inst 128: constrain_bits(bits=64) on arithmetic in conditional branch (guard=824)

1 error(s) | 4/11 circuits affected

Install and run

# Scan a single circuit
npx compact-zkir-lint circuit.zkir

# Scan all circuits in your compiled artifacts
npx compact-zkir-lint -r contracts/src/artifacts/

# Profile proving time across environments
npx compact-zkir-lint --profile -r contracts/src/artifacts/

# CI-friendly: SARIF output, non-zero exit on errors
npx compact-zkir-lint -r contracts/src/artifacts/ --format sarif > results.sarif

No dependencies on Midnight packages. Reads the .zkir JSON files that the compiler already produces. Works offline.

Benchmark your proof server

Built-in timing estimates are rough. Measure real proving times on your hardware:

# Start a proof server
docker run -d -p 6300:6300 \
  -v $HOME/.cache/midnight/zk-params:/root/.cache/midnight/zk-params \
  ghcr.io/midnight-ntwrk/proof-server:8.0.3

# Generate fixtures and run benchmarks (first time: npm run benchmark:setup)
npm run benchmark -- -o profile.json

# Lint with real timing data
npx compact-zkir-lint --profile --profile-config profile.json -r contracts/src/artifacts/

Measures k=10-16 directly against the proof server, extrapolates k=17-25 from the observed doubling rate. See the circuit profiling guide for output format, payload size limits, and configuration.

What it finds

In ZK circuits, both branches of an if/else execute unconditionally — only the result is selected via cond_select. Constraints inside dead branches fire on invalid intermediate values, causing proof failures that JS testing can't catch.

compact-zkir-lint detects 16 patterns across four categories:

Category Rules Severity
Divergence (DIV-*) DIV-001 through DIV-005 error / warn
Runtime (RT-*) RT-001 through RT-004 warn / info
Statistics (STATS-*) STATS-001, STATS-002 info
Performance (PERF-*) PERF-001 through PERF-006 error / warn / info

See the full rules reference for details, examples, and fix guidance.

How it works

  1. Parses compiled .zkir JSON files (v2 format, zero dependencies)
  2. Builds a data-flow graph: which instruction produces which memory variable
  3. Tracks guard propagation: which variables are inside conditional branches
  4. Memoized zero-analysis: determines if dead-branch values default to zero (safe) vs non-zero (dangerous)
  5. Flags constraint instructions operating on branch-local values before they reach a cond_select merge

Documentation

Acknowledgements

License

Apache-2.0

About

Static analyzer for Compact ZKIR files — detects JS/ZK divergence patterns where compact-runtime succeeds but proof validation fails

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors