Proof Generation
Achronyme generates zero-knowledge proofs natively — no external tools required. Both backends produce real, verifiable proofs using standard cryptographic protocols.
Two Proving Systems
Section titled “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
Section titled “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
Section titled “CLI: circuit Command”The circuit command compiles a standalone .ach file:
# R1CS (default): compile + witness + export .r1cs/.wtnsachronyme circuit multiply.ach --inputs "x=6,y=7,out=42"
# Plonkish: compile + verifyachronyme circuit multiply.ach --backend plonkish --inputs "x=6,y=7,out=42"
# Plonkish with proof generationachronyme circuit multiply.ach --backend plonkish --inputs "x=6,y=7,out=42" --proveR1CS Output Files
Section titled “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.r1cssnarkjs wtns check circuit.r1cs circuit.wtnssnarkjs groth16 setup circuit.r1cs pot_final.ptau circuit.zkeysnarkjs groth16 prove circuit.zkey circuit.wtns proof.json public.jsonsnarkjs groth16 verify vkey.json public.json proof.jsonOr let Achronyme handle it natively — see the prove {} block section below.
Plonkish Output
Section titled “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
Section titled “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.solThis produces a Solidity contract that verifies Groth16 proofs for the specific circuit.
Inline: prove {} Blocks
Section titled “Inline: prove {} Blocks”Prove blocks let you generate proofs inline within regular Achronyme programs:
let secret = 42let hash = 0p18569430475105882...
let p = prove(hash: Public) { assert_eq(poseidon(secret, 0), hash)}
// p is a proof objectprint(proof_json(p))print(proof_public(p))print(proof_vkey(p))How Prove Blocks Work
Section titled “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
Section titled “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
Section titled “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
Section titled “Backend Selection”Prove blocks support both backends:
- R1CS + Groth16 (default): native via ark-groth16
- Plonkish + KZG-PlonK: native via halo2
Key Caching
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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