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

Proof Generation

Generating and verifying zero-knowledge proofs.

Achronyme generates zero-knowledge proofs natively — no external tools required. Both backends produce real, verifiable proofs using standard cryptographic protocols.

Two Proving Systems

R1CS + Groth16Plonkish + KZG-PlonK
Libraryark-groth16PSE halo2
CurveBN254BN254
Proof size~128 bytes (constant)Larger (scales with circuit)
SetupPer-circuit trusted setupUniversal KZG params (reusable)
VerificationConstant timeLogarithmic

The Pipeline

Whether using the CLI or inline prove {} blocks, the proof pipeline follows the same steps:

Source → Parse → AST → IR → Optimize → Compile → Witness → Verify → Prove
  1. Parse: source code to AST
  2. IR Lowering: AST to SSA intermediate representation, extracting public/witness declarations
  3. Optimize: const_fold, dce, bool_prop passes reduce constraint count
  4. Compile: IR instructions become R1CS constraints or Plonkish table rows
  5. Witness: concrete input values fill the witness vector/table
  6. Verify: constraints are checked against the witness (catches bugs before proving)
  7. Prove: cryptographic proof is generated

CLI: circuit Command

The circuit command compiles a standalone .ach file:

# R1CS (default): compile + witness + export .r1cs/.wtns
achronyme circuit multiply.ach --inputs "x=6,y=7,out=42"

# Plonkish: compile + verify
achronyme circuit multiply.ach --backend plonkish --inputs "x=6,y=7,out=42"

# Plonkish with proof generation
achronyme circuit multiply.ach --backend plonkish --inputs "x=6,y=7,out=42" --prove

R1CS Output Files

With the R1CS backend, the CLI exports two binary files:

  • circuit.r1cs: the constraint system in iden3 format (snarkjs-compatible)
  • circuit.wtns: the witness vector in iden3 format

These can be used directly with snarkjs for Groth16 proof generation:

# Using snarkjs (external)
snarkjs r1cs info circuit.r1cs
snarkjs wtns check circuit.r1cs circuit.wtns
snarkjs groth16 setup circuit.r1cs pot_final.ptau circuit.zkey
snarkjs groth16 prove circuit.zkey circuit.wtns proof.json public.json
snarkjs groth16 verify vkey.json public.json proof.json

Or let Achronyme handle it natively — see the prove {} block section below.

Plonkish Output

With --prove, the Plonkish backend generates:

  • proof.json: the KZG-PlonK proof (hex-encoded bytes)
  • public.json: public input values
  • vkey.json: the verifying key (hex-encoded)

Solidity Verifier

For R1CS/Groth16, you can generate an on-chain verifier:

achronyme circuit multiply.ach --inputs "x=6,y=7,out=42" --solidity Verifier.sol

This produces a Solidity contract that verifies Groth16 proofs for the specific circuit.

Inline: prove {} Blocks

Prove blocks let you generate proofs inline within regular Achronyme programs:

let secret = 42
let hash = 0p18569430475105882...

let p = prove(hash: Public) {
    assert_eq(poseidon(secret, 0), hash)
}

// p is a proof object
print(proof_json(p))
print(proof_public(p))
print(proof_vkey(p))

How Prove Blocks Work

  1. The VM encounters the prove {} block
  2. Variables from the outer scope are capturedsecret and hash become circuit inputs
  3. Int values are automatically converted to field elements (the only place this happens implicitly)
  4. The block is compiled as a circuit, a witness is generated from captured values, and a proof is produced
  5. The result is a ProofObject on the heap, accessible via native functions

ProveResult

A prove block returns one of:

  • Proof: contains proof_json, public_json, and vkey_json strings
  • VerifiedOnly: constraints were verified but no proof was generated (verify-only mode)

Proof Object Natives

FunctionReturnsDescription
proof_json(p)StringThe proof data (Groth16 or PlonK format)
proof_public(p)StringPublic inputs as a JSON array of decimal strings
proof_vkey(p)StringThe verification key

Backend Selection

Prove blocks support both backends:

  • R1CS + Groth16 (default): native via ark-groth16
  • Plonkish + KZG-PlonK: native via halo2

Key Caching

Proof generation requires cryptographic keys (proving key + verifying key). These are expensive to compute, so Achronyme caches them:

  • Location: ~/.achronyme/cache/
  • R1CS (Groth16): cached by a SHA256 hash of the constraint system structure. Same circuit = same keys, even across runs.
  • Plonkish (KZG): universal params cached by k (the log2 of table size). Reusable across different circuits of the same size.

On first run for a new circuit, key generation may take a few seconds. Subsequent runs with the same circuit structure are near-instant.

Witness Generation

The witness is the complete assignment of values to all circuit wires — inputs, intermediates, and outputs. The compiler builds it in three passes:

  1. Evaluate: runs the IR with concrete inputs for early validation. Catches assertion failures, division by zero, and missing inputs before emitting any constraints.
  2. Compile: lowers IR to constraints, recording a trace of WitnessOp instructions as a side effect.
  3. Replay: fills the witness vector by replaying the ops trace with concrete values.

Witness Operations

Each intermediate wire is computed by a recorded operation:

OpDescription
AssignLCEvaluate a linear combination
MultiplyMultiply two LCs
InverseCompute modular inverse
BitExtractExtract the n-th bit from a field element
IsZeroIsZero gadget: set result and inverse
PoseidonHashCompute Poseidon permutation (fills ~360 internal wires)

Error Handling

The pipeline reports errors at the earliest possible stage:

StageErrorExample
IR LoweringParse/declaration errorsvariable 'x' not declared
EvaluationAssertion/arithmetic errorsassert_eq failed: 5 != 6
CompilationConstraint errorsdivision by zero
VerificationUnsatisfied constraintsconstraint 3 failed
Proof GenerationCryptographic errorsGroth16 setup failed

The early evaluation pass is intentional: it catches logical errors before spending time on constraint generation and proving.

Further Reading

  • R1CS — how constraints work in the R1CS backend
  • Plonkish — how the Plonkish backend works
  • Circuit Overview — writing circuits in Achronyme
  • Builtins — built-in circuit functions and their costs
Navigation