-
Notifications
You must be signed in to change notification settings - Fork 15
feat: zero-knowledge proof guide #1398
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
mysteryon88
wants to merge
7
commits into
ton-org:main
Choose a base branch
from
mysteryon88-forks:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+364
−28
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
36cf1a8
docs: ZK-proof guide (Circom, Gnark, Noname, Arkworks + Groth16) for TON
mysteryon88 b6c5650
fix empty string
mysteryon88 120ea98
fixes AI review results and comments
mysteryon88 0ebdb74
Merge branch 'main' into main
mysteryon88 bd7921f
fix npm remark
mysteryon88 d06bb66
Merge branches 'main' and 'main' of github.com:mysteryon88-forks/docs
mysteryon88 5e5dd43
Merge branch 'main' into main
mysteryon88 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,333 @@ | ||
| --- | ||
| title: "Zero-knowledge proofs on TON" | ||
| sidebarTitle: "Zero-knowledge proofs" | ||
| --- | ||
|
|
||
| import { Aside } from '/snippets/aside.jsx'; | ||
|
|
||
| ## Introduction | ||
|
|
||
| This guide shows how to create, compile, and test a simple Circom scheme and verify a **ZK-proof** in the **TON** blockchain using the **zk-SNARK Groth16** protocol. This approach is a starting point for more complex cases and integrations. The examples are based on a minimal multiplication scheme. | ||
|
|
||
| Read more about Circom and zero-knowledge proofs in the [Circom documentation](https://docs.circom.io/). | ||
|
|
||
| <Aside> | ||
| This guide is also applicable to circuits written in the [Noname](https://github.com/zksecurity/noname) language, since the `export-ton-verifier` library integrates with `snarkjs`, which in turn integrates with the Noname language. | ||
|
|
||
| Examples can be found in the [zk-ton-examples](https://github.com/zk-examples/zk-ton-examples/) repository. | ||
| </Aside> | ||
|
|
||
| ## What this guide covers | ||
|
|
||
| - Basic workflow with zero-knowledge proofs in TON. | ||
| - Setting up the environment for ZK in TON. | ||
| - Creating and compiling the Circom scheme. | ||
| - Performing a simplified trusted setup (Groth16). | ||
| - Exporting the verifier for FunC, Tolk, and Tact. | ||
| - Local and on-chain proof verification. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - **Node.js** and **npm** installed | ||
| - **circom** and **snarkjs** installed | ||
| - Basic TON knowledge and Blueprint tool | ||
|
|
||
| ## Project setup | ||
|
|
||
| 1. Create a new project using Blueprint: | ||
|
|
||
| ```bash | ||
| npm create ton@latest ZkSimple | ||
| cd ZkSimple | ||
| ``` | ||
|
|
||
| 2. Install libraries for working with ZK proofs: | ||
|
|
||
| ```bash | ||
| npm install snarkjs @types/snarkjs | ||
| ``` | ||
|
|
||
| 3. Install the verifier export utility for TON: | ||
|
|
||
| ```bash | ||
| npm install export-ton-verifier@latest | ||
| ``` | ||
|
|
||
| This utility exports verifier contracts for FunC, Tolk, and Tact. | ||
|
|
||
| ## Create the Circom circuit | ||
|
|
||
| Create the directory `circuits/Multiplier` and the file `Multiplier.circom`: | ||
|
|
||
| ```bash | ||
| mkdir -p circuits/Multiplier | ||
| cd circuits/Multiplier | ||
| ``` | ||
|
|
||
| ```circom | ||
| pragma circom 2.2.2; | ||
|
|
||
| template Multiplier() { | ||
| signal input a; | ||
| signal input b; | ||
|
|
||
| signal output c; | ||
|
|
||
| c <== a*b; | ||
| } | ||
|
|
||
| component main = Multiplier(); | ||
| ``` | ||
|
|
||
| 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`: | ||
|
|
||
| ```bash | ||
| circom Multiplier.circom --r1cs --wasm --sym --prime bls12381 | ||
| ``` | ||
|
|
||
| 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: | ||
|
|
||
| ```bash | ||
| snarkjs r1cs info Multiplier.r1cs | ||
| ``` | ||
|
|
||
| Output example: | ||
|
|
||
| ``` | ||
| [INFO] snarkJS: Curve: bls12-381 | ||
| [INFO] snarkJS: # of Wires: 4 | ||
| [INFO] snarkJS: # of Constraints: 1 | ||
| [INFO] snarkJS: # of Private Inputs: 2 | ||
| [INFO] snarkJS: # of Public Inputs: 0 | ||
| [INFO] snarkJS: # of Outputs: 1 | ||
| ``` | ||
|
|
||
| <Aside> | ||
| `snarkjs` supports the **altbn-128** and **bls12-381** curves. Altbn-128 is available in Ethereum, but **bls12-381** is used for TON, so it is the one chosen in this guide. | ||
| </Aside> | ||
|
|
||
| ## 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. Parameter (`10`) affects execution time; its selection depends on the size of the scheme - the more constraints, the higher the parameter required. | ||
|
|
||
| ```bash | ||
| # first phase | ||
| snarkjs powersoftau new bls12-381 10 pot10_0000.ptau -v | ||
| snarkjs powersoftau contribute pot10_0000.ptau pot10_0001.ptau --name="First contribution" -v -e="some random text" | ||
|
|
||
| # second phase (depends on the compiled scheme) | ||
| snarkjs powersoftau prepare phase2 pot10_0001.ptau pot10_final.ptau -v | ||
| snarkjs groth16 setup Multiplier.r1cs pot10_final.ptau Multiplier_0000.zkey | ||
| snarkjs zkey contribute Multiplier_0000.zkey Multiplier_final.zkey --name="1st Contributor" -v -e="some random text" | ||
|
|
||
| # export verification key | ||
| snarkjs zkey export verificationkey Multiplier_final.zkey verification_key.json | ||
| ``` | ||
|
|
||
| Clear up unnecessary artifacts: | ||
|
|
||
| ```sh | ||
| rm pot10_0000.ptau pot10_0001.ptau pot10_final.ptau Multiplier_0000.zkey | ||
| ``` | ||
|
|
||
| ## Export the verifier contract | ||
|
|
||
| ```bash | ||
| # export FunC contract (default) | ||
| npx export-ton-verifier ./circuits/Multiplier/Multiplier_final.zkey ./contracts/verifier_multiplier.fc | ||
|
|
||
| # export Tolk contract | ||
| npx export-ton-verifier ./circuits/Multiplier/Multiplier_final.zkey ./contracts/verifier_multiplier.tolk --tolk | ||
|
|
||
| # export Tact contract | ||
| npx export-ton-verifier ./circuits/Multiplier/Multiplier_final.zkey ./contracts/verifier_multiplier.tact --tact | ||
| ``` | ||
|
|
||
| For FunC and Tolk, wrappers must be generated manually: | ||
|
|
||
| ```bash | ||
| npx export-ton-verifier import-wrapper ./wrappers/Verifier.ts --force | ||
| ``` | ||
Kaladin13 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| 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`: | ||
|
|
||
| ```ts | ||
| import * as snarkjs from 'snarkjs'; | ||
| import path from 'path'; | ||
| import { dictFromInputList, groth16CompressProof } from 'export-ton-verifier'; | ||
|
|
||
| // for Tact (After running `npx blueprint build --all`) | ||
| import { Verifier } from '../build/Verifier_tact/tact_Verifier'; | ||
|
|
||
| // for FunC and Tolk | ||
| import { Verifier } from '../wrappers/Verifier'; | ||
| ``` | ||
|
|
||
| Local verification: | ||
|
|
||
| ```ts | ||
| const wasmPath = path.join(__dirname, '../circuits/Multiplier', 'Multiplier.wasm'); | ||
| const zkeyPath = path.join(__dirname, '../circuits/Multiplier', 'Multiplier_final.zkey'); | ||
| const verificationKey = require('../circuits/Multiplier/verification_key.json'); | ||
|
|
||
| const input = { a: '342', b: '1245' }; | ||
|
|
||
| const { proof, publicSignals } = await snarkjs.groth16.fullProve(input, wasmPath, zkeyPath); | ||
| const okLocal = await snarkjs.groth16.verify(verificationKey, publicSignals, proof); | ||
| ``` | ||
|
|
||
| On-chain verification: | ||
|
|
||
| ```ts | ||
| const { pi_a, pi_b, pi_c, pubInputs } = await groth16CompressProof(proof, publicSignals); | ||
|
|
||
| // Quick check via get-method: verifies the proof locally without changing blockchain state. | ||
| expect(await verifier.getVerify({ pi_a, pi_b, pi_c, pubInputs })).toBe(true); | ||
|
|
||
| // Send the proof to the contract in a message | ||
| // The contract will run verification; handling the result/flow is up to the developer using this template. | ||
| await verifier.sendVerify(deployer.getSender(), { pi_a, pi_b, pi_c, pubInputs, value: toNano('0.15') }); | ||
| ``` | ||
mysteryon88 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| <Aside type="tip"> | ||
| Build the contracts before running tests. For Tact contracts, run `npx blueprint build --all` first. For FunC/Tolk, ensure the wrappers are generated. | ||
| </Aside> | ||
|
|
||
| ## Other Languages | ||
|
|
||
| This tutorial follows the path **Circom → snarkjs → export-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](https://github.com/zk-examples/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. | ||
|
|
||
| <Aside> | ||
| Two utilities are available that help convert proofs and verification keys into a format compatible with **snarkjs**: | ||
|
|
||
| - [ark-snarkjs](https://github.com/mysteryon88/ark-snarkjs): use for exporting from **arkworks** | ||
| - [gnark-to-snarkjs](https://github.com/mysteryon88/gnark-to-snarkjs): use for exporting from **gnark** | ||
| </Aside> | ||
|
|
||
| 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: | ||
|
|
||
| ```sh | ||
| cargo init | ||
| cargo add ark-bls12-381 ark-ff ark-groth16 ark-r1cs-std ark-relations ark-snark ark-snarkjs ark-std rand@0.8.5 | ||
| ``` | ||
|
|
||
| <Aside> | ||
| The packages listed above are the core dependencies needed for most arkworks circuits. Depending on the specific circuit implementation, additional packages may be required. | ||
| </Aside> | ||
|
|
||
| 2. 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](https://github.com/arkworks-rs/r1cs-tutorial). A working example of a simple multiplication circuit can be found in the [zk-ton-examples repository](https://github.com/zk-examples/zk-ton-examples/tree/main/circuits/Arkworks/MulCircuit). | ||
|
|
||
| 2. Compile, generate proof, and perform trusted setup following the same workflow as in the Circom section above. | ||
|
|
||
| 2. Export the proof and verification key to JSON using **ark-snarkjs**: | ||
|
|
||
| ```rust | ||
| use ark_snarkjs::{export_proof, export_vk}; | ||
| use ark_bls12_381::{Bls12_381, Fr}; | ||
|
|
||
| let _ = export_proof::<Bls12_381, _>(&proof, &public_inputs, "json/proof.json"); | ||
| let _ = export_vk::<Bls12_381, _>( | ||
| ¶ms.vk, | ||
| public_inputs.len(), | ||
| "json/verification_key.json", | ||
| ); | ||
| ``` | ||
|
|
||
| The directory and files will be created automatically. | ||
|
|
||
| 5. Export the verifier contract: | ||
|
|
||
| ```sh | ||
| # FunC contract | ||
| npx export-ton-verifier ./circuits/Arkworks/MulCircuit/json/verification_key.json ./contracts/verifier_ark.fc | ||
|
|
||
| # Tact contract | ||
| npx export-ton-verifier ./circuits/Arkworks/MulCircuit/json/verification_key.json ./contracts/verifier_ark.tact --tact | ||
|
|
||
| # Tolk contract | ||
| npx export-ton-verifier ./circuits/Arkworks/MulCircuit/json/verification_key.json ./contracts/verifier_ark.tolk --tolk | ||
| ``` | ||
|
|
||
| ### 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](https://github.com/Consensys/gnark?tab=readme-ov-file#example). A working example of a cubic circuit can be found in the [zk-ton-examples repository](https://github.com/zk-examples/zk-ton-examples/tree/main/circuits/Cubic%20%28gnark%29). | ||
|
|
||
| 1. Add **gnark-to-snarkjs** as a dependency: | ||
|
|
||
| ```sh | ||
| go get github.com/mysteryon88/gnark-to-snarkjs@latest | ||
| ``` | ||
|
|
||
| 3. Export the proof and verification key: | ||
|
|
||
| ```go | ||
| { | ||
| proof_out, _ := os.Create("proof.json") | ||
| defer proof_out.Close() | ||
| _ = gnarktosnarkjs.ExportProof(proof, []string{"35"}, proof_out) | ||
| } | ||
| { | ||
| out, _ := os.Create("verification_key.json") | ||
| defer out.Close() | ||
| _ = gnarktosnarkjs.ExportVerifyingKey(vk, out) | ||
| } | ||
| ``` | ||
|
|
||
| 4. Export the verifier contract: | ||
|
|
||
| ```sh | ||
| # Tact contract | ||
| npx export-ton-verifier ./circuits/cubic-gnark/verification_key.json ./contracts/verifier_cubic.tact --tact | ||
|
|
||
| # FunC contract | ||
| npx export-ton-verifier ./circuits/cubic-gnark/verification_key.json ./contracts/verifier_cubic.fc | ||
|
|
||
| # Tolk contract | ||
| npx export-ton-verifier ./circuits/cubic-gnark/verification_key.json ./contracts/verifier_cubic.tolk --tolk | ||
| ``` | ||
|
|
||
| ## 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. | ||
|
|
||
| ## Useful Links | ||
|
|
||
| - Example repository: [zk-ton-examples](https://github.com/zk-examples/zk-ton-examples/) | ||
| - Verifier export library: [export-ton-verifier](https://github.com/mysteryon88/export-ton-verifier) | ||
| - Additional utilities: | ||
| - [ark-snarkjs](https://github.com/mysteryon88/ark-snarkjs) | ||
| - [gnark-to-snarkjs](https://github.com/mysteryon88/gnark-to-snarkjs) | ||
| - Using ZK proofs in Tact: [docs.tact](https://docs.tact-lang.org/cookbook/zk-proofs/) | ||
| - Circom: [docs.circom.io](https://docs.circom.io/) | ||
| - Noname: [zksecurity/noname](https://github.com/zksecurity/noname) | ||
| - Gnark: [Consensys/gnark](https://github.com/Consensys/gnark) | ||
| - Arkworks: [arkworks.rs](https://arkworks.rs/) | ||
| - SnarkJS: [iden3/snarkjs](https://github.com/iden3/snarkjs) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.