Browse Source

Rename to snarkjs, cli and some fixes

master
Jordi Baylina 5 years ago
parent
commit
54a4be447f
No known key found for this signature in database GPG Key ID: 7480C80C1BE43112
17 changed files with 842 additions and 110 deletions
  1. +352
    -0
      cli.js
  2. +1
    -1
      package-lock.json
  3. +9
    -3
      package.json
  4. +0
    -1
      sha256_2_vk_proof.json
  5. +0
    -1
      sha256_2_vk_verifier.json
  6. +1
    -1
      src/bigint.js
  7. +2
    -2
      src/calculateWitness.js
  8. +52
    -0
      src/circuit.js
  9. +72
    -65
      src/gcurve.js
  10. +2
    -2
      src/prover.js
  11. +1
    -1
      src/setup.js
  12. +36
    -0
      src/stringifybigint.js
  13. +243
    -0
      templates/verifier.sol
  14. +65
    -0
      templates/verifier_abi.json
  15. +4
    -31
      test/zksnark.js
  16. +1
    -1
      vk_proof.json
  17. +1
    -1
      vk_verifier.json

+ 352
- 0
cli.js

@ -0,0 +1,352 @@
#!/usr/bin/env node
/*
Copyright 2018 0KIMS association.
This file is part of jaz (Zero Knowledge Circuit Compiler).
jaz is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jaz is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with jaz. If not, see <https://www.gnu.org/licenses/>.
*/
/* eslint-disable no-console */
const fs = require("fs");
const path = require("path");
const zkSnark = require("./index.js");
const {stringifyBigInts, unstringifyBigInts} = require("./src/stringifybigint.js");
const version = require("./package").version;
const argv = require("yargs")
.version(version)
.usage(`snarkjs <command> <options>
setup command
=============
snarkjs setup <option>
Runs a setup for a circuit generating the proving and the verification key.
-c or --circuit <circuitFile>
Filename of the compiled circuit file generated by circom.
Default: circuit.json
--pk or --provingkey <provingKeyFile>
Output filename where the proving key will be stored.
Default: proving_key.json
--vk or --verificationkey <verificationKeyFile>
Output Filename where the verification key will be stored.
Default: verification_key.json
calculate witness command
=========================
snarkjs calculatewitness <options>
Calculate the witness of a circuit given an input.
-c or --circuit <circuitFile>
Filename of the compiled circuit file generated by circom.
Default: circuit.json
-i or --input <inputFile>
JSON file with the inputs of the circuit.
Default: input.json
Example of for a circuit with tow inputs a and b:
{"a": "22", "b": "33"}
-w or --witness
Output filename with the generated witness.
Default: witness.json
generate a proof command
========================
snarkjs proof <options>
-w or --witness
Input filename used to calculate the proof.
Default: witness.json
--pk or --provingkey <provingKeyFile>
Input filename with the proving key (generated during the setup).
Default: proving_key.json
-p or --proof
Output filenam with the zero knowlage proof.
Default: proof.json
--pub or --public <publicFilename>
Output filename with the value of the public wires/signals.
This info will be needed to verify the proof.
Default: public.json
verify command
==============
snarkjs verify <options>
The command returns "OK" if the proof is valid
and "INVALID" in case it is not a valid proof.
--vk or --verificationkey <verificationKeyFile>
Input Filename with the verification key (generated during the setup).
Default: verification_key.json
-p or --proof
Input filenam with the zero knowlage proof you want to verify
Default: proof.json
--pub or --public <publicFilename>
Input filename with the public wires/signals.
Default: public.json
generate solidity verifier command
==================================
snarkjs generateverifier <options>
Generates a solidity smart contract that verifies the zero knowlage proof.
--vk or --verificationkey <verificationKeyFile>
Input Filename with the verification key (generated during the setup).
Default: verification_key.json
-v or --verifier
Output file with a solidity smart contract that verifies a zero knowlage proof.
Default: verifier.sol
generate call parameters
========================
snarkjs generatecall <options>
Outputs into the console the raw parameters to be used in 'verifyProof'
method of the solidity verifier.
-p or --proof
Input filenam with the zero knowlage proof you want to use
Default: proof.json
--pub or --public <publicFilename>
Input filename with the public wires/signals.
Default: public.json
`)
.alias("c", "circuit")
.alias("pk", "provingkey")
.alias("vk", "verificationkey")
.alias("w", "witness")
.alias("p", "proof")
.alias("i", "input")
.alias("pub", "public")
.alias("v", "verifier")
.help("h")
.alias("h", "help")
.epilogue(`Copyright (C) 2018 0kims association
This program comes with ABSOLUTELY NO WARRANTY;
This is free software, and you are welcome to redistribute it
under certain conditions; see the COPYING file in the official
repo directory at https://github.com/iden3/circom `)
.argv;
const circuitName = (argv.circuit) ? argv.circuit : "circuit.json";
const provingKeyName = (argv.provingkey) ? argv.provingkey : "proving_key.json";
const verificationKeyName = (argv.verificationkey) ? argv.verificationkey : "verification_key.json";
const inputName = (argv.input) ? argv.input : "input.json";
const witnessName = (argv.witness) ? argv.witness : "witness.json";
const proofName = (argv.proof) ? argv.proof : "proof.json";
const publicName = (argv.public) ? argv.public : "public.json";
const verifierName = (argv.public) ? argv.public : "verifier.sol";
function p256(n) {
let nstr = n.toString(16);
while (nstr.length < 64) nstr = "0"+nstr;
nstr = `"0x${nstr}"`;
return nstr;
}
try {
if (argv._[0].toUpperCase() == "SETUP") {
const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8"));
const cir = new zkSnark.Circuit(cirDef);
const setup = zkSnark.setup(cir);
fs.writeFileSync(provingKeyName, JSON.stringify(stringifyBigInts(setup.vk_proof), null, 1), "utf-8");
fs.writeFileSync(verificationKeyName, JSON.stringify(stringifyBigInts(setup.vk_verifier), null, 1), "utf-8");
process.exit(0);
} else if (argv._[0].toUpperCase() == "CALCULATEWITNESS") {
const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8"));
const cir = new zkSnark.Circuit(cirDef);
const input = unstringifyBigInts(JSON.parse(fs.readFileSync(inputName, "utf8")));
const witness = cir.calculateWitness(input);
fs.writeFileSync(witnessName, JSON.stringify(stringifyBigInts(witness), null, 1), "utf-8");
process.exit(0);
} else if (argv._[0].toUpperCase() == "PROOF") {
const witness = unstringifyBigInts(JSON.parse(fs.readFileSync(witnessName, "utf8")));
const provingKey = unstringifyBigInts(JSON.parse(fs.readFileSync(provingKeyName, "utf8")));
const {proof, publicSignals} = zkSnark.genProof(provingKey, witness);
fs.writeFileSync(proofName, JSON.stringify(stringifyBigInts(proof), null, 1), "utf-8");
fs.writeFileSync(publicName, JSON.stringify(stringifyBigInts(publicSignals), null, 1), "utf-8");
process.exit(0);
} else if (argv._[0].toUpperCase() == "VERIFY") {
const public = unstringifyBigInts(JSON.parse(fs.readFileSync(publicName, "utf8")));
const verificationKey = unstringifyBigInts(JSON.parse(fs.readFileSync(verificationKeyName, "utf8")));
const proof = unstringifyBigInts(JSON.parse(fs.readFileSync(proofName, "utf8")));
const isValid = zkSnark.isValid(verificationKey, proof, public);
if (isValid) {
console.log("OK");
process.exit(0);
} else {
console.log("INVALID");
process.exit(1);
}
} else if (argv._[0].toUpperCase() == "GENERATEVERIFIER") {
const verificationKey = unstringifyBigInts(JSON.parse(fs.readFileSync(verificationKeyName, "utf8")));
let template = fs.readFileSync(path.join( __dirname, "templates", "verifier.sol"), "utf-8");
const vka_str = `[${verificationKey.vk_a[0][1].toString()},`+
`${verificationKey.vk_a[0][0].toString()}], `+
`[${verificationKey.vk_a[1][1].toString()},` +
`${verificationKey.vk_a[1][0].toString()}]`;
template = template.replace("<%vk_a%>", vka_str);
const vkb_str = `${verificationKey.vk_b[0].toString()},`+
`${verificationKey.vk_b[1].toString()}`;
template = template.replace("<%vk_b%>", vkb_str);
const vkc_str = `[${verificationKey.vk_c[0][1].toString()},`+
`${verificationKey.vk_c[0][0].toString()}], `+
`[${verificationKey.vk_c[1][1].toString()},` +
`${verificationKey.vk_c[1][0].toString()}]`;
template = template.replace("<%vk_c%>", vkc_str);
const vkg_str = `[${verificationKey.vk_g[0][1].toString()},`+
`${verificationKey.vk_g[0][0].toString()}], `+
`[${verificationKey.vk_g[1][1].toString()},` +
`${verificationKey.vk_g[1][0].toString()}]`;
template = template.replace("<%vk_g%>", vkg_str);
const vkgb1_str = `${verificationKey.vk_gb_1[0].toString()},`+
`${verificationKey.vk_gb_1[1].toString()}`;
template = template.replace("<%vk_gb1%>", vkgb1_str);
const vkgb2_str = `[${verificationKey.vk_gb_2[0][1].toString()},`+
`${verificationKey.vk_gb_2[0][0].toString()}], `+
`[${verificationKey.vk_gb_2[1][1].toString()},` +
`${verificationKey.vk_gb_2[1][0].toString()}]`;
template = template.replace("<%vk_gb2%>", vkgb2_str);
const vkz_str = `[${verificationKey.vk_z[0][1].toString()},`+
`${verificationKey.vk_z[0][0].toString()}], `+
`[${verificationKey.vk_z[1][1].toString()},` +
`${verificationKey.vk_z[1][0].toString()}]`;
template = template.replace("<%vk_z%>", vkz_str);
// The points
template = template.replace("<%vk_input_length%>", (verificationKey.A.length-1).toString());
template = template.replace("<%vk_ic_length%>", verificationKey.A.length.toString());
let vi = "";
for (let i=0; i<verificationKey.A.length; i++) {
if (vi != "") vi = vi + " ";
vi = vi + `vk.IC[${i}] = Pairing.G1Point(${verificationKey.A[i][0].toString()},`+
`${verificationKey.A[i][1].toString()});\n`;
}
template = template.replace("<%vk_ic_pts%>", vi);
fs.writeFileSync(verifierName, template, "utf-8");
process.exit(0);
} else if (argv._[0].toUpperCase() == "GENERATECALL") {
const public = unstringifyBigInts(JSON.parse(fs.readFileSync(publicName, "utf8")));
const proof = unstringifyBigInts(JSON.parse(fs.readFileSync(proofName, "utf8")));
inputs = "";
for (let i=0; i<public.length; i++) {
if (inputs != "") inputs = inputs + ",";
inputs = inputs + p256(public[i]);
}
const S=`[${p256(proof.pi_a[0])}, ${p256(proof.pi_a[1])}],` +
`[${p256(proof.pi_ap[0])}, ${p256(proof.pi_ap[1])}],` +
`[[${p256(proof.pi_b[0][1])}, ${p256(proof.pi_b[0][0])}],[${p256(proof.pi_b[1][1])}, ${p256(proof.pi_b[1][0])}]],` +
`[${p256(proof.pi_bp[0])}, ${p256(proof.pi_bp[1])}],` +
`[${p256(proof.pi_c[0])}, ${p256(proof.pi_c[1])}],` +
`[${p256(proof.pi_cp[0])}, ${p256(proof.pi_cp[1])}],` +
`[${p256(proof.pi_h[0])}, ${p256(proof.pi_h[1])}],` +
`[${p256(proof.pi_kp[0])}, ${p256(proof.pi_kp[1])}],` +
`[${inputs}]` ;
console.log(S);
process.exit(0);
}
} catch(err) {
console.log("ERROR: " + err);
process.exit(1);
}

+ 1
- 1
package-lock.json

@ -1,6 +1,6 @@
{
"name": "zksnark",
"version": "0.0.5",
"version": "0.0.11",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

+ 9
- 3
package.json

@ -1,11 +1,17 @@
{
"name": "zksnark",
"version": "0.0.11",
"name": "snarkjs",
"version": "0.1.0",
"description": "zkSNARKs implementation in JavaScript",
"main": "index.js",
"scripts": {
"test": "mocha"
},
"bin": {
"snarkjs": "cli.js"
},
"directories": {
"templates": "templates"
},
"keywords": [
"zksnark",
"zcash",
@ -19,7 +25,7 @@
"license": "GPL-3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/iden3/zksnark.git"
"url": "https://github.com/iden3/snarkjs.git"
},
"dependencies": {
"big-integer": "^1.6.35",

+ 0
- 1
sha256_2_vk_proof.json
File diff suppressed because it is too large
View File


+ 0
- 1
sha256_2_vk_verifier.json
File diff suppressed because it is too large
View File


+ 1
- 1
src/bigint.js

@ -339,7 +339,7 @@ wBigInt.inverse = function(a, q) {
};
wBigInt.prototype.inverse = function (q) {
return wBigInt.genInverse(this, q);
return wBigInt.genInverse(q)(this);
};
wBigInt.add = function(a, b, q) {

+ 2
- 2
src/calculateWitness.js

@ -154,7 +154,7 @@ class RTCtx {
if (typeof(this.witness[sId]) == "undefined") {
firstInit = true;
}
this.witness[sId] = value;
this.witness[sId] = bigInt(value);
const callComponents = [];
for (let i=0; i<this.circuit.signals[sId].triggerComponents.length; i++) {
var idCmp = this.circuit.signals[sId].triggerComponents[i];
@ -164,7 +164,7 @@ class RTCtx {
callComponents.map( (c) => {
if (this.notInitSignals[c] == 0) this.triggerComponent(c);
});
return value;
return this.witness[sId];
}
setVar(name, sels, value) {

+ 52
- 0
src/circuit.js

@ -59,6 +59,58 @@ module.exports = class Circuit {
return calculateWitness(this, input, log);
}
checkWitness(w) {
const evalLC = (lc, w) => {
let acc = bigInt(0);
for (let k in lc) {
acc= acc.add(bigInt(w[k]).mul(bigInt(lc[k]))).mod(__P__);
}
return acc;
}
const checkConstraint = (ct, w) => {
const a=evalLC(ct[0],w);
const b=evalLC(ct[1],w);
const c=evalLC(ct[2],w);
const res = (a.mul(b).sub(c)).affine(__P__);
if (!res.isZero()) return false;
return true;
}
for (let i=0; i<this.constraints.length; i++) {
if (!checkConstraint(this.constraints[i], w)) {
this.printCostraint(this.constraints[i]);
return false;
}
}
return true;
}
printCostraint(c) {
const lc2str = (lc) => {
let S = "";
for (let k in lc) {
const name = this.signals[k].names[0];
let v = bigInt(lc[k]);
let vs;
if (!v.lesserOrEquals(__P__.shr(bigInt(1)))) {
v = __P__.sub(v);
vs = "-"+v.toString();
} else {
vs = "+"+v.toString();
}
S= S + " " + vs + name;
}
return S;
}
const S = `[ ${lc2str(c[0])} ] * [ ${lc2str(c[1])} ] - [ ${lc2str(c[2])} ]`;
console.log(S);
}
getSignalIdx(name) {
if (typeof(this.signalName2Idx[name]) != "undefined") return this.signalName2Idx[name];
if (!isNaN(name)) return Number(name);

+ 72
- 65
src/gcurve.js

@ -3,17 +3,17 @@
This file is part of zksnark JavaScript library.
zksnark JavaScript library is a free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your option)
zksnark JavaScript library is a free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your option)
any later version.
zksnark JavaScript library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
You should have received a copy of the GNU General Public License along with
zksnark JavaScript library. If not, see <https://www.gnu.org/licenses/>.
*/
@ -34,55 +34,57 @@ class GCurve {
add(p1, p2) {
const F = this.F;
if (this.isZero(p1)) return p2;
if (this.isZero(p2)) return p1;
const res = new Array(3);
const Z1Z1 = this.F.square( p1[2] );
const Z2Z2 = this.F.square( p2[2] );
const Z1Z1 = F.square( p1[2] );
const Z2Z2 = F.square( p2[2] );
const U1 = this.F.mul( p1[0] , Z2Z2 ); // U1 = X1 * Z2Z2
const U2 = this.F.mul( p2[0] , Z1Z1 ); // U2 = X2 * Z1Z1
const U1 = F.mul( p1[0] , Z2Z2 ); // U1 = X1 * Z2Z2
const U2 = F.mul( p2[0] , Z1Z1 ); // U2 = X2 * Z1Z1
const Z1_cubed = this.F.mul( p1[2] , Z1Z1);
const Z2_cubed = this.F.mul( p2[2] , Z2Z2);
const Z1_cubed = F.mul( p1[2] , Z1Z1);
const Z2_cubed = F.mul( p2[2] , Z2Z2);
const S1 = this.F.mul( p1[1] , Z2_cubed); // S1 = Y1 * Z2 * Z2Z2
const S2 = this.F.mul( p2[1] , Z1_cubed); // S2 = Y2 * Z1 * Z1Z1
const S1 = F.mul( p1[1] , Z2_cubed); // S1 = Y1 * Z2 * Z2Z2
const S2 = F.mul( p2[1] , Z1_cubed); // S2 = Y2 * Z1 * Z1Z1
if (this.F.equals(U1,U2) && this.F.equals(S1,S2)) {
if (F.equals(U1,U2) && F.equals(S1,S2)) {
return this.double(p1);
}
const H = this.F.sub( U2 , U1 ); // H = U2-U1
const H = F.sub( U2 , U1 ); // H = U2-U1
const S2_minus_S1 = this.F.sub( S2 , S1 );
const S2_minus_S1 = F.sub( S2 , S1 );
const I = this.F.square( this.F.add(H,H) ); // I = (2 * H)^2
const J = this.F.mul( H , I ); // J = H * I
const I = F.square( F.add(H,H) ); // I = (2 * H)^2
const J = F.mul( H , I ); // J = H * I
const r = this.F.add( S2_minus_S1 , S2_minus_S1 ); // r = 2 * (S2-S1)
const V = this.F.mul( U1 , I ); // V = U1 * I
const r = F.add( S2_minus_S1 , S2_minus_S1 ); // r = 2 * (S2-S1)
const V = F.mul( U1 , I ); // V = U1 * I
res[0] =
this.F.sub(
this.F.sub( this.F.square(r) , J ),
this.F.add( V , V )); // X3 = r^2 - J - 2 * V
F.sub(
F.sub( F.square(r) , J ),
F.add( V , V )); // X3 = r^2 - J - 2 * V
const S1_J = this.F.mul( S1 , J );
const S1_J = F.mul( S1 , J );
res[1] =
this.F.sub(
this.F.mul( r , this.F.sub(V,res[0])),
this.F.add( S1_J,S1_J )); // Y3 = r * (V-X3)-2 S1 J
F.sub(
F.mul( r , F.sub(V,res[0])),
F.add( S1_J,S1_J )); // Y3 = r * (V-X3)-2 S1 J
res[2] =
this.F.mul(
F.mul(
H,
this.F.sub(
this.F.square( this.F.add(p1[2],p2[2]) ),
this.F.add( Z1Z1 , Z2Z2 ))); // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H
F.sub(
F.square( F.add(p1[2],p2[2]) ),
F.add( Z1Z1 , Z2Z2 ))); // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H
return res;
}
@ -96,38 +98,40 @@ class GCurve {
}
double(p) {
const F = this.F;
const res = new Array(3);
if (this.isZero(p)) return p;
const A = this.F.square( p[0] ); // A = X1^2
const B = this.F.square( p[1] ); // B = Y1^2
const C = this.F.square( B ); // C = B^2
const A = F.square( p[0] ); // A = X1^2
const B = F.square( p[1] ); // B = Y1^2
const C = F.square( B ); // C = B^2
let D =
this.F.sub(
this.F.square( this.F.add(p[0] , B )),
this.F.add( A , C));
D = this.F.add(D,D); // D = 2 * ((X1 + B)^2 - A - C)
F.sub(
F.square( F.add(p[0] , B )),
F.add( A , C));
D = F.add(D,D); // D = 2 * ((X1 + B)^2 - A - C)
const E = this.F.add( this.F.add(A,A), A); // E = 3 * A
const F = this.F.square( E ); // F = E^2
const E = F.add( F.add(A,A), A); // E = 3 * A
const FF =F.square( E ); // F = E^2
res[0] = this.F.sub( F , this.F.add(D,D) ); // X3 = F - 2 D
res[0] = F.sub( FF , F.add(D,D) ); // X3 = F - 2 D
let eightC = this.F.add( C , C );
eightC = this.F.add( eightC , eightC );
eightC = this.F.add( eightC , eightC );
let eightC = F.add( C , C );
eightC = F.add( eightC , eightC );
eightC = F.add( eightC , eightC );
res[1] =
this.F.sub(
this.F.mul(
F.sub(
F.mul(
E,
this.F.sub( D, res[0] )),
F.sub( D, res[0] )),
eightC); // Y3 = E * (D - X3) - 8 * C
const Y1Z1 = this.F.mul( p[1] , p[2] );
res[2] = this.F.add( Y1Z1 , Y1Z1 ); // Z3 = 2 * Y1 * Z1
const Y1Z1 = F.mul( p[1] , p[2] );
res[2] = F.add( Y1Z1 , Y1Z1 ); // Z3 = 2 * Y1 * Z1
return res;
}
@ -137,39 +141,42 @@ class GCurve {
}
affine(p) {
const F = this.F;
if (this.isZero(p)) {
return this.zero;
} else {
const Z_inv = this.F.inverse(p[2]);
const Z2_inv = this.F.square(Z_inv);
const Z3_inv = this.F.mul(Z2_inv, Z_inv);
const Z_inv = F.inverse(p[2]);
const Z2_inv = F.square(Z_inv);
const Z3_inv = F.mul(Z2_inv, Z_inv);
const res = new Array(3);
res[0] = this.F.affine( this.F.mul(p[0],Z2_inv));
res[1] = this.F.affine( this.F.mul(p[1],Z3_inv));
res[2] = this.F.one;
res[0] = F.affine( F.mul(p[0],Z2_inv));
res[1] = F.affine( F.mul(p[1],Z3_inv));
res[2] = F.one;
return res;
}
}
equals(p1, p2) {
const F = this.F;
if (this.isZero(p1)) return this.isZero(p2);
if (this.isZero(p2)) return this.isZero(p1);
const Z1Z1 = this.F.square( p1[2] );
const Z2Z2 = this.F.square( p2[2] );
const Z1Z1 = F.square( p1[2] );
const Z2Z2 = F.square( p2[2] );
const U1 = this.F.mul( p1[0] , Z2Z2 );
const U2 = this.F.mul( p2[0] , Z1Z1 );
const U1 = F.mul( p1[0] , Z2Z2 );
const U2 = F.mul( p2[0] , Z1Z1 );
const Z1_cubed = this.F.mul( p1[2] , Z1Z1);
const Z2_cubed = this.F.mul( p2[2] , Z2Z2);
const Z1_cubed = F.mul( p1[2] , Z1Z1);
const Z2_cubed = F.mul( p2[2] , Z2Z2);
const S1 = this.F.mul( p1[1] , Z2_cubed);
const S2 = this.F.mul( p2[1] , Z1_cubed);
const S1 = F.mul( p1[1] , Z2_cubed);
const S2 = F.mul( p2[1] , Z1_cubed);
return (this.F.equals(U1,U2) && this.F.equals(S1,S2));
return (F.equals(U1,U2) && F.equals(S1,S2));
}
toString(p) {

+ 2
- 2
src/prover.js

@ -118,7 +118,7 @@ module.exports = function genProof(vk_proof, witness) {
const h = calculateH(vk_proof, witness, d1, d2, d3);
console.log(h.length + "/" + vk_proof.hExps.length);
// console.log(h.length + "/" + vk_proof.hExps.length);
for (let i = 0; i < h.length; i++) {
proof.pi_h = G1.add( proof.pi_h, G1.mulScalar( vk_proof.hExps[i], h[i]));
@ -133,7 +133,7 @@ module.exports = function genProof(vk_proof, witness) {
proof.pi_kp = G1.affine(proof.pi_kp);
proof.pi_h = G1.affine(proof.pi_h);
proof.h=h;
// proof.h=h;
const publicSignals = witness.slice(1, vk_proof.nPublic+1);

+ 1
- 1
src/setup.js

@ -126,7 +126,7 @@ function calculateEncriptedValuesAtT(setup, circuit) {
setup.vk_proof.Bp = new Array(circuit.nVars+1);
setup.vk_proof.Cp = new Array(circuit.nVars+1);
setup.vk_proof.Kp = new Array(circuit.nVars+3);
setup.vk_verifier.A = new Array(circuit.nVars);
setup.vk_verifier.A = new Array(circuit.nPublic);
setup.toxic.ka = F.random();
setup.toxic.kb = F.random();

+ 36
- 0
src/stringifybigint.js

@ -0,0 +1,36 @@
const bigInt = require("./bigint.js");
module.exports.stringifyBigInts = stringifyBigInts;
module.exports.unstringifyBigInts = unstringifyBigInts;
function stringifyBigInts(o) {
if ((typeof(o) == "bigint") || (o instanceof bigInt)) {
return o.toString(10);
} else if (Array.isArray(o)) {
return o.map(stringifyBigInts);
} else if (typeof o == "object") {
const res = {};
for (let k in o) {
res[k] = stringifyBigInts(o[k]);
}
return res;
} else {
return o;
}
}
function unstringifyBigInts(o) {
if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) {
return bigInt(o);
} else if (Array.isArray(o)) {
return o.map(unstringifyBigInts);
} else if (typeof o == "object") {
const res = {};
for (let k in o) {
res[k] = unstringifyBigInts(o[k]);
}
return res;
} else {
return o;
}
}

+ 243
- 0
templates/verifier.sol

@ -0,0 +1,243 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
pragma solidity ^0.4.14;
library Pairing {
struct G1Point {
uint X;
uint Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint[2] X;
uint[2] Y;
}
/// @return the generator of G1
function P1() pure internal returns (G1Point) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() pure internal returns (G2Point) {
// Original code point
return G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
/*
// Changed by Jordi point
return G2Point(
[10857046999023057135944570762232829481370756359578518086990519993285655852781,
11559732032986387107991004021392285783925812861821192530917403151452391805634],
[8495653923123431417604973247489272438418190587263600148770280649306958101930,
4082367875863433681332203403145435568316851327593401208105741076214120093531]
);
*/
}
/// @return the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point p) pure internal returns (G1Point) {
// The prime q in the base field F_q for G1
uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
if (p.X == 0 && p.Y == 0)
return G1Point(0, 0);
return G1Point(p.X, q - (p.Y % q));
}
/// @return the sum of two points of G1
function addition(G1Point p1, G1Point p2) view internal returns (G1Point r) {
uint[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
assembly {
success := staticcall(sub(gas, 2000), 6, input, 0xc0, r, 0x60)
// Use "invalid" to make gas estimation work
switch success case 0 { invalid() }
}
require(success);
}
/// @return the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point p, uint s) view internal returns (G1Point r) {
uint[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
assembly {
success := staticcall(sub(gas, 2000), 7, input, 0x80, r, 0x60)
// Use "invalid" to make gas estimation work
switch success case 0 { invalid() }
}
require (success);
}
/// @return the result of computing the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should
/// return true.
function pairing(G1Point[] p1, G2Point[] p2) view internal returns (bool) {
require(p1.length == p2.length);
uint elements = p1.length;
uint inputSize = elements * 6;
uint[] memory input = new uint[](inputSize);
for (uint i = 0; i < elements; i++)
{
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint[1] memory out;
bool success;
assembly {
success := staticcall(sub(gas, 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
// Use "invalid" to make gas estimation work
switch success case 0 { invalid() }
}
require(success);
return out[0] != 0;
}
/// Convenience method for a pairing check for two pairs.
function pairingProd2(G1Point a1, G2Point a2, G1Point b1, G2Point b2) view internal returns (bool) {
G1Point[] memory p1 = new G1Point[](2);
G2Point[] memory p2 = new G2Point[](2);
p1[0] = a1;
p1[1] = b1;
p2[0] = a2;
p2[1] = b2;
return pairing(p1, p2);
}
/// Convenience method for a pairing check for three pairs.
function pairingProd3(
G1Point a1, G2Point a2,
G1Point b1, G2Point b2,
G1Point c1, G2Point c2
) view internal returns (bool) {
G1Point[] memory p1 = new G1Point[](3);
G2Point[] memory p2 = new G2Point[](3);
p1[0] = a1;
p1[1] = b1;
p1[2] = c1;
p2[0] = a2;
p2[1] = b2;
p2[2] = c2;
return pairing(p1, p2);
}
/// Convenience method for a pairing check for four pairs.
function pairingProd4(
G1Point a1, G2Point a2,
G1Point b1, G2Point b2,
G1Point c1, G2Point c2,
G1Point d1, G2Point d2
) view internal returns (bool) {
G1Point[] memory p1 = new G1Point[](4);
G2Point[] memory p2 = new G2Point[](4);
p1[0] = a1;
p1[1] = b1;
p1[2] = c1;
p1[3] = d1;
p2[0] = a2;
p2[1] = b2;
p2[2] = c2;
p2[3] = d2;
return pairing(p1, p2);
}
}
contract Verifier {
using Pairing for *;
struct VerifyingKey {
Pairing.G2Point A;
Pairing.G1Point B;
Pairing.G2Point C;
Pairing.G2Point gamma;
Pairing.G1Point gammaBeta1;
Pairing.G2Point gammaBeta2;
Pairing.G2Point Z;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G1Point A_p;
Pairing.G2Point B;
Pairing.G1Point B_p;
Pairing.G1Point C;
Pairing.G1Point C_p;
Pairing.G1Point K;
Pairing.G1Point H;
}
function verifyingKey() pure internal returns (VerifyingKey vk) {
vk.A = Pairing.G2Point(<%vk_a%>);
vk.B = Pairing.G1Point(<%vk_b%>);
vk.C = Pairing.G2Point(<%vk_c%>);
vk.gamma = Pairing.G2Point(<%vk_g%>);
vk.gammaBeta1 = Pairing.G1Point(<%vk_gb1%>);
vk.gammaBeta2 = Pairing.G2Point(<%vk_gb2%>);
vk.Z = Pairing.G2Point(<%vk_z%>);
vk.IC = new Pairing.G1Point[](<%vk_ic_length%>);
<%vk_ic_pts%>
}
function verify(uint[] input, Proof proof) view internal returns (uint) {
VerifyingKey memory vk = verifyingKey();
require(input.length + 1 == vk.IC.length);
// Compute the linear combination vk_x
Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
for (uint i = 0; i < input.length; i++)
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i]));
vk_x = Pairing.addition(vk_x, vk.IC[0]);
if (!Pairing.pairingProd2(proof.A, vk.A, Pairing.negate(proof.A_p), Pairing.P2())) return 1;
if (!Pairing.pairingProd2(vk.B, proof.B, Pairing.negate(proof.B_p), Pairing.P2())) return 2;
if (!Pairing.pairingProd2(proof.C, vk.C, Pairing.negate(proof.C_p), Pairing.P2())) return 3;
if (!Pairing.pairingProd3(
proof.K, vk.gamma,
Pairing.negate(Pairing.addition(vk_x, Pairing.addition(proof.A, proof.C))), vk.gammaBeta2,
Pairing.negate(vk.gammaBeta1), proof.B
)) return 4;
if (!Pairing.pairingProd3(
Pairing.addition(vk_x, proof.A), proof.B,
Pairing.negate(proof.H), vk.Z,
Pairing.negate(proof.C), Pairing.P2()
)) return 5;
return 0;
}
function verifyProof(
uint[2] a,
uint[2] a_p,
uint[2][2] b,
uint[2] b_p,
uint[2] c,
uint[2] c_p,
uint[2] h,
uint[2] k,
uint[<%vk_input_length%>] input
) view public returns (bool r) {
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.A_p = Pairing.G1Point(a_p[0], a_p[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.B_p = Pairing.G1Point(b_p[0], b_p[1]);
proof.C = Pairing.G1Point(c[0], c[1]);
proof.C_p = Pairing.G1Point(c_p[0], c_p[1]);
proof.H = Pairing.G1Point(h[0], h[1]);
proof.K = Pairing.G1Point(k[0], k[1]);
uint[] memory inputValues = new uint[](input.length);
for(uint i = 0; i < input.length; i++){
inputValues[i] = input[i];
}
if (verify(inputValues, proof) == 0) {
return true;
} else {
return false;
}
}
}

+ 65
- 0
templates/verifier_abi.json

@ -0,0 +1,65 @@
[
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "s",
"type": "string"
}
],
"name": "Verified",
"type": "event"
},
{
"constant": false,
"inputs": [
{
"name": "a",
"type": "uint256[2]"
},
{
"name": "a_p",
"type": "uint256[2]"
},
{
"name": "b",
"type": "uint256[2][2]"
},
{
"name": "b_p",
"type": "uint256[2]"
},
{
"name": "c",
"type": "uint256[2]"
},
{
"name": "c_p",
"type": "uint256[2]"
},
{
"name": "h",
"type": "uint256[2]"
},
{
"name": "k",
"type": "uint256[2]"
},
{
"name": "input",
"type": "uint256[2]"
}
],
"name": "verifyTx",
"outputs": [
{
"name": "r",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
]

+ 4
- 31
test/zksnark.js

@ -27,6 +27,9 @@ const zkSnark = require("../index.js");
const BN128 = require("../src/bn128.js");
const PolField = require("../src/polfield.js");
const ZqField = require("../src/zqfield.js");
const {stringifyBigInts, unstringifyBigInts} = require("../src/stringifybigint.js");
const bn128 = new BN128();
const PolF = new PolField(new ZqField(bn128.r));
const G1 = bn128.G1;
@ -35,37 +38,7 @@ const G2 = bn128.G2;
const assert = chai.assert;
function stringifyBigInts(o) {
if ((typeof(o) == "bigint") || (o instanceof bigInt)) {
return o.toString(10);
} else if (Array.isArray(o)) {
return o.map(stringifyBigInts);
} else if (typeof o == "object") {
const res = {};
for (let k in o) {
res[k] = stringifyBigInts(o[k]);
}
return res;
} else {
return o;
}
}
function unstringifyBigInts(o) {
if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) {
return bigInt(o);
} else if (Array.isArray(o)) {
return o.map(unstringifyBigInts);
} else if (typeof o == "object") {
const res = {};
for (let k in o) {
res[k] = unstringifyBigInts(o[k]);
}
return res;
} else {
return o;
}
}
describe("zkSnark", () => {

+ 1
- 1
vk_proof.json
File diff suppressed because it is too large
View File


+ 1
- 1
vk_verifier.json

@ -1 +1 @@
{"nPublic":2,"A":[["19866551811478279859371505738760842460298832691829573450466306875259147816351","18484210313804053852691998481397858585039949227200722719662305248245758849458","1"],["3321197521086530222974755730452803687377653332413676316053594427542097303026","21405036250373007328155097101376947599833245333713640707489754435587971845022","1"],["21833147244326570889506780953761640127646772724320477084900501403705556180608","13228000966455921757863898151554541961470202242230065946010077829374885469919","1"],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"vk_a":[["17284880101934421716867000857655867908135830044531782413024303548989886895730","1735917810785977377641441402870114971383566928423272074303188394633486948966"],["18143813711447758200728255064833995555385678921614879156953742259682697013582","9778931845031431023119429754246894069349980576715652054851141383204525095587"],["1","0"]],"vk_b":["14976617904846839439005826980055141931353928644267029029764697310692939095021","5867142307356813613225767321301226628803608539631022334080355947827485621235","1"],"vk_c":[["14825307856429073007768725150519096517177743964102549507390431522825885473512","2993723324749955168046184125337407556318901678522829604900052191883372228164"],["10596857378882997562444306396128548970225716331660657686316389569267793694877","8924471540644031663480734201722112310725171102165508663043207184149950292723"],["1","0"]],"vk_gb_1":["6391389769949607088371850260826019006443584539084910402039856482240477201196","11459237189519841212595651868736624042781096594211055657773003974759899266504","1"],"vk_gb_2":[["8903022736104336682024560755602518274051619743344817898484205184695903011669","17253174988259244044272263486767974170507168609917129675725408354806456107130"],["7034345039375637030366458266633445787806831685389312798374746515789881396853","21229655513890199467150912049419581060418312327352989132791006661085219742639"],["1","0"]],"vk_g":[["21409225604727282108960769517090184919782401135734772621926559957826424142099","4886558222812229990753251273025235769688607418216792970736499124200668838569"],["10597146209887467940103412590383790281995865109533815104011762238891151306672","6277981791909106949721324666906110645859081424664916287488692958783040780257"],["1","0"]],"vk_z":[["14875504132786978560894206711379200637747665615205380091651641102667915352355","534711614457492228196937099267844466151486371571151310554367455631281265482"],["17462155184890063878837340287437334687618721645486008827392227127539533750814","10005242267604321112420693035002138527489909284960643107354149199565804371109"],["1","0"]]}
{"nPublic":2,"A":[["21783206803516044994174750002568690252068256560383904524664570548274544012277","1679775398117103986758101064951226346356097053425072202459493001797187917029","1"],["3563931453303131448175617496629182396918497049045278511792868802015132125617","17108253597332388611410216938743242005120426021393164810072439917710370685334","1"],["18179154975167298459464967912756929539327940172006222494491237104150902332714","11897109050886577708781458409326193138191930520293738495773116438104193774744","1"],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"vk_a":[["4173169569084855090451015931771305703791038614957422228114247239725673275484","15737814612943777266478815572455893036780131604136610205845198132131788177577"],["1644920580273342432541014783358872312652899730596419348798911195398240709441","17160612290645377130311216483095075521122368171209018500717585377548945449124"],["1","0"]],"vk_b":["3129477430316857273072652156669680608349177144500726024771966478535189917291","2204597623351392423204933166035596624315558069159716487001087795509032407966","1"],"vk_c":[["6922742103746135240859914028276952915767498632628485531113151802414101730779","2493359791500660583968747154877749072901979233596700327715061079445897608264"],["15479419835813324972058251699388948445591919493838401826032382765310218114299","11216226198303890903116858400517129966589639754755110980352510264090367304324"],["1","0"]],"vk_gb_1":["20636273490948975989301814480411448137428962548037114221547396388112418751537","2153047681821913584045881307154242044203392985058304522044183326616941760513","1"],"vk_gb_2":[["563621456460024257753708881112012393912388465269005796975012484248913174902","11703781974560846553921002567783147967101964919208467709816995544499787064518"],["400695514409109256820817717804748868087353053091778307255603601175602390130","804564173322442171955490892303197064166628245840972758087205328751897748494"],["1","0"]],"vk_g":[["15945306278353779575372259791829745890525116619705142648112339784668070264339","2395213805761838023496888843888695283485611819932093758555565635859446667666"],["14128126802440372327888268365395629550202124513234768223004952085604370737789","4732453395557645117865101298914691363869880242145323027177232228553106025538"],["1","0"]],"vk_z":[["8032936434160817668602170465209401652117194389636501044820380642856094643737","5470877429980811677348989917749436245542761942229263490094842318618756128755"],["524782744940140160762259687120679618686923326750254515638261595371928594284","20422436679908706145328503275240616703082912175224896119015320150398834742278"],["1","0"]]}

Loading…
Cancel
Save