Limitations and Roadmap
What the Circom frontend supports today, and what is coming next.
The Circom frontend landed in beta.20 and is still growing. This page is the single source of truth for what works now and what is scoped for upcoming releases.
Supported Today
Imports
import circuit "file.circom" as Name— full-circuit absorption.import { T1, T2 } from "file.circom"— selective template imports with optionalasaliases.import "file.circom" as P— namespaced library imports.- Transitive
includeresolution with cycle detection and canonical-path deduplication. -l/--liblibrary search flag onach circom.
Circom language features
pragma circom 2.0.xand 2.1.x.signal input,signal output, and intermediate signals.<==,===, and<--(with full E100/W101/W102/W103 analysis).templatewith parameters and signal arrays.componentinstantiation, including component arrays (component muls[n]).functiondeclarations evaluated at compile time (imperative:var,while,for,if/else,return,++,*=, nested calls).forloops with constant, parametric, and expression bounds.if/elsebranching — both branches lowered, branch selection via mux when needed.- Compile-time
varwith 256-bit two’s-complement arithmetic (BigVal), so templates likeCompConstantthat compute1 << 128work correctly. - 1-D and 2-D compile-time array variables, with row-major flattening and multi-dimensional index resolution.
- Array template parameters (
Template(t, C, 0)whereCis a precomputed array). - Ternary constant-folding so dead-branch array indices like
xL[-1]never reach lowering. - Compile-time-known ternaries select their branch at lowering, avoiding dead-branch references.
Backend output
- R1CS (Groth16) and Plonkish (halo2 KZG PSE fork).
- Constraint counts that match or beat reference Circom 2.x after the O2 optimizer runs.
.r1cs+.wtnsbinary exports that remainsnarkjs-compatible.- Solidity verifier generation for Groth16.
Call sites
prove {}blocks calling selective or namespaced templates.circuit name(...) { ... }declarations calling templates.- VM-mode calls from top-level
.achcode (see VM Mode for restrictions).
Circomlib Coverage
The following circomlib primitives have been compiled end-to-end, run through R1CS generation, and verified against reference implementations. The full constraint-count comparison lives in r1cs_optimization_benchmark in circom/tests/e2e.rs; the condensed table shows Achronyme’s O1 output against circom O2 (circom’s best):
| Template | Achronyme O1 | circom O2 | Status |
|---|---|---|---|
Num2Bits(8) | 9 | 17 | ✓ Achronyme beats circom O2 by 8 |
Bits2Num(8) | 1 | — | ✓ R1CS verified |
IsZero() | 2 | 2 | ✓ Matches circom O2 |
LessThan(8) | 10 | 20 | ✓ Achronyme beats circom O2 by 10 |
CompConstant(n) | ✓ | ✓ | ✓ R1CS verified |
Poseidon(2) | 240 | 240 | ✓ Matches circom O2 |
Pedersen(8) | 13 | 13 | ✓ Matches circom O2 |
MiMC(n, nRounds) | ✓ | ✓ | ✓ R1CS verified |
MiMCSponge(2, 220, 1) | 1317 | 1320 | ✓ Achronyme beats circom O2 by 3 |
BabyAdd, BabyDbl, BabyCheck | 48 (combined) | — | ✓ R1CS verified |
EscalarMulFix(253) | 11 | 11 | ✓ Matches circom O2 |
EscalarMulAny(254) | 2310 | 2310 | ✓ Matches circom O2 |
EdDSAPoseidonVerifier | — | — | ✓ Compile + instantiate (41,136 IR nodes, 263,709 VM instructions); R1CS E2E pending test run |
| Mux, gates, bitify, comparators | — | — | ✓ Used transitively by the above |
End-to-end Groth16 proof verification has been done on-chain for Num2Bits, IsZero, LessThan, Poseidon(2) and EscalarMulAny(254).
Unsupported Circom Features
These are rejected at parse or lowering time with clear errors:
busdeclarations — not yet supported.tagdeclarations — not yet supported.custom_templates— custom gate extensions from Circom 2.1+.- Recursive
functionbodies — functions are evaluated imperatively at compile time, which rules out non-terminating recursion and any recursion whose depth the lowerer cannot prove bounded. - Non-constant array dimensions outside of
for-loop unrolling contexts. - Runtime-variable array indices in circuit mode (the IR is fully unrolled, so array indices must be compile-time known).
If you hit one of these, the error will tell you exactly which feature was rejected and point at the offending line.
VM Mode Limitations
VM mode (calling templates from non-prove code under ach run) is narrower than circuit mode. Phase 4 restrictions:
- Template arguments must be integer literals.
let N = 8; Num2Bits(N)(x)is rejected — useNum2Bits(8)(x)directly until the VM-mode compile-time constant folder lands. - Scalar signal inputs only. Templates with
signal input in[n]cannot be called from VM mode. - No cross-process
.achbpersistence. Circom handles and libraries are not yet serialized into the bytecode file, soach run file.achworks butach compile file.ach && ach run file.achbdoes not carry the circom state across processes. - No runtime library loading. The circom registry is frozen at compile time.
ach runcannot ingest a new.circomfile at runtime.
See VM Mode for the call semantics and why these restrictions exist.
Roadmap
Planned work, in rough priority order:
Phase 5 — Manifest integration (shipped)
The [circom] section in achronyme.toml is live:
[circom]
libs = ["vendor/circomlib/circuits"]
ach run, ach circuit, and ach circom all consume [circom].libs automatically, and CLI -l/--lib flags append to the list rather than replacing it. See Project Configuration.
Phase 6 — Docs and examples (in progress)
Shipped:
- Six-chapter Circom Interop guide in the main docs (you are reading it).
- Full circomlib constraint-count benchmark table (see above).
Pending:
- Worked tutorials (Merkle inclusion with imported Poseidon, EdDSA signature verification).
- Cross-tool benchmarks comparing Achronyme + imported circomlib vs plain circom.
- Migration guide for teams moving existing circom projects.
Phase 4 follow-ups (VM mode)
- Compile-time constant folding so VM-mode template args can be variables as long as they fold.
- Array signal inputs by extending the
CallCircomTemplateopcode to accept input arrays. - Cross-process
.achbby serializingCircomHandleand the library registry into the bytecode file.
Open research
busandtagsupport — mostly a parser + lowering problem; the backend should not need changes.custom_templates— these compile to halo2 custom gates in reference circom; Achronyme’s Plonkish backend already supports custom gates, so this is mostly a lowering mapping.- Broader O2/DEDUCE coverage so templates that currently match circom O1 can drop further when DEDUCE’s Gaussian elimination finds additional linear constraints to fold.
Long-term
- Noir frontend. The same dual-frontend approach (parse → lower → ProveIR) that makes Circom interop work would let Achronyme absorb Noir programs as well. No commitment yet — tracked as research.
- STARK backend for Goldilocks. Not Circom-specific, but relevant since some circomlib templates (MiMC variants, Poseidon with
α=7) are a natural fit for Goldilocks once a STARK backend exists.
The project roadmap page tracks the same items at a higher level; project manifest integration will be updated once the [circom] section lands.