Building a simple ZK project on TON
👋 Introduction
Zero-knowledge (ZK) proofs are a fundamental cryptographic primitive that allows one party (the prover) to prove to another party (the verifier) that a statement is true without revealing any information beyond the validity of the statement itself. Zero-knowledge proofs are a powerful tool for building privacy-preserving systems and have been used in a variety of applications including anonymous payments, anonymous messaging systems, and trustless bridges.
Prior to June 2023 it wasn't possible to verify cryptographic proofs on TON. Due to the prevalence of complex computation behind the pairing algorithm, it was necessary to increase the functionality of TVM by adding TVM opcodes to conduct proof verification. This functionality was added in the June 2023 update and at the time of this writing is only available on testnet.
🦄 This tutorial will cover
- The basics of zero-knowledge cryptography and specifically zk-SNARKs (Zero-Knowledge Succinct Non-Interactive Argument of Knowledge)
- Initiating a trusted setup ceremony (using the Powers of Tau)
- Writing and compiling a simple ZK circuit (using the Circom language)
- Generating, deploying, and testing a FunC contract to verify a sample ZK-proof
🟥🟦 Explaining ZK-proofs with a color-focused example
Before we dig into the details of zero-knowledge, let's start with a simple problem. Suppose you want to prove to a color-blind person that it is possible to distinguish between different colors. We’ll use an interactive solution to solve this problem. Assume the color-blind person (the verifier) finds two identical pieces of paper, with one being red 🟥 and one being blue 🟦.
The verifier shows one of the pieces of paper to you (the prover) and asks you to remember the color. Then the verifier holds that specific piece of paper behind their back and either keeps it the same or changes it and asks you whether the color has changed or not. If you can tell the difference, then you can see colors (or you were just lucky because you had a 50% chance of guessing the correct color).
Now if the verifier completes this process 10 times, and you can tell the difference each time, then the verifier is ~99.90234% (1 - (1/2)^10) confident that the correct colors are being used. Therefore, if the verifier completes the process 30 times, then the verifier will be 99.99999990686774% (1 - (1/2)^30) confident.
Nonetheless, this is an interactive solution and it's not efficient to have a DApp that asks users to send 30 transactions to prove specific data. Therefore, a non-interactive solution is needed; this is where Zk-SNARKs and Zk-STARKs come in.
For the purposes of this tutorial, we’ll only cover Zk-SNARKs. However, you can read more about how Zk-STARKs work on the StarkWare website, while info that compares the differences between Zk-SNARKs and Zk-STARKs can be found on this Panther Protocol blog post.**
🎯 Zk-SNARK: Zero-Knowledge Succinct Non-Interactive Argument of Knowledge
A Zk-SNARK is a non-interactive proof system where the prover can demonstrate to the verifier that a statement is true by simply submitting one proof. And the verifier is able to verify the proof in a very short time. Typically, dealing with a Zk-SNARK consists of three main phases:
- Conducting a trusted setup using a multi-party computation (MPC) protocol to generate proving and verification keys (using Powers of TAU)
- Generating a proof using a prover key, public input, and secret input (witness)
- Verifying the proof
Let's set up our development environment and start coding!
⚙ Development environment setup
Let's begin the process by taking the following steps:
- Create a new project called "simple-zk" using Blueprint by executing the following command, after that, enter a name for your contract (e.g. ZkSimple) and then select the 1st option (using an empty contract).
npm create ton@latest simple-zk
- Next we’ll clone the snarkjs repo that is adjusted to support FunC contracts
git clone https://github.com/kroist/snarkjs.git
cd snarkjs
npm ci
cd ../simple-zk
- Then we’ll install the required libraries needed for ZkSNARKs
npm add --save-dev snarkjs ffjavascript
npm i -g circom
- Next we’ll add the below section to the package.json (note that some of the opcodes that we’ll use are not available in the mainnet release yet)
"overrides": {
"@ton-community/func-js-bin": "0.4.5-tvmbeta.1",
"@ton-community/func-js": "0.6.3-tvmbeta.1"
}
- Additionally, we’ll need to change the version of the @ton-community/sandbox to be able to use the latest TVM updates
npm i --save-dev @ton-community/[email protected]
Great! Now we are ready to start writing our first ZK project on TON!
We currently have two main folders that make up our ZK project:
simple-zk
folder: contains our Blueprint template which will enable us to write our circuit and contracts and testssnarkjs
folder: contains the snarkjs repo that we cloned in step 2
Circom circuit
First let's create a folder simple-zk/circuits
and then create a file in it and add the following code to it:
template Multiplier() {
signal private input a;
signal private input b;
//private input means that this input is not public and will not be revealed in the proof
signal output c;
c <== a*b;
}
component main = Multiplier();
Above we added a simple multiplier circuit. By using this circuit we can prove that we know two numbers that when multiplied together result in a specific number (c) without revealing the corresponding numbers (a and b) themselves.
To read more about the circom language consider having a look at this website.
Next we’ll create a folder for our build files and move the data there by conducting the following (while being in the simple-zk
folder):
mkdir -p ./build/circuits
cd ./build/circuits