circom/TUTORIAL.md
TUTORIAL.mdRaw
1# circom and snarkjs tutorial
2
3This tutorial will guide you in creating your first zero-knowledge SNARK circuit. It will take you through the various techniques to write circuits and show you how to create and verify proofs off-chain and on-chain on Ethereum.
4
5## 1. Installing the tools
6
7### 1.1 Pre-requisites
8
9If you don't have it installed yet, you need to install `Node.js`.
10
11The last stable version of `Node.js` (or 8.12.0) works just fine, but if you install the latest current version `Node.js` (10.12.0) you will see a significant increase in performance. This is because last versions of node includes Big Integer Libraries nativelly. The `snarkjs` library makes use of this feature if available, and this improves the performance x10 (!).
12
13### 1.2 Install **circom** and **snarkjs**
14
15Run:
16
17```sh
18npm install -g circom
19npm install -g snarkjs
20```
21
22
23## 2. Working with a circuit
24
25Let's create a circuit that will allow you to prove that you are able to factor a number!
26
27### 2.1 Create a circuit in a new directory
28
291. Create an empty directory called `factor` where you will put all the files that you will use in this tutorial.
30```
31mkdir factor
32cd factor
33```
34
35
36> In a real circuit, you will probably want 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.
37
382. Create a new file named `circuit.circom` with the following content:
39
40```
41template Multiplier() {
42 signal private input a;
43 signal private input b;
44 signal output c;
45
46 c <== a*b;
47}
48
49component main = Multiplier();
50```
51
52This circuit has 2 private input signals named `a` and `b` and one output named `c`.
53
54The only thing that the circuit does is forcing the signal `c` to be the value of `a*b`
55
56After declaring the `Multiplier` template, we instantiate it with a component named`main`.
57
58Note: When compiling a circuit, a component named `main` must always exist.
59
60### 2.2 Compile the circuit
61
62We are now ready to compile the circuit. Run the following command:
63
64```sh
65circom circuit.circom --r1cs --wasm --sym
66```
67
68The `--r1cs` option will generate `circuit.r1cs` (the r1cs constraint system of the circuit in binary format).
69
70The `--wasm` option will generate `circuit.wasm` (the wasm code to generate the witness).
71
72The `--sym` option will generate `circuit.sym` (a symbols file required for debugging or if you want to print the constraint system in an annotated mode).
73
74
75## 3. Taking the compiled circuit to *snarkjs*
76
77Now that the circuit is compiled, we will continue with `snarkjs`.
78Please note that you can always access the help of `snarkjs` by typing:
79
80```sh
81snarkjs --help
82```
83
84### 3.1 View information and stats regarding a circuit
85
86To show general statistics of this circuit, you can run:
87
88```sh
89snarkjs info -r circuit.r1cs
90```
91
92You can also print the constraints of the circuit by running:
93
94```sh
95snarkjs printconstraints -r circuit.r1cs -s circuit.sym
96```
97
98
99### 3.2 Setting up using *snarkjs*
100
101
102Ok, let's run a setup for our circuit:
103
104```sh
105snarkjs setup
106```
107
108> By default `snarkjs` will look for and use `circuit.r1cs`. You can always specify a different circuit file by adding `-r <circuit R1CS file name>`
109
110The output of the setup will in the form of 2 files: `proving_key.json` and `verification_key.json`
111
112### 3.3. Calculating a witness
113
114Before creating any proof, we need to calculate all the signals of the circuit that match (all) the constrains of the circuit.
115
116`circom` generates a wasm module that calculates those for you. You need to provide a file with the inputs and it will execute the circuit and calculate all the intermediate signals and the output. This set of signals is the *witness*.
117
118The zero knowledge proofs prove that you know a set of signals (witness) that match all the constraints, without revealing any of the signals except the public inputs plus the outputs.
119
120For example, imagine you want to prove you are able to factor 33. It means that you know two numbers `a` and `b` and when you multiply them, it results in 33.
121
122> Of course you can always use one and the same number as `a` or `b`. We will deal with this problem later.
123
124So you want to prove that you know 3 and 11.
125
126Let's create a file named `input.json`
127
128```json
129{"a": 3, "b": 11}
130```
131
132Now let's calculate the witness:
133
134```sh
135snarkjs calculatewitness --wasm circuit.wasm --input input.json --witness witness.json
136```
137
138You may want to take a look at `witness.json` file with all the signals.
139
140### Create the proof
141
142Now that we have the witness generated, we can create the proof.
143
144```sh
145snarkjs proof
146```
147
148This command will use the `proving_key.json` and the `witness.json` files by default to generate `proof.json` and `public.json`
149
150The `proof.json` file will contain the actual proof. And the `public.json` file will contain just the values of the public inputs and the outputs.
151
152
153### Verifying the proof
154
155To verify the proof run:
156
157```sh
158snarkjs verify
159```
160
161This command will use `verification_key.json`, `proof.json` and `public.json` to verify that is valid.
162
163Here we are verifying that we know a witness that the public inputs and the outputs matches the ones in the `public.json` file.
164
165
166If the proof is ok, you will see `OK` or `INVALID` if not ok.
167
168### Generate the solidity verifier
169
170```sh
171snarkjs generateverifier
172```
173
174This command will take the `verification_key.json` and generate solidity code in `verifier.sol` file.
175
176You can take the code in `verifier.sol` and cut and paste it in remix.
177
178This code contains two contracts: Pairings and Verifier. You only need to deploy the `Verifier` contract.
179
180> You may want to use a test net like Rinkeby, Kovan or Ropsten. You can also use the Javascript VM, but in some browsers, the verification takes long and it may hang the page.
181
182
183### Verifying the proof on-chain
184
185The verifier contract deployed in the last step has a `view` function called `verifyProof`.
186
187This function will return true if the proof and the inputs are valid.
188
189To facilitate the call, you can use snarkjs to generate the parameters of the call by typing:
190
191```sh
192snarkjs generatecall
193```
194
195Just cut and paste the output to the parameters field of the `verifyProof` method in Remix.
196
197If every thing works ok, this method should return true.
198
199If you change any bit in the parameters, the result will be verifiably false.
200
201
202## Bonus track
203
204We can fix the circuit to not accept one as any of the values by adding some extra constraints.
205
206Here the trick is that we use the property that 0 has no inverse. So `(a-1)` should not have an inverse.
207
208That means that `(a-1)*inv = 1` will be inpossible to match if `a` is 1.
209
210We just calculate inv by `1/(a-1)`
211
212So let's modify the circuit:
213
214```
215template Multiplier() {
216 signal private input a;
217 signal private input b;
218 signal output c;
219 signal inva;
220 signal invb;
221
222 inva <-- 1/(a-1);
223 (a-1)*inva === 1;
224
225 invb <-- 1/(b-1);
226 (b-1)*invb === 1;
227
228 c <== a*b;
229}
230
231component main = Multiplier();
232```
233
234A nice thing of the circom language is that you can split a <== into two independent actions: <-- and ===
235
236The <-- and --> operators assign a value to a signal without creating any constraints.
237
238The === operator adds a constraint without assigning any value to any signal.
239
240The circuit also has another problem: the operation works in Zr, so we need to guarantee the multiplication does not overflow. This can be done by converting the inputs to binary and checking the ranges, but we will reserve it for future tutorials.
241
242## Where to go from here:
243
244You may want to read the [README](https://github.com/iden3/circom) to learn more features about circom.
245
246You can also check a library with many basic circuits lib binarizations, comparators, eddsa, hashes, merkle trees etc [here](https://github.com/iden3/circomlib) (Work in progress).
247
248
249Or a exponentiation in the Baby Jub curve [here](https://github.com/iden3/circomlib) (Work in progress).
250
251
252# Final note
253
254There is nothing worse for a dev than working with a buggy compiler. This is a very early stage of the compiler, so there are many bugs and lots of work needs to be done. Please have it present if you are doing anything serious with it.
255
256And please contact us for any isue you have. In general, a github issue with a small piece of code with the bug is very useful to us.
257
258Enjoy zero knowledge proving!