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 + Groth16 | Plonkish + KZG-PlonK | |
|---|---|---|
| Library | ark-groth16 | PSE halo2 |
| Curve | BN254 | BN254 |
| Proof size | ~128 bytes (constant) | Larger (scales with circuit) |
| Setup | Per-circuit trusted setup | Universal KZG params (reusable) |
| Verification | Constant time | Logarithmic |
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
- Parse: source code to AST
- IR Lowering: AST to SSA intermediate representation, extracting
public/witnessdeclarations - Optimize:
const_fold,dce,bool_proppasses reduce constraint count - Compile: IR instructions become R1CS constraints or Plonkish table rows
- Witness: concrete input values fill the witness vector/table
- Verify: constraints are checked against the witness (catches bugs before proving)
- 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 valuesvkey.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
- The VM encounters the
prove {}block - Variables from the outer scope are captured —
secretandhashbecome circuit inputs - Int values are automatically converted to field elements (the only place this happens implicitly)
- The block is compiled as a circuit, a witness is generated from captured values, and a proof is produced
- The result is a
ProofObjecton the heap, accessible via native functions
ProveResult
A prove block returns one of:
Proof: containsproof_json,public_json, andvkey_jsonstringsVerifiedOnly: constraints were verified but no proof was generated (verify-only mode)
Proof Object Natives
| Function | Returns | Description |
|---|---|---|
proof_json(p) | String | The proof data (Groth16 or PlonK format) |
proof_public(p) | String | Public inputs as a JSON array of decimal strings |
proof_vkey(p) | String | The 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:
- Evaluate: runs the IR with concrete inputs for early validation. Catches assertion failures, division by zero, and missing inputs before emitting any constraints.
- Compile: lowers IR to constraints, recording a trace of
WitnessOpinstructions as a side effect. - Replay: fills the witness vector by replaying the ops trace with concrete values.
Witness Operations
Each intermediate wire is computed by a recorded operation:
| Op | Description |
|---|---|
AssignLC | Evaluate a linear combination |
Multiply | Multiply two LCs |
Inverse | Compute modular inverse |
BitExtract | Extract the n-th bit from a field element |
IsZero | IsZero gadget: set result and inverse |
PoseidonHash | Compute Poseidon permutation (fills ~360 internal wires) |
Error Handling
The pipeline reports errors at the earliest possible stage:
| Stage | Error | Example |
|---|---|---|
| IR Lowering | Parse/declaration errors | variable 'x' not declared |
| Evaluation | Assertion/arithmetic errors | assert_eq failed: 5 != 6 |
| Compilation | Constraint errors | division by zero |
| Verification | Unsatisfied constraints | constraint 3 failed |
| Proof Generation | Cryptographic errors | Groth16 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