arnaucube
arnaucube/snarkjsPublic Self-hosted repository
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
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