Skip to main content
This guide shows how to create, compile, and test a simple Circom scheme and verify a ZK-proof using the zk-SNARK Groth16 protocol.

Prerequisites

Project setup

  1. Create a new project using Blueprint:
  2. Install libraries for working with ZK-proofs:
  3. Install the verifier export utility for TON:
This utility exports verifier contracts for FunC, Tolk, and Tact.

Create the Circom circuit

Create the directory circuits/Multiplier and the file Multiplier.circom:
This circuit proves knowledge of two numbers a and b, whose product is equal to the public output c, without revealing a and b themselves.

Compile

Run in circuits/Multiplier:
After compilation, the following files will appear:
  • Multiplier.r1cs — circuit constraints (R1CS)
  • Multiplier.sym — symbolic signal map
  • Multiplier.wasm — artifact for generating proof
Check constraints:
Output example:

Trusted setup (Groth16)

The trusted setup is a one-time ceremony that generates the proving and verification keys for a circuit. It’s called “trusted” because if the setup parameters are compromised, proofs could be forged. For production use, participate in a multi-party trusted setup ceremony. For local development and testing, a simplified single-party setup is sufficient. For local tests, perform a simplified trusted setup ceremony. The “power of tau” parameter (10) has to be chosen
  • as low as possible, because it affects execution time;
  • high enough, because the more constraints in the scheme, the higher the parameter required.
Clear up unnecessary artifacts:

Export the verifier contract

For FunC and Tolk, wrappers must be generated manually:
This command generates a TypeScript wrapper file that provides type-safe methods to interact with the verifier contract.

Testing and verification

In tests/ZkSimple.spec.ts:
Local verification:
On-chain verification:

Other Languages

This tutorial follows the path Circom → snarkjsexport-ton-verifier → TON. The same workflow applies to other stacks — the key requirement is to obtain a proof and a verification key in snarkjs format. In the example repository — zk-ton-examples — there are already templates for noname, gnark, and arkworks: proofs can be generated in any of these stacks, then converted into snarkjs format and verified both locally and on-chain in the same way. The idea is always the same: generate proof.json and verification_key.json in snarkjs format, then use export-ton-verifier and perform verification in TON.

Arkworks (Rust)

Use the arkworks library to generate the proof and verification key, then convert them into snarkjs format with ark-snarkjs.
  1. Set up an Arkworks project:
  1. Write the circuit in Rust. Implement the circuit logic using arkworks primitives, similar to how a Circom circuit would be written. Learn how to write constraints in arkworks by following the Arkworks R1CS tutorial. A working example of a simple multiplication circuit can be found in the zk-ton-examples repository.
  2. Compile, generate proof, and perform trusted setup following the same workflow as in the Circom section above.
  3. Export the proof and verification key to JSON using ark-snarkjs:
The directory and files will be created automatically.
  1. Export the verifier contract:

gnark (Go)

Use the gnark library to generate the proof and verification key, then convert them into snarkjs format with gnark-to-snarkjs.
  1. Set up a gnark project. You can find an example circuit in the gnark repository. A working example of a cubic circuit can be found in the zk-ton-examples repository.
  2. Add gnark-to-snarkjs as a dependency:
  1. Export the proof and verification key:
  1. Export the verifier contract:

Conclusion

This guide demonstrates a minimal example: circuit → trusted setup → verifier export → verification in TON. This workflow can be extended to support more complex circuits and real-world applications.