You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

352 lines
12 KiB

  1. #!/usr/bin/env node
  2. /*
  3. Copyright 2018 0KIMS association.
  4. This file is part of jaz (Zero Knowledge Circuit Compiler).
  5. jaz is a free software: you can redistribute it and/or modify it
  6. under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. jaz is distributed in the hope that it will be useful, but WITHOUT
  10. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11. or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  12. License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with jaz. If not, see <https://www.gnu.org/licenses/>.
  15. */
  16. /* eslint-disable no-console */
  17. const fs = require("fs");
  18. const path = require("path");
  19. const zkSnark = require("./index.js");
  20. const {stringifyBigInts, unstringifyBigInts} = require("./src/stringifybigint.js");
  21. const version = require("./package").version;
  22. const argv = require("yargs")
  23. .version(version)
  24. .usage(`snarkjs <command> <options>
  25. setup command
  26. =============
  27. snarkjs setup <option>
  28. Runs a setup for a circuit generating the proving and the verification key.
  29. -c or --circuit <circuitFile>
  30. Filename of the compiled circuit file generated by circom.
  31. Default: circuit.json
  32. --pk or --provingkey <provingKeyFile>
  33. Output filename where the proving key will be stored.
  34. Default: proving_key.json
  35. --vk or --verificationkey <verificationKeyFile>
  36. Output Filename where the verification key will be stored.
  37. Default: verification_key.json
  38. calculate witness command
  39. =========================
  40. snarkjs calculatewitness <options>
  41. Calculate the witness of a circuit given an input.
  42. -c or --circuit <circuitFile>
  43. Filename of the compiled circuit file generated by circom.
  44. Default: circuit.json
  45. -i or --input <inputFile>
  46. JSON file with the inputs of the circuit.
  47. Default: input.json
  48. Example of for a circuit with tow inputs a and b:
  49. {"a": "22", "b": "33"}
  50. -w or --witness
  51. Output filename with the generated witness.
  52. Default: witness.json
  53. generate a proof command
  54. ========================
  55. snarkjs proof <options>
  56. -w or --witness
  57. Input filename used to calculate the proof.
  58. Default: witness.json
  59. --pk or --provingkey <provingKeyFile>
  60. Input filename with the proving key (generated during the setup).
  61. Default: proving_key.json
  62. -p or --proof
  63. Output filenam with the zero knowlage proof.
  64. Default: proof.json
  65. --pub or --public <publicFilename>
  66. Output filename with the value of the public wires/signals.
  67. This info will be needed to verify the proof.
  68. Default: public.json
  69. verify command
  70. ==============
  71. snarkjs verify <options>
  72. The command returns "OK" if the proof is valid
  73. and "INVALID" in case it is not a valid proof.
  74. --vk or --verificationkey <verificationKeyFile>
  75. Input Filename with the verification key (generated during the setup).
  76. Default: verification_key.json
  77. -p or --proof
  78. Input filenam with the zero knowlage proof you want to verify
  79. Default: proof.json
  80. --pub or --public <publicFilename>
  81. Input filename with the public wires/signals.
  82. Default: public.json
  83. generate solidity verifier command
  84. ==================================
  85. snarkjs generateverifier <options>
  86. Generates a solidity smart contract that verifies the zero knowlage proof.
  87. --vk or --verificationkey <verificationKeyFile>
  88. Input Filename with the verification key (generated during the setup).
  89. Default: verification_key.json
  90. -v or --verifier
  91. Output file with a solidity smart contract that verifies a zero knowlage proof.
  92. Default: verifier.sol
  93. generate call parameters
  94. ========================
  95. snarkjs generatecall <options>
  96. Outputs into the console the raw parameters to be used in 'verifyProof'
  97. method of the solidity verifier.
  98. -p or --proof
  99. Input filenam with the zero knowlage proof you want to use
  100. Default: proof.json
  101. --pub or --public <publicFilename>
  102. Input filename with the public wires/signals.
  103. Default: public.json
  104. `)
  105. .alias("c", "circuit")
  106. .alias("pk", "provingkey")
  107. .alias("vk", "verificationkey")
  108. .alias("w", "witness")
  109. .alias("p", "proof")
  110. .alias("i", "input")
  111. .alias("pub", "public")
  112. .alias("v", "verifier")
  113. .help("h")
  114. .alias("h", "help")
  115. .epilogue(`Copyright (C) 2018 0kims association
  116. This program comes with ABSOLUTELY NO WARRANTY;
  117. This is free software, and you are welcome to redistribute it
  118. under certain conditions; see the COPYING file in the official
  119. repo directory at https://github.com/iden3/circom `)
  120. .argv;
  121. const circuitName = (argv.circuit) ? argv.circuit : "circuit.json";
  122. const provingKeyName = (argv.provingkey) ? argv.provingkey : "proving_key.json";
  123. const verificationKeyName = (argv.verificationkey) ? argv.verificationkey : "verification_key.json";
  124. const inputName = (argv.input) ? argv.input : "input.json";
  125. const witnessName = (argv.witness) ? argv.witness : "witness.json";
  126. const proofName = (argv.proof) ? argv.proof : "proof.json";
  127. const publicName = (argv.public) ? argv.public : "public.json";
  128. const verifierName = (argv.public) ? argv.public : "verifier.sol";
  129. function p256(n) {
  130. let nstr = n.toString(16);
  131. while (nstr.length < 64) nstr = "0"+nstr;
  132. nstr = `"0x${nstr}"`;
  133. return nstr;
  134. }
  135. try {
  136. if (argv._[0].toUpperCase() == "SETUP") {
  137. const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8"));
  138. const cir = new zkSnark.Circuit(cirDef);
  139. const setup = zkSnark.setup(cir);
  140. fs.writeFileSync(provingKeyName, JSON.stringify(stringifyBigInts(setup.vk_proof), null, 1), "utf-8");
  141. fs.writeFileSync(verificationKeyName, JSON.stringify(stringifyBigInts(setup.vk_verifier), null, 1), "utf-8");
  142. process.exit(0);
  143. } else if (argv._[0].toUpperCase() == "CALCULATEWITNESS") {
  144. const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8"));
  145. const cir = new zkSnark.Circuit(cirDef);
  146. const input = unstringifyBigInts(JSON.parse(fs.readFileSync(inputName, "utf8")));
  147. const witness = cir.calculateWitness(input);
  148. fs.writeFileSync(witnessName, JSON.stringify(stringifyBigInts(witness), null, 1), "utf-8");
  149. process.exit(0);
  150. } else if (argv._[0].toUpperCase() == "PROOF") {
  151. const witness = unstringifyBigInts(JSON.parse(fs.readFileSync(witnessName, "utf8")));
  152. const provingKey = unstringifyBigInts(JSON.parse(fs.readFileSync(provingKeyName, "utf8")));
  153. const {proof, publicSignals} = zkSnark.genProof(provingKey, witness);
  154. fs.writeFileSync(proofName, JSON.stringify(stringifyBigInts(proof), null, 1), "utf-8");
  155. fs.writeFileSync(publicName, JSON.stringify(stringifyBigInts(publicSignals), null, 1), "utf-8");
  156. process.exit(0);
  157. } else if (argv._[0].toUpperCase() == "VERIFY") {
  158. const public = unstringifyBigInts(JSON.parse(fs.readFileSync(publicName, "utf8")));
  159. const verificationKey = unstringifyBigInts(JSON.parse(fs.readFileSync(verificationKeyName, "utf8")));
  160. const proof = unstringifyBigInts(JSON.parse(fs.readFileSync(proofName, "utf8")));
  161. const isValid = zkSnark.isValid(verificationKey, proof, public);
  162. if (isValid) {
  163. console.log("OK");
  164. process.exit(0);
  165. } else {
  166. console.log("INVALID");
  167. process.exit(1);
  168. }
  169. } else if (argv._[0].toUpperCase() == "GENERATEVERIFIER") {
  170. const verificationKey = unstringifyBigInts(JSON.parse(fs.readFileSync(verificationKeyName, "utf8")));
  171. let template = fs.readFileSync(path.join( __dirname, "templates", "verifier.sol"), "utf-8");
  172. const vka_str = `[${verificationKey.vk_a[0][1].toString()},`+
  173. `${verificationKey.vk_a[0][0].toString()}], `+
  174. `[${verificationKey.vk_a[1][1].toString()},` +
  175. `${verificationKey.vk_a[1][0].toString()}]`;
  176. template = template.replace("<%vk_a%>", vka_str);
  177. const vkb_str = `${verificationKey.vk_b[0].toString()},`+
  178. `${verificationKey.vk_b[1].toString()}`;
  179. template = template.replace("<%vk_b%>", vkb_str);
  180. const vkc_str = `[${verificationKey.vk_c[0][1].toString()},`+
  181. `${verificationKey.vk_c[0][0].toString()}], `+
  182. `[${verificationKey.vk_c[1][1].toString()},` +
  183. `${verificationKey.vk_c[1][0].toString()}]`;
  184. template = template.replace("<%vk_c%>", vkc_str);
  185. const vkg_str = `[${verificationKey.vk_g[0][1].toString()},`+
  186. `${verificationKey.vk_g[0][0].toString()}], `+
  187. `[${verificationKey.vk_g[1][1].toString()},` +
  188. `${verificationKey.vk_g[1][0].toString()}]`;
  189. template = template.replace("<%vk_g%>", vkg_str);
  190. const vkgb1_str = `${verificationKey.vk_gb_1[0].toString()},`+
  191. `${verificationKey.vk_gb_1[1].toString()}`;
  192. template = template.replace("<%vk_gb1%>", vkgb1_str);
  193. const vkgb2_str = `[${verificationKey.vk_gb_2[0][1].toString()},`+
  194. `${verificationKey.vk_gb_2[0][0].toString()}], `+
  195. `[${verificationKey.vk_gb_2[1][1].toString()},` +
  196. `${verificationKey.vk_gb_2[1][0].toString()}]`;
  197. template = template.replace("<%vk_gb2%>", vkgb2_str);
  198. const vkz_str = `[${verificationKey.vk_z[0][1].toString()},`+
  199. `${verificationKey.vk_z[0][0].toString()}], `+
  200. `[${verificationKey.vk_z[1][1].toString()},` +
  201. `${verificationKey.vk_z[1][0].toString()}]`;
  202. template = template.replace("<%vk_z%>", vkz_str);
  203. // The points
  204. template = template.replace("<%vk_input_length%>", (verificationKey.A.length-1).toString());
  205. template = template.replace("<%vk_ic_length%>", verificationKey.A.length.toString());
  206. let vi = "";
  207. for (let i=0; i<verificationKey.A.length; i++) {
  208. if (vi != "") vi = vi + " ";
  209. vi = vi + `vk.IC[${i}] = Pairing.G1Point(${verificationKey.A[i][0].toString()},`+
  210. `${verificationKey.A[i][1].toString()});\n`;
  211. }
  212. template = template.replace("<%vk_ic_pts%>", vi);
  213. fs.writeFileSync(verifierName, template, "utf-8");
  214. process.exit(0);
  215. } else if (argv._[0].toUpperCase() == "GENERATECALL") {
  216. const public = unstringifyBigInts(JSON.parse(fs.readFileSync(publicName, "utf8")));
  217. const proof = unstringifyBigInts(JSON.parse(fs.readFileSync(proofName, "utf8")));
  218. inputs = "";
  219. for (let i=0; i<public.length; i++) {
  220. if (inputs != "") inputs = inputs + ",";
  221. inputs = inputs + p256(public[i]);
  222. }
  223. const S=`[${p256(proof.pi_a[0])}, ${p256(proof.pi_a[1])}],` +
  224. `[${p256(proof.pi_ap[0])}, ${p256(proof.pi_ap[1])}],` +
  225. `[[${p256(proof.pi_b[0][1])}, ${p256(proof.pi_b[0][0])}],[${p256(proof.pi_b[1][1])}, ${p256(proof.pi_b[1][0])}]],` +
  226. `[${p256(proof.pi_bp[0])}, ${p256(proof.pi_bp[1])}],` +
  227. `[${p256(proof.pi_c[0])}, ${p256(proof.pi_c[1])}],` +
  228. `[${p256(proof.pi_cp[0])}, ${p256(proof.pi_cp[1])}],` +
  229. `[${p256(proof.pi_h[0])}, ${p256(proof.pi_h[1])}],` +
  230. `[${p256(proof.pi_kp[0])}, ${p256(proof.pi_kp[1])}],` +
  231. `[${inputs}]` ;
  232. console.log(S);
  233. process.exit(0);
  234. }
  235. } catch(err) {
  236. console.log("ERROR: " + err);
  237. process.exit(1);
  238. }