circom/TUTORIAL.md
TUTORIAL.mdRaw
1# circom and snarkjs tutorial
2
3This tutorial will guide you in creating your first Zero Knowledge zkSnark circuit. It will take you through the various techniques to write circuits, and will show you how to create proofs and verify them 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 circom_runtime
20npm install -g snarkjs
21```
22
23
24## 2. Working with a circuit
25
26Let's create a circuit that tries to prove that you are able to factor a number!
27
28### 2.1 Create a circuit in a new directory
29
301. Create an empty directory called `factor` where you will put all the files that you will use in this tutorial.
31```
32mkdir factor
33cd factor
34```
35
36
37> 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.
38
392. Create a new file named `circuit.circom` with the following content:
40
41```
42template Multiplier() {
43 signal private input a;
44 signal private input b;
45 signal output c;
46
47 c <== a*b;
48}
49
50component main = Multiplier();
51```
52
53This circuit has 2 private input signals named `a` and `b` and one output named `c`.
54
55The only thing that the circuit does is forcing the signal `c` to be the value of `a*b`
56
57After declaring the `Multiplier` template, we instantiate it with a component named`main`.
58
59Note: When compiling a circuit, a component named `main` must always exist.
60
61### 2.2 Compile the circuit
62
63We are now ready to compile the circuit. Run the following command:
64
65```sh
66circom circuit.circom --r1cs --wasm --sym
67```
68
69The -r optin will generate `circuit.r1cs` ( The r1cs constraint system of the circuit in binary format)
70The -w will generate `circuit.wasm` (The wasm code to generate the witness)
71The -s will generate `circuit.sym` (This is the symbols file, required for debugging or if you want to print the constraint system in an annotated mode)
72
73
74## 3. Taking the compiled circuit to *snarkjs*
75
76Now that the circuit is compiled, we will continue with `snarkjs`.
77Please note that you can always access the help of `snarkjs` by typing:
78
79```sh
80snarkjs --help
81```
82
83### 3.1 View information and stats regarding a circuit
84
85To show general statistics of this circuit, you can run:
86
87```sh
88snarkjs info -r circuit.r1cs
89```
90
91You can also print the constraints of the circuit by running:
92
93```sh
94snarkjs printconstraints -r circuit.r1cs -s circuit.sym
95```
96
97
98### 3.2 Setting up using *snarkjs*
99
100
101Ok, let's run a setup for our circuit:
102
103```sh
104snarkjs setup
105```
106
107> 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>`
108
109The output of the setup will in the form of 2 files: `proving_key.json` and `verification_key.json`
110
111### 3.3. Calculating a witness
112
113Before creating any proof, we need to calculate all the signals of the circuit that match (all) the constrains of the circuit.
114
115`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*.
116
117The 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.
118
119For 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.
120
121> Of course you can always use one and the same number as `a` or `b`. We will deal with this problem later.
122
123So you want to prove that you know 3 and 11.
124
125Let's create a file named `input.json`
126
127```json
128{"a": 3, "b": 11}
129```
130
131Now let's calculate the witness:
132
133```sh
134snarkjs calculatewitness --wasm circuit.wasm --input input.json --witness witness.json
135```
136
137`calcwit` is part of the circom_runtime package and it's just a wrapper in JS to call the wasm module.
138
139You can use `circom_runtime` from your own project to calulate the witness.
140
141You may want to take a look at `witness.json` file with all the signals.
142
143### Create the proof
144
145Now that we have the witness generated, we can create the proof.
146
147```sh
148snarkjs proof
149```
150
151This command will use the `proving_key.json` and the `witness.json` files by default to generate `proof.json` and `public.json`
152
153The `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.
154
155
156### Verifying the proof
157
158To verify the proof run:
159
160```sh
161snarkjs verify
162```
163
164This command will use `verification_key.json`, `proof.json` and `public.json` to verify that is valid.
165
166Here we are verifying that we know a witness that the public inputs and the outputs matches the ones in the `public.json` file.
167
168
169If the proof is ok, you will see `OK` or `INVALID` if not ok.
170
171### Generate the solidity verifier
172
173```sh
174snarkjs generateverifier
175```
176
177This command will take the `verification_key.json` and generate solidity code in `verifier.sol` file.
178
179You can take the code in `verifier.sol` and cut and paste it in remix.
180
181This code contains two contracts: Pairings and Verifier. You only need to deploy the `Verifier` contract.
182
183> 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.
184
185
186### Verifying the proof on-chain
187
188The verifier contract deployed in the last step has a `view` function called `verifyProof`.
189
190This function will return true if the proof and the inputs are valid.
191
192To facilitate the call, you can use snarkjs to generate the parameters of the call by typing:
193
194```sh
195snarkjs generatecall
196```
197
198Just cut and paste the output to the parameters field of the `verifyProof` method in Remix.
199
200If every thing works ok, this method should return true.
201
202If you change any bit in the parameters, the result will be verifiably false.
203
204
205## Bonus track
206
207We can fix the circuit to not accept one as any of the values by adding some extra constraints.
208
209Here the trick is that we use the property that 0 has no inverse. So `(a-1)` should not have an inverse.
210
211That means that `(a-1)*inv = 1` will be inpossible to match if `a` is 1.
212
213We just calculate inv by `1/(a-1)`
214
215So let's modify the circuit:
216
217```
218template Multiplier() {
219 signal private input a;
220 signal private input b;
221 signal output c;
222 signal inva;
223 signal invb;
224
225 inva <-- 1/(a-1);
226 (a-1)*inva === 1;
227
228 invb <-- 1/(b-1);
229 (b-1)*invb === 1;
230
231 c <== a*b;
232}
233
234component main = Multiplier();
235```
236
237A nice thing of the circom language is that you can split a <== into two independent actions: <-- and ===
238
239The <-- and --> operators assign a value to a signal without creating any constraints.
240
241The === operator adds a constraint without assigning any value to any signal.
242
243The 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.
244
245## Where to go from here:
246
247You may want to read the [README](https://github.com/iden3/circom) to learn more features about circom.
248
249You 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).
250
251
252Or a exponentiation in the Baby Jub curve [here](https://github.com/iden3/circomlib) (Work in progress).
253
254
255# Final note
256
257There 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.
258
259And 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.
260
261Enjoy zero knowledge proving!