Introducing Achronyme — a language for zero-knowledge proofs. Read the announcement arrow_right_alt

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 optional as aliases.
  • import "file.circom" as P — namespaced library imports.
  • Transitive include resolution with cycle detection and canonical-path deduplication.
  • -l/--lib library search flag on ach circom.

Circom language features

  • pragma circom 2.0.x and 2.1.x.
  • signal input, signal output, and intermediate signals.
  • <==, ===, and <-- (with full E100/W101/W102/W103 analysis).
  • template with parameters and signal arrays.
  • component instantiation, including component arrays (component muls[n]).
  • function declarations evaluated at compile time (imperative: var, while, for, if/else, return, ++, *=, nested calls).
  • for loops with constant, parametric, and expression bounds.
  • if/else branching — both branches lowered, branch selection via mux when needed.
  • Compile-time var with 256-bit two’s-complement arithmetic (BigVal), so templates like CompConstant that compute 1 << 128 work 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) where C is 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 + .wtns binary exports that remain snarkjs-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 .ach code (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):

TemplateAchronyme O1circom O2Status
Num2Bits(8)917✓ Achronyme beats circom O2 by 8
Bits2Num(8)1✓ R1CS verified
IsZero()22✓ Matches circom O2
LessThan(8)1020✓ Achronyme beats circom O2 by 10
CompConstant(n)✓ R1CS verified
Poseidon(2)240240✓ Matches circom O2
Pedersen(8)1313✓ Matches circom O2
MiMC(n, nRounds)✓ R1CS verified
MiMCSponge(2, 220, 1)13171320✓ Achronyme beats circom O2 by 3
BabyAdd, BabyDbl, BabyCheck48 (combined)✓ R1CS verified
EscalarMulFix(253)1111✓ Matches circom O2
EscalarMulAny(254)23102310✓ 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

Every unsupported feature below is parsed correctly and rejected with a dedicated error (E2xx) pointing at the offending line, rather than crashing or silently miscompiling. The rationale column explains why the feature is gated today and what would unlock it.

Parsed but rejected in lowering

FeatureErrorRationale
bus declarations (Circom 2.2.0)E205 — “bus types require Circom ≥2.2.0 bus compilation support which is not yet implemented”Adopted by circomlib only sparsely; no circomlib circuit currently shipped in this benchmark requires buses. The lowering mapping is well-defined; work is sequenced after broader circomlib coverage demand emerges.
custom templates (Circom 2.1.0)E205 — “template T is declared as custom which generates Plonk custom gates; custom templates are not supported in R1CS mode”Custom templates compile to Plonk custom gates in reference circom. Achronyme’s Plonkish backend already supports custom gates via halo2, but the .circom → Plonkish lowering path is not yet wired — for today’s circomlib coverage (all R1CS) the restriction has no user-facing cost.
extern_c modifier (Circom 2.2.3+)Parsed as metadata; no lowering code pathReserved for Circom’s experimental FFI escape hatch; no circomlib circuit uses it. Will be addressed if a real need appears.

Not yet parsed

FeatureRationale
Signal tag declarations with semantic meaningsignal s {tagName} parses as a signal with metadata; tags themselves do not influence constraint generation yet. Tags are rarely load-bearing in circomlib.
Anonymous components (Template()(...) inline call without a name binding)Rarely used; the explicit-name form always works.
Array literal as signal assignment (signal z <== [a, b, c])Element-by-element assignment is the documented workaround.

Structural — by design

These restrictions come from Achronyme’s lowering model (fully-unrolled IR, R1CS-first), not from missing work:

  • Recursive function bodies — functions are imperative compile-time evaluators. Non-terminating recursion and recursion whose depth the lowerer cannot prove bounded are rejected at evaluation time.
  • Non-constant array dimensions outside of for-loop unrolling contexts — the IR is statically shaped.
  • Runtime-variable array indices in circuit mode — the IR is fully unrolled, so array indices must be compile-time known. This mirrors the restriction circom itself applies; circomlib follows the same discipline.

If any of these are blocking a real circuit for you, please open an issue with the .circom source — most cases resolve to a structural workaround rather than a language extension.

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 — use Num2Bits(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 .achb persistence. Circom handles and libraries are not yet serialized into the bytecode file, so ach run file.ach works but ach compile file.ach && ach run file.achb does not carry the circom state across processes.
  • No runtime library loading. The circom registry is frozen at compile time. ach run cannot ingest a new .circom file 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 CallCircomTemplate opcode to accept input arrays.
  • Cross-process .achb by serializing CircomHandle and the library registry into the bytecode file.

Open research

  • bus and tag support — 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.

Navigation