This tutorial will guide you through the process of creating and validating your first zero-knowledge SNARK circuit using circom and snarkJS.

â€‹Installing the toolsâ€‹

â€‹My first circuitâ€‹

â€‹Bonus trackâ€‹

First, you need to install `Node.js`

. To get a better performance, it is important that you install version 10 or higher. This is because last versions of `Node.js`

include big integer support and web assembly compilers that help run code faster.

Then, install `circom`

and `snarkJS`

. You can do it running the following commands:

npm install -g circomnpm install -g snarkjs

Let's create a circuit that will allow you to prove that you are able to factor a number.

Create an empty directory called

`factor`

where you will put all the files.

mkdir factorcd factor

In a real circuit, we recommend you to create a

`git`

repository with a`circuits`

directory and a`test`

directory with all your tests, and the needed scripts to build all the circuits.

2. Create a new file named `circuit.circom`

with the following content:

template Multiplier() {signal private input a;signal private input b;signal output c;c <== a*b;}â€‹component main = Multiplier();

This circuit has two private input signals named `a`

and `b`

and one output named `c`

. The circuit named `Multiplier`

circuit forces the signal `c`

to be the result of the multiplication `a*b`

. After declaring the template `Multiplier`

, we need to instantiate it with a component named `main`

.

When compiling a circuit a component named `main`

must always exist.

3. We are now ready to **compile** the circuit. Run the following command:

circom circuit.circom --r1cs --wasm --sym

With these options we generate three types of files:

`--r1cs`

: it generates the file`circuit.r1cs`

that contains the R1CS constraint system of the circuit in binary format.`--wasm`

: it generates the file`circuit.wasm`

that contains the`Wasm`

code to generate the witness.`--sym`

: it generates the file`circuit.sym`

, a symbols file required for debugging or for printing the constraint system in an annotated mode.

Now that the circuit is compiled, we will use `snarkJS`

to generate and validate zk-SNARK proofs. More specifically, **we will prove that we are able to factor the number 33**. That is, we will show that we know two integers `a`

and `b`

such that when we multiply them, it results in 33.

You can always access the **help** of`snarkJS`

by typing the command

`$ snarkjs --help`

With

`snarkJS`

, you can get general**statistics**of the circuit and print the**constraints**. Just run:

snarkjs info -c circuit.r1cssnarkjs print -r circuit.r1cs -s circuit.sym

2. To generate and verify zk-SNARK proofs, it is required to have a **setup**.

The generation of the setup has two phases: the first step consists in the creation of some values known as **powers of tau**. For this tutorial we will keep a simple "powers of tau" file. Run the following commands:

// Start a new powers of tau ceremony and make a contributionâ€‹snarkjs powersoftau new bn128 12 pot12_0000.ptau -vsnarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau --name="First contribution" -v

You will be prompted to **enter some random text** that will be used as source of entropy. Once you have entered you text, the commands will output a transcript named `pot12_001.ptau`

. This first part of the setup is generic and useful to any circuit, so you can save it to reuse it in future projects.

The generation of the **setup** is necessary to obtain the proving and verification keys of zk-SNARK proofs. This step requires the generation of some random values that need to be eliminated. This elimination process is crucial: if these values are ever exposed, the security of the whole scheme is compromised.

To construct the setting, we use a multi-party computation (MPC) ceremony that allows multiple independent parties to collaboratively construct the parameters. With MPC, it is enough that **one single participant deletes its secret **counterpart of the contribution in order to keep the whole scheme secure.

The construction of the trusted setup has two phases: a general MPC ceremony that is valid for any circuit (known as **powers of tau ceremony**), and a second phase (**phase 2**) that is constructed for each specific circuit. Anyone can contribute with their randomness to the MPC ceremonies and typically, before getting the final parameters, a random beacon is applied.

For the sake of simplicity, we generated a setup with only one contribution without giving all the details. If you want to deepen into robust setups with multiple contributions:

You can download the file

`powersOfTau28_hez_final.ptau`

, which contains 54 contributions and a final random beacon, and use it to import and export challenges.If you want to run your own MPC ceremonies or learn about generating trusted setups with

`snarkJS`

, we recommend you to follow this other tutorial.

The next step, which is called **phase 2** of the setup, is **circuit-specific**. First, we have to prepare the phase running the command:

snarkjs powersoftau prepare phase2 pot12_0001.ptau pot12_final.ptau -v

The generation of phase 2 is similar to what we did with powers of tau. In this case, we will generate a `.zkey`

file that will contain the proving and verification keys together with all phase 2 contributions.

// Start a new zkey and make a contributionâ€‹snarkjs zkey new circuit.r1cs pot12_final.ptau circuit_0000.zkeysnarkjs zkey contribute circuit_0000.zkey circuit_final.zkey --name="1st Contributor Name" -v

As before, you will be prompted to enter some random text to provide a source of entropy. The output will be a file named `circuit_final.zkey`

, which we will use to **export the verification key**.

snarkjs zkey export verificationkey circuit_final.zkey verification_key.json

Now, the verification key from `circuit_final.zkey`

is exported into the file `verification_key.json`

.

You can always **verify** that the computations of a `.ptau`

or a `.zkey`

file are correct:

snarkjs powersoftau verify pot12_final.ptausnarkjs zkey verify circuit.r1cs pot12_final.ptau circuit_final.zkey

If everything checks out, you should see the following at the top of the output:

[INFO] snarkJS: Powers of Tau file OK![INFO] snarkJS: ZKey OK!

â€‹âš The command `snarkjs zkey verify`

also checks that the `.zkey`

file corresponds to the specific circuit.

3. Once the setup is ready, we **compute a** **witness** for the circuit.

Before creating any proof, we need to calculate all the signals of the circuit that match all the constraints of the circuit. For that, we will use the `Wasm`

module generated by`circom`

that helps do this job. We simply need to provide a file with the inputs and the module will execute the circuit and calculate all the intermediate signals and the output. The set of inputs, intermediate signals and output is called witness.

In our case, we want to prove that we able to factor the number 33. So, we assign `a = 3`

and `b = 11`

.

Note that we could assign the number 1 to one of the inputs and the number 33 to the other. So, our proof does not really show that we are able to factor the number 33. At the end of this section, we will add few modifications to the circuit to deal with this problem.

We need to create a file named `input.json`

with the inputs.

{"a": 3, "b": 11}

Now, we calculate the witness and generate a file `witness.wtns`

with the result.

snarkjs wtns calculate circuit.wasm input.json witness.wtns

4. Once the witness is computed, we can **generate a zk-proof **associated to the circuit and the witness.

snarkjs groth16 prove circuit_final.zkey witness.wtns proof.json public.json

This command generates a proof (Groth16 is a specific zk-SNARK protocol) and outputs two files:

`proof.json`

: it contains the zk-SNARK proof.`public.json`

: it contains the values of the public inputs and outputs.

5. To **verify the proof**, run:

snarkjs groth16 verify verification_key.json public.json proof.json

This command uses the files `verification_key.json`

we exported earlier,`proof.json`

and `public.json`

to check if the proof is valid. If the proof is valid, the command outputs an `OK`

.

A valid proof not only proves that we know a set of signals that satisfy the circuit, but also that the public inputs and outputs that we use match the ones described in the `public.json`

file.

â€‹ðŸ‘‰ It is also possible to generate a **solidity verifier** that allows **verifying proofs on Ethereum blockchain**.

First, we need to generate the solidity code using the command:

snarkjs zkey export solidityverifier circuit_final.zkey verifier.sol

This command takes validation key `circuit_final.zkey`

and outputs solidity code in a file named `verifier.sol`

. You can take the code from this file and cut and paste it in Remix. You will see that the code contains two contracts: `Pairing`

and `Verifier`

. You only need to deploy the `Verifier`

contract.

You may want to use first a testnet like Rinkeby, Kovan or Ropsten. You can also use the JavaScript VM, but in some browsers the verification takes long and the page may freeze.

The `Verifier`

has a `view`

function called `verifyProof`

that returns `TRUE`

if and only if the proof and the inputs are valid. To facilitate the call, you can use `snarkJS`

to generate the parameters of the call by typing:

snarkjs generatecall

Cut and paste the output of the command to the parameters field of the `verifyProof`

method in Remix. If everything works fine, this method should return `TRUE`

. You can try to change just a single bit of the parameters, and you will see that the result is verifiable `FALSE`

.

We have shown that it is possible to generate a proof that shows that we know two factors `a`

and `b`

such that `a*b = 33`

. But this does not prove that we know how to factor the number 33, as we could have chosen `a = 1`

and `b = 33`

and in general, for any integer `n`

, choose inputs `a = 1`

, `b = n`

.

In this section, we will modify the circuit so that it is not possible to assign the number 1 to any of the inputs. To do so, we will use the fact that **0 is the only number with no inverse**.

ðŸ‘‰ Our arithmetic circuits consist of signals that live in the finite field $\mathbb{F}_p$, where $p$ is this prime number. In this field, the only element that has no inverse is the number 0.

For example, if we want to impose `a != 1`

, we can impose, equivalently, that `(a-1) != 0`

, which is true if and only if `(a-1)`

has no inverse. This condition can be translated in terms of constraints: if we define a new variable `inva`

that is the inverse of `a`

, then the condition `(a-1)*inva = 1`

can only be satisfied if `a != 1`

. The inverse `inva`

can easily be calculated doing `1/(a-1)`

.

Let's modify the circuit according to this:

template Multiplier() {signal private input a;signal private input b;signal output c;signal inva;signal invb;â€‹inva <-- 1/(a-1);(a-1)*inva === 1;â€‹invb <-- 1/(b-1);(b-1)*invb === 1;â€‹c <== a*b;}â€‹component main = Multiplier();

Note that the calculation of the inverse `1/(a-1)`

is done using the simple arrow `<--`

instead of the double arrow `<==`

. The reason for this, is that the double arrow gathers two actions together:

`<--`

: assign a value to a signal without creating any constraint.`===`

: add a constraint without assigning any value to any signal.

The operation `1/(a-1)`

does not have the form of a constraint (it is not linear nor quadratic), so we have to use `<--`

to assign a value and then manually add the constraint `(a-1)*inva === 1`

to ensure a constraint that captures the previous assignment.

You can read more about the difference between constraints and calculation assignments in the section Signals > Assignment to Signals.

**Note: **The circuit still has another problem. Since the operations work in $\mathbb{F}_p$, we should guarantee that the multiplication does not overflow. This can be done by converting the signals to binary and checking that the values are in the range ` 0...(p-1)`

. This fix is quite complex, so we keep it for further tutorials.