OpenZeppelin / OpenZeppelin/compact-contracts
dev: check @circuitInfo annotations against the compiled k/rows
@0xisk is already working on this.
Since Jul 29, 2026.
- Dominant language
- TypeScript
- Stars
- 55
- Forks
- 29
- Avg merge
- 5d 7h
- Merged PRs (30d)
- 25
Description
🧐 Motivation
Every circuit in the repo carries a hand-maintained @circuitInfo k=…, rows=… annotation, and nothing checks it. A refactor that changes a circuit's cost leaves the annotation stale, silently. Reviewers and audit readers treat those numbers as fact, and a k bump is the number that matters most: it doubles proving cost and moves a circuit toward the block and proving limits.
There is no test for this today because the numbers aren't in the artifact. Confirmed by inspection, not assumption:
| number | compiler/contract-info.json |
zkir/*.zkir |
zkir/*.bzkir |
keys/* |
|---|---|---|---|---|
names, pure, proof, ABI |
✅ | — | — | — |
| k | ❌ | ❌ | ❌ | only inferable from prover-key size |
| rows | ❌ | ❌ | ❌ | ❌ |
bzkir headers start midnight:ir-source and prover keys midnight:prover-key[; neither encodes k. Verifier keys are a constant 2119 bytes across every circuit. k can be recovered from prover-key size (size / 2^k lands in 297.9–344.8 against 2× per k step), but that is a constant fitted to a serialization format we don't own.
📝 The data already exists
@openzeppelin/compact-builder already solves the hard part. CompilerService spawns compact under a PTY via script — because compactc only renders the constraint table to a terminal — and Compiler.js parses it and calls writeCircuitInfoJson, producing .circuit-info.json beside the sources:
{
"generatedAt": "2026-07-27T13:07:56.652Z",
"files": {
"MockFungibleToken.compact": [
{ "name": "_approve", "k": 11, "rows": 1409 },
{ "name": "_transfer", "k": 12, "rows": 2192 }
]
}
}
Eight such files exist across contracts/src/** today. So nothing needs to be produced — it needs to be checked.
Two properties of that file shape the design:
- it is written only on a full compile, since k and rows come from the ZK pass (
--skip-zkyields only theCompiling N circuits:header) - it is gitignored (
.gitignore:28), so it is a build product with no committed baseline
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.