snarkjs/cli.js
cli.jsRaw
1#!/usr/bin/env node
2
3/*
4 Copyright 2018 0KIMS association.
5
6 This file is part of jaz (Zero Knowledge Circuit Compiler).
7
8 jaz is a free software: you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 jaz is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with jaz. If not, see <https://www.gnu.org/licenses/>.
20*/
21
22/* eslint-disable no-console */
23
24const fs = require("fs");
25const path = require("path");
26
27const zkSnark = require("./index.js");
28const {stringifyBigInts, unstringifyBigInts} = require("./src/stringifybigint.js");
29
30
31const version = require("./package").version;
32
33const argv = require("yargs")
34 .version(version)
35 .usage(`snarkjs <command> <options>
36
37setup command
38=============
39
40 snarkjs setup <option>
41
42 Runs a setup for a circuit generating the proving and the verification key.
43
44 -c or --circuit <circuitFile>
45
46 Filename of the compiled circuit file generated by circom.
47
48 Default: circuit.json
49
50 --pk or --provingkey <provingKeyFile>
51
52 Output filename where the proving key will be stored.
53
54 Default: proving_key.json
55
56 --vk or --verificationkey <verificationKeyFile>
57
58 Output Filename where the verification key will be stored.
59
60 Default: verification_key.json
61
62calculate witness command
63=========================
64
65 snarkjs calculatewitness <options>
66
67 Calculate the witness of a circuit given an input.
68
69 -c or --circuit <circuitFile>
70
71 Filename of the compiled circuit file generated by circom.
72
73 Default: circuit.json
74
75 -i or --input <inputFile>
76
77 JSON file with the inputs of the circuit.
78
79 Default: input.json
80
81 Example of for a circuit with tow inputs a and b:
82
83 {"a": "22", "b": "33"}
84
85 -w or --witness
86
87 Output filename with the generated witness.
88
89 Default: witness.json
90
91generate a proof command
92========================
93
94 snarkjs proof <options>
95
96 -w or --witness
97
98 Input filename used to calculate the proof.
99
100 Default: witness.json
101
102 --pk or --provingkey <provingKeyFile>
103
104 Input filename with the proving key (generated during the setup).
105
106 Default: proving_key.json
107
108 -p or --proof
109
110 Output filenam with the zero knowlage proof.
111
112 Default: proof.json
113
114 --pub or --public <publicFilename>
115
116 Output filename with the value of the public wires/signals.
117 This info will be needed to verify the proof.
118
119 Default: public.json
120
121verify command
122==============
123
124 snarkjs verify <options>
125
126 The command returns "OK" if the proof is valid
127 and "INVALID" in case it is not a valid proof.
128
129 --vk or --verificationkey <verificationKeyFile>
130
131 Input Filename with the verification key (generated during the setup).
132
133 Default: verification_key.json
134
135 -p or --proof
136
137 Input filenam with the zero knowlage proof you want to verify
138
139 Default: proof.json
140
141 --pub or --public <publicFilename>
142
143 Input filename with the public wires/signals.
144
145 Default: public.json
146
147generate solidity verifier command
148==================================
149
150 snarkjs generateverifier <options>
151
152 Generates a solidity smart contract that verifies the zero knowlage proof.
153
154 --vk or --verificationkey <verificationKeyFile>
155
156 Input Filename with the verification key (generated during the setup).
157
158 Default: verification_key.json
159
160 -v or --verifier
161
162 Output file with a solidity smart contract that verifies a zero knowlage proof.
163
164 Default: verifier.sol
165
166generate call parameters
167========================
168
169 snarkjs generatecall <options>
170
171 Outputs into the console the raw parameters to be used in 'verifyProof'
172 method of the solidity verifier function.
173
174 -p or --proof
175
176 Input filename with the zero knowlage proof you want to use
177
178 Default: proof.json
179
180 --pub or --public <publicFilename>
181
182 Input filename with the public wires/signals.
183
184 Default: public.json
185
186circuit info
187============
188
189 snarkjs info <options>
190
191 Print statistics of a circuit
192
193 -c or --circuit <circuitFile>
194
195 Filename of the compiled circuit file generated by circom.
196
197 Default: circuit.json
198
199print constraints
200=================
201
202 snarkjs printconstraints <options>
203
204 Print all the constraints of a given circuit
205
206 -c or --circuit <circuitFile>
207
208 Filename of the compiled circuit file generated by circom.
209
210 Default: circuit.json
211 `)
212 .alias("c", "circuit")
213 .alias("pk", "provingkey")
214 .alias("vk", "verificationkey")
215 .alias("w", "witness")
216 .alias("p", "proof")
217 .alias("i", "input")
218 .alias("pub", "public")
219 .alias("v", "verifier")
220 .help("h")
221 .alias("h", "help")
222 .epilogue(`Copyright (C) 2018 0kims association
223 This program comes with ABSOLUTELY NO WARRANTY;
224 This is free software, and you are welcome to redistribute it
225 under certain conditions; see the COPYING file in the official
226 repo directory at https://github.com/iden3/circom `)
227 .argv;
228
229const circuitName = (argv.circuit) ? argv.circuit : "circuit.json";
230const provingKeyName = (argv.provingkey) ? argv.provingkey : "proving_key.json";
231const verificationKeyName = (argv.verificationkey) ? argv.verificationkey : "verification_key.json";
232const inputName = (argv.input) ? argv.input : "input.json";
233const witnessName = (argv.witness) ? argv.witness : "witness.json";
234const proofName = (argv.proof) ? argv.proof : "proof.json";
235const publicName = (argv.public) ? argv.public : "public.json";
236const verifierName = (argv.public) ? argv.public : "verifier.sol";
237
238function p256(n) {
239 let nstr = n.toString(16);
240 while (nstr.length < 64) nstr = "0"+nstr;
241 nstr = `"0x${nstr}"`;
242 return nstr;
243}
244
245try {
246 if (argv._[0].toUpperCase() == "INFO") {
247 const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8"));
248 const cir = new zkSnark.Circuit(cirDef);
249
250 console.log(`# Wires: ${cir.nVars}`);
251 console.log(`# Constraints: ${cir.nConstraints}`);
252 console.log(`# Private Inputs: ${cir.nPrvInputs}`);
253 console.log(`# Public Inputs: ${cir.nPubInputs}`);
254 console.log(`# Outputs: ${cir.nOutputs}`);
255
256 } else if (argv._[0].toUpperCase() == "PRINTCONSTRAINTS") {
257 const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8"));
258 const cir = new zkSnark.Circuit(cirDef);
259
260 cir.printConstraints();
261
262 } else if (argv._[0].toUpperCase() == "SETUP") {
263 const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8"));
264 const cir = new zkSnark.Circuit(cirDef);
265 const setup = zkSnark.setup(cir);
266
267 fs.writeFileSync(provingKeyName, JSON.stringify(stringifyBigInts(setup.vk_proof), null, 1), "utf-8");
268 fs.writeFileSync(verificationKeyName, JSON.stringify(stringifyBigInts(setup.vk_verifier), null, 1), "utf-8");
269 process.exit(0);
270 } else if (argv._[0].toUpperCase() == "CALCULATEWITNESS") {
271 const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8"));
272 const cir = new zkSnark.Circuit(cirDef);
273 const input = unstringifyBigInts(JSON.parse(fs.readFileSync(inputName, "utf8")));
274
275 const witness = cir.calculateWitness(input);
276
277 fs.writeFileSync(witnessName, JSON.stringify(stringifyBigInts(witness), null, 1), "utf-8");
278 process.exit(0);
279 } else if (argv._[0].toUpperCase() == "PROOF") {
280 const witness = unstringifyBigInts(JSON.parse(fs.readFileSync(witnessName, "utf8")));
281 const provingKey = unstringifyBigInts(JSON.parse(fs.readFileSync(provingKeyName, "utf8")));
282
283 const {proof, publicSignals} = zkSnark.genProof(provingKey, witness);
284
285 fs.writeFileSync(proofName, JSON.stringify(stringifyBigInts(proof), null, 1), "utf-8");
286 fs.writeFileSync(publicName, JSON.stringify(stringifyBigInts(publicSignals), null, 1), "utf-8");
287 process.exit(0);
288 } else if (argv._[0].toUpperCase() == "VERIFY") {
289 const public = unstringifyBigInts(JSON.parse(fs.readFileSync(publicName, "utf8")));
290 const verificationKey = unstringifyBigInts(JSON.parse(fs.readFileSync(verificationKeyName, "utf8")));
291 const proof = unstringifyBigInts(JSON.parse(fs.readFileSync(proofName, "utf8")));
292 const isValid = zkSnark.isValid(verificationKey, proof, public);
293
294 if (isValid) {
295 console.log("OK");
296 process.exit(0);
297 } else {
298 console.log("INVALID");
299 process.exit(1);
300 }
301 } else if (argv._[0].toUpperCase() == "GENERATEVERIFIER") {
302
303 const verificationKey = unstringifyBigInts(JSON.parse(fs.readFileSync(verificationKeyName, "utf8")));
304 let template = fs.readFileSync(path.join( __dirname, "templates", "verifier.sol"), "utf-8");
305
306 const vka_str = `[${verificationKey.vk_a[0][1].toString()},`+
307 `${verificationKey.vk_a[0][0].toString()}], `+
308 `[${verificationKey.vk_a[1][1].toString()},` +
309 `${verificationKey.vk_a[1][0].toString()}]`;
310 template = template.replace("<%vk_a%>", vka_str);
311
312 const vkb_str = `${verificationKey.vk_b[0].toString()},`+
313 `${verificationKey.vk_b[1].toString()}`;
314 template = template.replace("<%vk_b%>", vkb_str);
315
316 const vkc_str = `[${verificationKey.vk_c[0][1].toString()},`+
317 `${verificationKey.vk_c[0][0].toString()}], `+
318 `[${verificationKey.vk_c[1][1].toString()},` +
319 `${verificationKey.vk_c[1][0].toString()}]`;
320 template = template.replace("<%vk_c%>", vkc_str);
321
322 const vkg_str = `[${verificationKey.vk_g[0][1].toString()},`+
323 `${verificationKey.vk_g[0][0].toString()}], `+
324 `[${verificationKey.vk_g[1][1].toString()},` +
325 `${verificationKey.vk_g[1][0].toString()}]`;
326 template = template.replace("<%vk_g%>", vkg_str);
327
328 const vkgb1_str = `${verificationKey.vk_gb_1[0].toString()},`+
329 `${verificationKey.vk_gb_1[1].toString()}`;
330 template = template.replace("<%vk_gb1%>", vkgb1_str);
331
332 const vkgb2_str = `[${verificationKey.vk_gb_2[0][1].toString()},`+
333 `${verificationKey.vk_gb_2[0][0].toString()}], `+
334 `[${verificationKey.vk_gb_2[1][1].toString()},` +
335 `${verificationKey.vk_gb_2[1][0].toString()}]`;
336 template = template.replace("<%vk_gb2%>", vkgb2_str);
337
338 const vkz_str = `[${verificationKey.vk_z[0][1].toString()},`+
339 `${verificationKey.vk_z[0][0].toString()}], `+
340 `[${verificationKey.vk_z[1][1].toString()},` +
341 `${verificationKey.vk_z[1][0].toString()}]`;
342 template = template.replace("<%vk_z%>", vkz_str);
343
344 // The points
345
346 template = template.replace("<%vk_input_length%>", (verificationKey.A.length-1).toString());
347 template = template.replace("<%vk_ic_length%>", verificationKey.A.length.toString());
348 let vi = "";
349 for (let i=0; i<verificationKey.A.length; i++) {
350 if (vi != "") vi = vi + " ";
351 vi = vi + `vk.IC[${i}] = Pairing.G1Point(${verificationKey.A[i][0].toString()},`+
352 `${verificationKey.A[i][1].toString()});\n`;
353 }
354 template = template.replace("<%vk_ic_pts%>", vi);
355
356
357 fs.writeFileSync(verifierName, template, "utf-8");
358 process.exit(0);
359
360 } else if (argv._[0].toUpperCase() == "GENERATECALL") {
361
362 const public = unstringifyBigInts(JSON.parse(fs.readFileSync(publicName, "utf8")));
363 const proof = unstringifyBigInts(JSON.parse(fs.readFileSync(proofName, "utf8")));
364
365 let inputs = "";
366 for (let i=0; i<public.length; i++) {
367 if (inputs != "") inputs = inputs + ",";
368 inputs = inputs + p256(public[i]);
369 }
370
371 const S=`[${p256(proof.pi_a[0])}, ${p256(proof.pi_a[1])}],` +
372 `[${p256(proof.pi_ap[0])}, ${p256(proof.pi_ap[1])}],` +
373 `[[${p256(proof.pi_b[0][1])}, ${p256(proof.pi_b[0][0])}],[${p256(proof.pi_b[1][1])}, ${p256(proof.pi_b[1][0])}]],` +
374 `[${p256(proof.pi_bp[0])}, ${p256(proof.pi_bp[1])}],` +
375 `[${p256(proof.pi_c[0])}, ${p256(proof.pi_c[1])}],` +
376 `[${p256(proof.pi_cp[0])}, ${p256(proof.pi_cp[1])}],` +
377 `[${p256(proof.pi_h[0])}, ${p256(proof.pi_h[1])}],` +
378 `[${p256(proof.pi_kp[0])}, ${p256(proof.pi_kp[1])}],` +
379 `[${inputs}]` ;
380
381 console.log(S);
382 process.exit(0);
383 } else {
384 throw new Error("Invalid Command");
385 }
386} catch(err) {
387 console.log("ERROR: " + err);
388 process.exit(1);
389}
390
391
392
393
394