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.
173
174 -p or --proof
175
176 Input filenam 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
186
187 `)
188 .alias("c", "circuit")
189 .alias("pk", "provingkey")
190 .alias("vk", "verificationkey")
191 .alias("w", "witness")
192 .alias("p", "proof")
193 .alias("i", "input")
194 .alias("pub", "public")
195 .alias("v", "verifier")
196 .help("h")
197 .alias("h", "help")
198 .epilogue(`Copyright (C) 2018 0kims association
199 This program comes with ABSOLUTELY NO WARRANTY;
200 This is free software, and you are welcome to redistribute it
201 under certain conditions; see the COPYING file in the official
202 repo directory at https://github.com/iden3/circom `)
203 .argv;
204
205const circuitName = (argv.circuit) ? argv.circuit : "circuit.json";
206const provingKeyName = (argv.provingkey) ? argv.provingkey : "proving_key.json";
207const verificationKeyName = (argv.verificationkey) ? argv.verificationkey : "verification_key.json";
208const inputName = (argv.input) ? argv.input : "input.json";
209const witnessName = (argv.witness) ? argv.witness : "witness.json";
210const proofName = (argv.proof) ? argv.proof : "proof.json";
211const publicName = (argv.public) ? argv.public : "public.json";
212const verifierName = (argv.public) ? argv.public : "verifier.sol";
213
214function p256(n) {
215 let nstr = n.toString(16);
216 while (nstr.length < 64) nstr = "0"+nstr;
217 nstr = `"0x${nstr}"`;
218 return nstr;
219}
220
221try {
222 if (argv._[0].toUpperCase() == "SETUP") {
223 const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8"));
224 const cir = new zkSnark.Circuit(cirDef);
225 const setup = zkSnark.setup(cir);
226
227 fs.writeFileSync(provingKeyName, JSON.stringify(stringifyBigInts(setup.vk_proof), null, 1), "utf-8");
228 fs.writeFileSync(verificationKeyName, JSON.stringify(stringifyBigInts(setup.vk_verifier), null, 1), "utf-8");
229 process.exit(0);
230 } else if (argv._[0].toUpperCase() == "CALCULATEWITNESS") {
231 const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8"));
232 const cir = new zkSnark.Circuit(cirDef);
233 const input = unstringifyBigInts(JSON.parse(fs.readFileSync(inputName, "utf8")));
234
235 const witness = cir.calculateWitness(input);
236
237 fs.writeFileSync(witnessName, JSON.stringify(stringifyBigInts(witness), null, 1), "utf-8");
238 process.exit(0);
239 } else if (argv._[0].toUpperCase() == "PROOF") {
240 const witness = unstringifyBigInts(JSON.parse(fs.readFileSync(witnessName, "utf8")));
241 const provingKey = unstringifyBigInts(JSON.parse(fs.readFileSync(provingKeyName, "utf8")));
242
243 const {proof, publicSignals} = zkSnark.genProof(provingKey, witness);
244
245 fs.writeFileSync(proofName, JSON.stringify(stringifyBigInts(proof), null, 1), "utf-8");
246 fs.writeFileSync(publicName, JSON.stringify(stringifyBigInts(publicSignals), null, 1), "utf-8");
247 process.exit(0);
248 } else if (argv._[0].toUpperCase() == "VERIFY") {
249 const public = unstringifyBigInts(JSON.parse(fs.readFileSync(publicName, "utf8")));
250 const verificationKey = unstringifyBigInts(JSON.parse(fs.readFileSync(verificationKeyName, "utf8")));
251 const proof = unstringifyBigInts(JSON.parse(fs.readFileSync(proofName, "utf8")));
252 const isValid = zkSnark.isValid(verificationKey, proof, public);
253
254 if (isValid) {
255 console.log("OK");
256 process.exit(0);
257 } else {
258 console.log("INVALID");
259 process.exit(1);
260 }
261 } else if (argv._[0].toUpperCase() == "GENERATEVERIFIER") {
262
263 const verificationKey = unstringifyBigInts(JSON.parse(fs.readFileSync(verificationKeyName, "utf8")));
264 let template = fs.readFileSync(path.join( __dirname, "templates", "verifier.sol"), "utf-8");
265
266 const vka_str = `[${verificationKey.vk_a[0][1].toString()},`+
267 `${verificationKey.vk_a[0][0].toString()}], `+
268 `[${verificationKey.vk_a[1][1].toString()},` +
269 `${verificationKey.vk_a[1][0].toString()}]`;
270 template = template.replace("<%vk_a%>", vka_str);
271
272 const vkb_str = `${verificationKey.vk_b[0].toString()},`+
273 `${verificationKey.vk_b[1].toString()}`;
274 template = template.replace("<%vk_b%>", vkb_str);
275
276 const vkc_str = `[${verificationKey.vk_c[0][1].toString()},`+
277 `${verificationKey.vk_c[0][0].toString()}], `+
278 `[${verificationKey.vk_c[1][1].toString()},` +
279 `${verificationKey.vk_c[1][0].toString()}]`;
280 template = template.replace("<%vk_c%>", vkc_str);
281
282 const vkg_str = `[${verificationKey.vk_g[0][1].toString()},`+
283 `${verificationKey.vk_g[0][0].toString()}], `+
284 `[${verificationKey.vk_g[1][1].toString()},` +
285 `${verificationKey.vk_g[1][0].toString()}]`;
286 template = template.replace("<%vk_g%>", vkg_str);
287
288 const vkgb1_str = `${verificationKey.vk_gb_1[0].toString()},`+
289 `${verificationKey.vk_gb_1[1].toString()}`;
290 template = template.replace("<%vk_gb1%>", vkgb1_str);
291
292 const vkgb2_str = `[${verificationKey.vk_gb_2[0][1].toString()},`+
293 `${verificationKey.vk_gb_2[0][0].toString()}], `+
294 `[${verificationKey.vk_gb_2[1][1].toString()},` +
295 `${verificationKey.vk_gb_2[1][0].toString()}]`;
296 template = template.replace("<%vk_gb2%>", vkgb2_str);
297
298 const vkz_str = `[${verificationKey.vk_z[0][1].toString()},`+
299 `${verificationKey.vk_z[0][0].toString()}], `+
300 `[${verificationKey.vk_z[1][1].toString()},` +
301 `${verificationKey.vk_z[1][0].toString()}]`;
302 template = template.replace("<%vk_z%>", vkz_str);
303
304 // The points
305
306 template = template.replace("<%vk_input_length%>", (verificationKey.A.length-1).toString());
307 template = template.replace("<%vk_ic_length%>", verificationKey.A.length.toString());
308 let vi = "";
309 for (let i=0; i<verificationKey.A.length; i++) {
310 if (vi != "") vi = vi + " ";
311 vi = vi + `vk.IC[${i}] = Pairing.G1Point(${verificationKey.A[i][0].toString()},`+
312 `${verificationKey.A[i][1].toString()});\n`;
313 }
314 template = template.replace("<%vk_ic_pts%>", vi);
315
316
317 fs.writeFileSync(verifierName, template, "utf-8");
318 process.exit(0);
319
320 } else if (argv._[0].toUpperCase() == "GENERATECALL") {
321
322 const public = unstringifyBigInts(JSON.parse(fs.readFileSync(publicName, "utf8")));
323 const proof = unstringifyBigInts(JSON.parse(fs.readFileSync(proofName, "utf8")));
324
325 inputs = "";
326 for (let i=0; i<public.length; i++) {
327 if (inputs != "") inputs = inputs + ",";
328 inputs = inputs + p256(public[i]);
329 }
330
331 const S=`[${p256(proof.pi_a[0])}, ${p256(proof.pi_a[1])}],` +
332 `[${p256(proof.pi_ap[0])}, ${p256(proof.pi_ap[1])}],` +
333 `[[${p256(proof.pi_b[0][1])}, ${p256(proof.pi_b[0][0])}],[${p256(proof.pi_b[1][1])}, ${p256(proof.pi_b[1][0])}]],` +
334 `[${p256(proof.pi_bp[0])}, ${p256(proof.pi_bp[1])}],` +
335 `[${p256(proof.pi_c[0])}, ${p256(proof.pi_c[1])}],` +
336 `[${p256(proof.pi_cp[0])}, ${p256(proof.pi_cp[1])}],` +
337 `[${p256(proof.pi_h[0])}, ${p256(proof.pi_h[1])}],` +
338 `[${p256(proof.pi_kp[0])}, ${p256(proof.pi_kp[1])}],` +
339 `[${inputs}]` ;
340
341 console.log(S);
342 process.exit(0);
343 }
344} catch(err) {
345 console.log("ERROR: " + err);
346 process.exit(1);
347}
348
349
350
351
352