Important optimization for the trusted setup

This commit is contained in:
Jordi Baylina 2018-09-23 09:20:01 +02:00
parent 3343981187
commit 16ff407765
No known key found for this signature in database
GPG Key ID: 7480C80C1BE43112
10 changed files with 1162118 additions and 204 deletions

@ -3,28 +3,29 @@
This file is part of zksnark JavaScript library. This file is part of zksnark JavaScript library.
zksnark JavaScript library is a free software: you can redistribute it and/or 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 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) Free Software Foundation, either version 3 of the License, or (at your option)
any later version. any later version.
zksnark JavaScript library is distributed in the hope that it will be useful, zksnark JavaScript library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details. 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/>. zksnark JavaScript library. If not, see <https://www.gnu.org/licenses/>.
*/ */
/* /*
This library does operations on polynomials with coefficients in a field F. This library does operations on polynomials with coefficients in a field F.
A polynomial P(x) = p0 + p1 * x + p2 * x^2 + ... + pn * x^n is represented A polynomial P(x) = p0 + p1 * x + p2 * x^2 + ... + pn * x^n is represented
by the array [ p0, p1, p2, ... , pn ]. by the array [ p0, p1, p2, ... , pn ].
*/ */
const bigInt = require("./bigint.js"); const bigInt = require("./bigint.js");
const assert = require("assert");
class PolField { class PolField {
constructor (F) { constructor (F) {
@ -52,6 +53,35 @@ class PolField {
n--; n--;
} }
this.roots = [];
/* for (let i=0; i<16; i++) {
let r = this.F.one;
n = 1 << i;
const rootsi = new Array(n);
for (let j=0; j<n; j++) {
rootsi[j] = r;
r = this.F.mul(r, this.w[i]);
}
this.roots.push(rootsi);
}
*/
this._setRoots(15);
}
_setRoots(n) {
for (let i=n; (i>=0) && (!this.roots[i]); i--) {
let r = this.F.one;
const nroots = 1 << i;
const rootsi = new Array(nroots);
for (let j=0; j<nroots; j++) {
rootsi[j] = r;
r = this.F.mul(r, this.w[i]);
}
this.roots[i] = rootsi;
}
} }
add(a, b) { add(a, b) {
@ -117,12 +147,14 @@ class PolField {
mulFFT(a,b) { mulFFT(a,b) {
const longestN = Math.max(a.length, b.length); const longestN = Math.max(a.length, b.length);
const bitsResult = log2(longestN-1)+2; const bitsResult = log2(longestN-1)+2;
this._setRoots(bitsResult);
const m = 1 << bitsResult; const m = 1 << bitsResult;
const ea = this.extend(a,m); const ea = this.extend(a,m);
const eb = this.extend(b,m); const eb = this.extend(b,m);
const ta = this._fft(ea, bitsResult, 0, 1, false); const ta = __fft(this, ea, bitsResult, 0, 1, false);
const tb = this._fft(eb, bitsResult, 0, 1, false); const tb = __fft(this, eb, bitsResult, 0, 1, false);
const tres = new Array(m); const tres = new Array(m);
@ -130,7 +162,7 @@ class PolField {
tres[i] = this.F.mul(ta[i], tb[i]); tres[i] = this.F.mul(ta[i], tb[i]);
} }
const res = this._fft(tres, bitsResult, 0, 1, true); const res = __fft(this, tres, bitsResult, 0, 1, true);
const twoinvm = this.F.inverse( this.F.mulScalar(this.F.one, m) ); const twoinvm = this.F.inverse( this.F.mulScalar(this.F.one, m) );
const resn = new Array(m); const resn = new Array(m);
@ -159,7 +191,7 @@ class PolField {
} }
} }
eval(p, x) { eval2(p, x) {
let v = this.F.zero; let v = this.F.zero;
let ix = this.F.one; let ix = this.F.one;
for (let i=0; i<p.length; i++) { for (let i=0; i<p.length; i++) {
@ -169,6 +201,26 @@ class PolField {
return v; return v;
} }
eval(p,x) {
const F = this.F;
if (p.length == 0) return F.zero;
const m = this._next2Power(p.length);
const ep = this.extend(p, m);
return _eval(ep, x, 0, 1, m);
function _eval(p, x, offset, step, n) {
if (n==1) return p[offset];
const newX = F.square(x);
const res= F.add(
_eval(p, newX, offset, step << 1, n >> 1),
F.mul(
x,
_eval(p, newX, offset+step , step << 1, n >> 1)));
return res;
}
}
lagrange(points) { lagrange(points) {
let roots = [this.F.one]; let roots = [this.F.one];
for (let i=0; i<points.length; i++) { for (let i=0; i<points.length; i++) {
@ -188,6 +240,38 @@ class PolField {
return sum; return sum;
} }
fft(p) {
if (p.length <= 1) return p;
const bits = log2(p.length-1)+1;
this._setRoots(bits);
const m = 1 << bits;
const ep = this.extend(p, m);
const res = __fft(this, ep, bits, 0, 1);
return res;
}
ifft(p) {
if (p.length <= 1) return p;
const bits = log2(p.length-1)+1;
this._setRoots(bits);
const m = 1 << bits;
const ep = this.extend(p, m);
const res = __fft(this, ep, bits, 0, 1);
const twoinvm = this.F.inverse( this.F.mulScalar(this.F.one, m) );
const resn = new Array(m);
for (let i=0; i<m; i++) {
resn[i] = this.F.mul(res[(m-i)%m], twoinvm);
}
return resn;
}
_fft(pall, bits, offset, step) { _fft(pall, bits, offset, step) {
const n = 1 << bits; const n = 1 << bits;
@ -354,6 +438,62 @@ class PolField {
return q; return q;
} }
// returns the ith nth-root of one
oneRoot(n, i) {
let nbits = log2(n-1)+1;
let res = this.F.one;
let r = i;
assert(i<n);
assert(1<<nbits === n);
while (r>0) {
if (r & 1 == 1) {
res = this.F.mul(res, this.w[nbits]);
}
r = r >> 1;
nbits --;
}
return res;
}
computeVanishingPolinomial(bits, t) {
const m = 1 << bits;
return this.F.sub(this.F.exp(t, bigInt(m)), this.F.one);
}
evaluateLagrangePolynomials(bits, t) {
const m= 1 << bits;
const tm = this.F.exp(t, bigInt(m));
const u= new Array(m).fill(this.F.zero);
this._setRoots(bits);
const omega = this.w[bits];
if (this.F.equals(tm, this.F.one)) {
for (let i = 0; i < m; i++) {
if (this.F.equals(this.roots[bits][0],t)) { // i.e., t equals omega^i
u[i] = this.F.one;
return u;
}
}
}
const z = this.F.sub(tm, this.F.one);
// let l = this.F.mul(z, this.F.exp(this.F.twoinv, m));
let l = this.F.mul(z, this.F.inverse(bigInt(m)));
for (let i = 0; i < m; i++) {
u[i] = this.F.mul(l, this.F.inverse(this.F.sub(t,this.roots[bits][i])));
l = this.F.mul(l, omega);
}
return u;
}
log2(V) {
return log2(V);
}
} }
function log2( V ) function log2( V )
@ -361,4 +501,31 @@ function log2( V )
return( ( ( V & 0xFFFF0000 ) !== 0 ? ( V &= 0xFFFF0000, 16 ) : 0 ) | ( ( V & 0xFF00FF00 ) !== 0 ? ( V &= 0xFF00FF00, 8 ) : 0 ) | ( ( V & 0xF0F0F0F0 ) !== 0 ? ( V &= 0xF0F0F0F0, 4 ) : 0 ) | ( ( V & 0xCCCCCCCC ) !== 0 ? ( V &= 0xCCCCCCCC, 2 ) : 0 ) | ( ( V & 0xAAAAAAAA ) !== 0 ) ); return( ( ( V & 0xFFFF0000 ) !== 0 ? ( V &= 0xFFFF0000, 16 ) : 0 ) | ( ( V & 0xFF00FF00 ) !== 0 ? ( V &= 0xFF00FF00, 8 ) : 0 ) | ( ( V & 0xF0F0F0F0 ) !== 0 ? ( V &= 0xF0F0F0F0, 4 ) : 0 ) | ( ( V & 0xCCCCCCCC ) !== 0 ? ( V &= 0xCCCCCCCC, 2 ) : 0 ) | ( ( V & 0xAAAAAAAA ) !== 0 ) );
} }
function __fft(PF, pall, bits, offset, step) {
const n = 1 << bits;
if (n==1) {
return [ pall[offset] ];
} else if (n==2) {
return [
PF.F.add(pall[offset], pall[offset + step]),
PF.F.sub(pall[offset], pall[offset + step])];
}
const ndiv2 = n >> 1;
const p1 = __fft(PF, pall, bits-1, offset, step*2);
const p2 = __fft(PF, pall, bits-1, offset+step, step*2);
const out = new Array(n);
for (let i=0; i<ndiv2; i++) {
out[i] = PF.F.add(p1[i], PF.F.mul(PF.roots[bits][i], p2[i]));
out[i+ndiv2] = PF.F.sub(p1[i], PF.F.mul(PF.roots[bits][i], p2[i]));
}
return out;
}
module.exports = PolField; module.exports = PolField;

@ -3,17 +3,17 @@
This file is part of zksnark JavaScript library. This file is part of zksnark JavaScript library.
zksnark JavaScript library is a free software: you can redistribute it and/or 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 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) Free Software Foundation, either version 3 of the License, or (at your option)
any later version. any later version.
zksnark JavaScript library is distributed in the hope that it will be useful, zksnark JavaScript library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details. 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/>. zksnark JavaScript library. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -67,6 +67,7 @@ module.exports = function genProof(vk_proof, witness) {
proof.pi_kp = G1.add( proof.pi_kp, G1.mulScalar( vk_proof.Kp[s], witness[s])); proof.pi_kp = G1.add( proof.pi_kp, G1.mulScalar( vk_proof.Kp[s], witness[s]));
} }
/*
let polA = []; let polA = [];
let polB = []; let polB = [];
let polC = []; let polC = [];
@ -91,11 +92,15 @@ module.exports = function genProof(vk_proof, witness) {
[witness[s]] )); [witness[s]] ));
} }
let polFull = PolF.sub(PolF.mul( polA, polB), polC); let polFull = PolF.sub(PolF.mul( polA, polB), polC);
const h = PolF.div(polFull, vk_proof.polZ ); const h = PolF.div(polFull, vk_proof.polZ );
*/
// console.log(h.length + "/" + vk_proof.hExps.length); const h = calculateH(vk_proof, witness);
console.log(h.length + "/" + vk_proof.hExps.length);
for (let i = 0; i < h.length; i++) { for (let i = 0; i < h.length; i++) {
proof.pi_h = G1.add( proof.pi_h, G1.mulScalar( vk_proof.hExps[i], h[i])); proof.pi_h = G1.add( proof.pi_h, G1.mulScalar( vk_proof.hExps[i], h[i]));
@ -110,7 +115,56 @@ module.exports = function genProof(vk_proof, witness) {
proof.pi_kp = G1.affine(proof.pi_kp); proof.pi_kp = G1.affine(proof.pi_kp);
proof.pi_h = G1.affine(proof.pi_h); proof.pi_h = G1.affine(proof.pi_h);
proof.h=h;
const publicSignals = witness.slice(1, vk_proof.nPublic+1); const publicSignals = witness.slice(1, vk_proof.nPublic+1);
return {proof, publicSignals}; return {proof, publicSignals};
}; };
function calculateH(vk_proof, witness) {
const F = PolF.F;
const m = vk_proof.domainSize;
const polA_T = new Array(m).fill(PolF.F.zero);
const polB_T = new Array(m).fill(PolF.F.zero);
const polC_T = new Array(m).fill(PolF.F.zero);
for (let s=0; s<vk_proof.nVars; s++) {
for (let c in vk_proof.polsA[s]) {
polA_T[c] = F.add(polA_T[c], F.mul(witness[s], vk_proof.polsA[s][c]));
}
for (let c in vk_proof.polsB[s]) {
polB_T[c] = F.add(polB_T[c], F.mul(witness[s], vk_proof.polsB[s][c]));
}
for (let c in vk_proof.polsC[s]) {
polC_T[c] = F.add(polC_T[c], F.mul(witness[s], vk_proof.polsC[s][c]));
}
}
const polA_S = PolF.ifft(polA_T);
const polB_S = PolF.ifft(polB_T);
const polAB_S = PolF.mul(polA_S, polB_S);
const polC_S = PolF.ifft(polC_T);
const polABC_S = PolF.sub(polAB_S, polC_S);
const polZ_S = new Array(m+1).fill(F.zero);
polZ_S[m] = F.one;
polZ_S[0] = F.neg(F.one);
const H_S = PolF.div(polABC_S, polZ_S);
/*
const H2S = PolF.mul(H_S, polZ_S);
if (PolF.equals(H2S, polABC_S)) {
console.log("Is Divisible!");
} else {
console.log("ERROR: Not divisible!");
}
*/
return H_S;
}

@ -3,17 +3,17 @@
This file is part of zksnark JavaScript library. This file is part of zksnark JavaScript library.
zksnark JavaScript library is a free software: you can redistribute it and/or 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 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) Free Software Foundation, either version 3 of the License, or (at your option)
any later version. any later version.
zksnark JavaScript library is distributed in the hope that it will be useful, zksnark JavaScript library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details. 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/>. zksnark JavaScript library. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -43,7 +43,11 @@ module.exports = function setup(circuit) {
toxic: {} toxic: {}
}; };
calculatePolynomials(setup, circuit);
setup.vk_proof.domainBits = PolF.log2(circuit.nConstraints + circuit.nPubInputs + circuit.nOutputs +1 -1) +1;
setup.vk_proof.domainSize = 1 << setup.vk_proof.domainBits;
calculatePolinomials(setup, circuit);
setup.toxic.t = F.random(); setup.toxic.t = F.random();
calculateEncriptedValuesAtT(setup, circuit); calculateEncriptedValuesAtT(setup, circuit);
calculateHexps(setup, circuit); calculateHexps(setup, circuit);
@ -51,128 +55,80 @@ module.exports = function setup(circuit) {
return setup; return setup;
}; };
function calculatePolynomials(setup, circuit) {
// Calculate the points that must cross each polynomial
/* function calculatePolinomials(setup, circuit) {
setup.toxic.aExtra = [];
setup.toxic.bExtra = []; setup.vk_proof.polsA = new Array(circuit.nVars);
setup.toxic.cExtra = []; setup.vk_proof.polsB = new Array(circuit.nVars);
const aPoints = []; setup.vk_proof.polsC = new Array(circuit.nVars);
const bPoints = []; for (let i=0; i<circuit.nVars; i++) {
const cPoints = []; setup.vk_proof.polsA[i] = {};
for (let s = 0; s<circuit.nVars; s++) { setup.vk_proof.polsB[i] = {};
aPoints[s] = []; setup.vk_proof.polsC[i] = {};
bPoints[s] = [];
cPoints[s] = [];
for (let c=0; c<circuit.nConstraints; c++) {
aPoints[s].push([[bigInt(c), F.one], [circuit.a(c, s), F.one]]);
bPoints[s].push([[bigInt(c), F.one], [circuit.b(c, s), F.one]]);
cPoints[s].push([[bigInt(c), F.one], [circuit.c(c, s), F.one]]);
}
// Add an extra point to avoid constant polinolials.
setup.toxic.aExtra[s] = F.random();
setup.toxic.bExtra[s] = F.random();
setup.toxic.cExtra[s] = F.random();
aPoints[s].push([[bigInt(circuit.nConstraints), F.one], [setup.toxic.aExtra[s], F.one]]);
bPoints[s].push([[bigInt(circuit.nConstraints), F.one], [setup.toxic.bExtra[s], F.one]]);
cPoints[s].push([[bigInt(circuit.nConstraints), F.one], [setup.toxic.cExtra[s], F.one]]);
} }
// Calculate the polynomials using Lagrange
setup.vk_proof.polsA = [];
setup.vk_proof.polsB = [];
setup.vk_proof.polsC = [];
for (let s=0; s<circuit.nVars; s++) {
// console.log(`Caclcualte Pol ${s}/${circuit.nVars}`);
const pA = RatPolF.lagrange( aPoints[s] );
const pB = RatPolF.lagrange( bPoints[s] );
const pC = RatPolF.lagrange( cPoints[s] );
setup.vk_proof.polsA.push( unrat(pA) );
setup.vk_proof.polsB.push( unrat(pB) );
setup.vk_proof.polsC.push( unrat(pC) );
}
*/
setup.toxic.aExtra = [];
setup.toxic.bExtra = [];
setup.toxic.cExtra = [];
let allZerosPol = [bigInt(1)];
for (let c=0; c<=circuit.nConstraints; c++) {
allZerosPol = PolF.mul(allZerosPol, [F.neg(bigInt(c)), F.one]);
}
setup.vk_proof.polsA = [];
setup.vk_proof.polsB = [];
setup.vk_proof.polsC = [];
for (let s = 0; s<circuit.nVars; s++) {
setup.vk_proof.polsA.push([]);
setup.vk_proof.polsB.push([]);
setup.vk_proof.polsC.push([]);
}
for (let c=0; c<circuit.nConstraints; c++) { for (let c=0; c<circuit.nConstraints; c++) {
const mpol = PolF.ruffini(allZerosPol, bigInt(c));
const normalizer = PolF.F.inverse(PolF.eval(mpol, bigInt(c)));
for (let s = 0; s<circuit.nVars; s++) {
const factorA = PolF.F.mul(normalizer, circuit.a(c, s));
const spolA = PolF.mulScalar(mpol, factorA);
setup.vk_proof.polsA[s] = PolF.add(setup.vk_proof.polsA[s], spolA);
const factorB = PolF.F.mul(normalizer, circuit.b(c, s)); for (let s in circuit.constraints[c][0]) {
const spolB = PolF.mulScalar(mpol, factorB); setup.vk_proof.polsA[s][c] = bigInt(circuit.constraints[c][0][s]);
setup.vk_proof.polsB[s] = PolF.add(setup.vk_proof.polsB[s], spolB); }
for (let s in circuit.constraints[c][1]) {
const factorC = PolF.F.mul(normalizer, circuit.c(c, s)); setup.vk_proof.polsB[s][c] = bigInt(circuit.constraints[c][1][s]);
const spolC = PolF.mulScalar(mpol, factorC); }
setup.vk_proof.polsC[s] = PolF.add(setup.vk_proof.polsC[s], spolC); for (let s in circuit.constraints[c][2]) {
setup.vk_proof.polsC[s][c] = bigInt(circuit.constraints[c][2][s]);
} }
} }
const mpol = PolF.ruffini(allZerosPol, bigInt(circuit.nConstraints));
const normalizer = PolF.F.inverse(PolF.eval(mpol, bigInt(circuit.nConstraints)));
for (let s = 0; s<circuit.nVars; s++) {
setup.toxic.aExtra[s] = F.random();
const factorA = PolF.F.mul(normalizer, setup.toxic.aExtra[s]);
const spolA = PolF.mulScalar(mpol, factorA);
setup.vk_proof.polsA[s] = PolF.add(setup.vk_proof.polsA[s], spolA);
setup.toxic.bExtra[s] = F.random(); /**
const factorB = PolF.F.mul(normalizer, setup.toxic.bExtra[s]); * add and process the constraints
const spolB = PolF.mulScalar(mpol, factorB); * input_i * 0 = 0
setup.vk_proof.polsB[s] = PolF.add(setup.vk_proof.polsB[s], spolB); * to ensure soundness of input consistency
*/
setup.toxic.cExtra[s] = F.random(); for (let i = 0; i < circuit.nPubInputs + circuit.nOutputs + 1; ++i)
const factorC = PolF.F.mul(normalizer, setup.toxic.cExtra[s]); {
const spolC = PolF.mulScalar(mpol, factorC); setup.vk_proof.polsA[i][circuit.nConstraints + i] = F.one;
setup.vk_proof.polsC[s] = PolF.add(setup.vk_proof.polsC[s], spolC);
}
// Calculate Z polynomial
// Z = 1
setup.vk_proof.polZ = [bigInt(1)];
for (let c=0; c<circuit.nConstraints; c++) {
// Z = Z * (x - p_c)
setup.vk_proof.polZ = PolF.mul(
setup.vk_proof.polZ,
[F.neg(bigInt(c)), bigInt(1)] );
} }
} }
function calculateValuesAtT(setup, circuit) {
const z_t = PolF.computeVanishingPolinomial(setup.vk_proof.domainBits, setup.toxic.t);
const u = PolF.evaluateLagrangePolynomials(setup.vk_proof.domainBits, setup.toxic.t);
const a_t = new Array(circuit.nVars).fill(F.zero);
const b_t = new Array(circuit.nVars).fill(F.zero);
const c_t = new Array(circuit.nVars).fill(F.zero);
// TODO: substitute setup.polsA for coeficients
for (let s=0; s<circuit.nVars; s++) {
for (let c in setup.vk_proof.polsA[s]) {
a_t[s] = F.add(a_t[s], F.mul(u[c], setup.vk_proof.polsA[s][c]));
}
for (let c in setup.vk_proof.polsB[s]) {
b_t[s] = F.add(b_t[s], F.mul(u[c], setup.vk_proof.polsB[s][c]));
}
for (let c in setup.vk_proof.polsC[s]) {
c_t[s] = F.add(c_t[s], F.mul(u[c], setup.vk_proof.polsC[s][c]));
}
}
return {a_t, b_t, c_t, z_t};
}
function calculateEncriptedValuesAtT(setup, circuit) { function calculateEncriptedValuesAtT(setup, circuit) {
setup.vk_proof.A = [];
setup.vk_proof.B = []; const v = calculateValuesAtT(setup, circuit);
setup.vk_proof.C = []; setup.vk_proof.A = new Array(circuit.nVars);
setup.vk_proof.Ap = []; setup.vk_proof.B = new Array(circuit.nVars);
setup.vk_proof.Bp = []; setup.vk_proof.C = new Array(circuit.nVars);
setup.vk_proof.Cp = []; setup.vk_proof.Ap = new Array(circuit.nVars);
setup.vk_proof.Kp = []; setup.vk_proof.Bp = new Array(circuit.nVars);
setup.vk_verifier.A = []; setup.vk_proof.Cp = new Array(circuit.nVars);
setup.vk_proof.Kp = new Array(circuit.nVars);
setup.vk_verifier.A = new Array(circuit.nVars);
setup.toxic.ka = F.random(); setup.toxic.ka = F.random();
setup.toxic.kb = F.random(); setup.toxic.kb = F.random();
@ -192,37 +148,34 @@ function calculateEncriptedValuesAtT(setup, circuit) {
for (let s=0; s<circuit.nVars; s++) { for (let s=0; s<circuit.nVars; s++) {
// A[i] = G1 * polA(t) // A[i] = G1 * polA(t)
const at = F.affine(PolF.eval(setup.vk_proof.polsA[s], setup.toxic.t)); const A = G1.affine(G1.mulScalar(G1.g, v.a_t[s]));
const A = G1.affine(G1.mulScalar(G1.g, at));
setup.vk_proof.A.push(A); setup.vk_proof.A[s] = A;
if (s <= setup.vk_proof.nPublic) { if (s <= setup.vk_proof.nPublic) {
setup.vk_verifier.A.push(A); setup.vk_verifier.A[s]=A;
} }
// B1[i] = G1 * polB(t) // B1[i] = G1 * polB(t)
const bt = F.affine(PolF.eval(setup.vk_proof.polsB[s], setup.toxic.t)); const B1 = G1.affine(G1.mulScalar(G1.g, v.b_t[s]));
const B1 = G1.affine(G1.mulScalar(G1.g, bt));
// B2[i] = G2 * polB(t) // B2[i] = G2 * polB(t)
const B2 = G2.affine(G2.mulScalar(G2.g, bt)); const B2 = G2.affine(G2.mulScalar(G2.g, v.b_t[s]));
setup.vk_proof.B.push(B2); setup.vk_proof.B[s]=B2;
// C[i] = G1 * polC(t) // C[i] = G1 * polC(t)
const ct = F.affine(PolF.eval(setup.vk_proof.polsC[s], setup.toxic.t)); const C = G1.affine(G1.mulScalar( G1.g, v.c_t[s]));
const C = G1.affine(G1.mulScalar( G1.g, ct)); setup.vk_proof.C[s] =C;
setup.vk_proof.C.push (C);
// K = G1 * (A+B+C) // K = G1 * (A+B+C)
const kt = F.affine(F.add(F.add(at, bt), ct)); const kt = F.affine(F.add(F.add(v.a_t[s], v.b_t[s]), v.c_t[s]));
const K = G1.affine(G1.mulScalar( G1.g, kt)); const K = G1.affine(G1.mulScalar( G1.g, kt));
// Comment this lines to improve the process
const Ktest = G1.affine(G1.add(G1.add(A, B1), C)); const Ktest = G1.affine(G1.add(G1.add(A, B1), C));
if (!G1.equals(K, Ktest)) { if (!G1.equals(K, Ktest)) {
@ -231,30 +184,20 @@ function calculateEncriptedValuesAtT(setup, circuit) {
setup.vk_proof.Ap.push(G1.affine(G1.mulScalar(A, setup.toxic.ka))); setup.vk_proof.Ap[s] = G1.affine(G1.mulScalar(A, setup.toxic.ka));
setup.vk_proof.Bp.push(G1.affine(G1.mulScalar(B1, setup.toxic.kb))); setup.vk_proof.Bp[s] = G1.affine(G1.mulScalar(B1, setup.toxic.kb));
setup.vk_proof.Cp.push(G1.affine(G1.mulScalar(C, setup.toxic.kc))); setup.vk_proof.Cp[s] = G1.affine(G1.mulScalar(C, setup.toxic.kc));
setup.vk_proof.Kp.push(G1.affine(G1.mulScalar(K, setup.toxic.kbeta))); setup.vk_proof.Kp[s] = G1.affine(G1.mulScalar(K, setup.toxic.kbeta));
} }
setup.vk_verifier.vk_z = G2.affine(G2.mulScalar( setup.vk_verifier.vk_z = G2.affine(G2.mulScalar(
G2.g, G2.g,
PolF.eval(setup.vk_proof.polZ, setup.toxic.t))); v.z_t));
} }
function calculateHexps(setup, circuit) { function calculateHexps(setup, circuit) {
let maxA = 0;
let maxB = 0;
let maxC = 0;
for (let s=0; s<circuit.nVars; s++) {
maxA = Math.max(maxA, setup.vk_proof.polsA[s].length);
maxB = Math.max(maxB, setup.vk_proof.polsB[s].length);
maxC = Math.max(maxC, setup.vk_proof.polsC[s].length);
}
let maxFull = Math.max(maxA + maxB - 1, maxC); const maxH = setup.vk_proof.domainSize;
const maxH = maxFull - setup.vk_proof.polZ.length + 1;
setup.vk_proof.hExps = new Array(maxH); setup.vk_proof.hExps = new Array(maxH);
setup.vk_proof.hExps[0] = G1.g; setup.vk_proof.hExps[0] = G1.g;
@ -264,12 +207,4 @@ function calculateHexps(setup, circuit) {
eT = F.mul(eT, setup.toxic.t); eT = F.mul(eT, setup.toxic.t);
} }
} }
/*
function unrat(p) {
const res = new Array(p.length);
for (let i=0; i<p.length; i++) {
res[i] = RatPolF.F.toF(p[i]);
}
return res;
}
*/

353
src/setup_old.js Normal file

@ -0,0 +1,353 @@
/*
Copyright 2018 0kims association.
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)
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
more details.
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/>.
*/
const bigInt = require("./bigint.js");
const BN128 = require("./bn128.js");
const PolField = require("./polfield.js");
const ZqField = require("./zqfield.js");
const RatField = require("./ratfield.js");
const bn128 = new BN128();
const G1 = bn128.G1;
const G2 = bn128.G2;
const PolF = new PolField(new ZqField(bn128.r));
const RatPolF = new PolField(new RatField(new ZqField(bn128.r)));
const F = new ZqField(bn128.r);
module.exports = function setup(circuit) {
const setup = {
vk_proof : {
nVars: circuit.nVars,
nPublic: circuit.nPubInputs + circuit.nOutputs
},
vk_verifier: {
nPublic: circuit.nPubInputs + circuit.nOutputs
},
toxic: {}
};
calculatePolynomials2(setup, circuit);
setup.toxic.t = F.random();
calculateEncriptedValuesAtT(setup, circuit);
calculateHexps(setup, circuit);
return setup;
};
function calculatePolynomials(setup, circuit) {
// Calculate the points that must cross each polynomial
/*
setup.toxic.aExtra = [];
setup.toxic.bExtra = [];
setup.toxic.cExtra = [];
const aPoints = [];
const bPoints = [];
const cPoints = [];
for (let s = 0; s<circuit.nVars; s++) {
aPoints[s] = [];
bPoints[s] = [];
cPoints[s] = [];
for (let c=0; c<circuit.nConstraints; c++) {
aPoints[s].push([[bigInt(c), F.one], [circuit.a(c, s), F.one]]);
bPoints[s].push([[bigInt(c), F.one], [circuit.b(c, s), F.one]]);
cPoints[s].push([[bigInt(c), F.one], [circuit.c(c, s), F.one]]);
}
// Add an extra point to avoid constant polinolials.
setup.toxic.aExtra[s] = F.random();
setup.toxic.bExtra[s] = F.random();
setup.toxic.cExtra[s] = F.random();
aPoints[s].push([[bigInt(circuit.nConstraints), F.one], [setup.toxic.aExtra[s], F.one]]);
bPoints[s].push([[bigInt(circuit.nConstraints), F.one], [setup.toxic.bExtra[s], F.one]]);
cPoints[s].push([[bigInt(circuit.nConstraints), F.one], [setup.toxic.cExtra[s], F.one]]);
}
// Calculate the polynomials using Lagrange
setup.vk_proof.polsA = [];
setup.vk_proof.polsB = [];
setup.vk_proof.polsC = [];
for (let s=0; s<circuit.nVars; s++) {
// console.log(`Caclcualte Pol ${s}/${circuit.nVars}`);
const pA = RatPolF.lagrange( aPoints[s] );
const pB = RatPolF.lagrange( bPoints[s] );
const pC = RatPolF.lagrange( cPoints[s] );
setup.vk_proof.polsA.push( unrat(pA) );
setup.vk_proof.polsB.push( unrat(pB) );
setup.vk_proof.polsC.push( unrat(pC) );
}
*/
setup.toxic.aExtra = [];
setup.toxic.bExtra = [];
setup.toxic.cExtra = [];
let allZerosPol = [bigInt(1)];
for (let c=0; c<=circuit.nConstraints; c++) {
allZerosPol = PolF.mul(allZerosPol, [F.neg(bigInt(c)), F.one]);
}
setup.vk_proof.polsA = [];
setup.vk_proof.polsB = [];
setup.vk_proof.polsC = [];
for (let s = 0; s<circuit.nVars; s++) {
setup.vk_proof.polsA.push([]);
setup.vk_proof.polsB.push([]);
setup.vk_proof.polsC.push([]);
}
for (let c=0; c<circuit.nConstraints; c++) {
console.log("Pol: "+ c);
const mpol = PolF.ruffini(allZerosPol, bigInt(c));
const normalizer = PolF.F.inverse(PolF.eval(mpol, bigInt(c)));
for (let s = 0; s<circuit.nVars; s++) {
if (!circuit.a(c, s).isZero()) {
const factorA = PolF.F.mul(normalizer, circuit.a(c, s));
const spolA = PolF.mulScalar(mpol, factorA);
setup.vk_proof.polsA[s] = PolF.add(setup.vk_proof.polsA[s], spolA);
}
if (!circuit.b(c, s).isZero()) {
const factorB = PolF.F.mul(normalizer, circuit.b(c, s));
const spolB = PolF.mulScalar(mpol, factorB);
setup.vk_proof.polsB[s] = PolF.add(setup.vk_proof.polsB[s], spolB);
}
if (!circuit.c(c, s).isZero()) {
const factorC = PolF.F.mul(normalizer, circuit.c(c, s));
const spolC = PolF.mulScalar(mpol, factorC);
setup.vk_proof.polsC[s] = PolF.add(setup.vk_proof.polsC[s], spolC);
}
}
if (global.gc) {
if (c%100 == 0) global.gc();
}
}
const mpol = PolF.ruffini(allZerosPol, bigInt(circuit.nConstraints));
const normalizer = PolF.F.inverse(PolF.eval(mpol, bigInt(circuit.nConstraints)));
for (let s = 0; s<circuit.nVars; s++) {
setup.toxic.aExtra[s] = F.random();
const factorA = PolF.F.mul(normalizer, setup.toxic.aExtra[s]);
const spolA = PolF.mulScalar(mpol, factorA);
setup.vk_proof.polsA[s] = PolF.add(setup.vk_proof.polsA[s], spolA);
setup.toxic.bExtra[s] = F.random();
const factorB = PolF.F.mul(normalizer, setup.toxic.bExtra[s]);
const spolB = PolF.mulScalar(mpol, factorB);
setup.vk_proof.polsB[s] = PolF.add(setup.vk_proof.polsB[s], spolB);
setup.toxic.cExtra[s] = F.random();
const factorC = PolF.F.mul(normalizer, setup.toxic.cExtra[s]);
const spolC = PolF.mulScalar(mpol, factorC);
setup.vk_proof.polsC[s] = PolF.add(setup.vk_proof.polsC[s], spolC);
}
// Calculate Z polynomial
// Z = 1
setup.vk_proof.polZ = [bigInt(1)];
for (let c=0; c<circuit.nConstraints; c++) {
// Z = Z * (x - p_c)
setup.vk_proof.polZ = PolF.mul(
setup.vk_proof.polZ,
[F.neg(bigInt(c)), bigInt(1)] );
}
}
function calculatePolynomials2(setup, circuit) {
setup.toxic.aExtra = [];
setup.toxic.bExtra = [];
setup.toxic.cExtra = [];
setup.vk_proof.polsA = [];
setup.vk_proof.polsB = [];
setup.vk_proof.polsC = [];
const aPoints = new Array(circuit.nConstraints+1);
const bPoints = new Array(circuit.nConstraints+1);
const cPoints = new Array(circuit.nConstraints+1);
for (let s = 0; s<circuit.nVars; s++) {
for (let c=0; c<circuit.nConstraints; c++) {
aPoints[c] = circuit.a(c, s);
bPoints[c] = circuit.b(c, s);
cPoints[c] = circuit.c(c, s);
}
// Add an extra point to avoid constant polinolials.
setup.toxic.aExtra[s] = F.random();
setup.toxic.bExtra[s] = F.random();
setup.toxic.cExtra[s] = F.random();
aPoints[circuit.nConstraints] = setup.toxic.aExtra[s];
bPoints[circuit.nConstraints] = setup.toxic.bExtra[s];
cPoints[circuit.nConstraints] = setup.toxic.cExtra[s];
const pA = PolF.ifft( aPoints );
const pB = PolF.ifft( bPoints );
const pC = PolF.ifft( cPoints );
setup.vk_proof.polsA.push( PolF.affine(pA) );
setup.vk_proof.polsB.push( PolF.affine(pB) );
setup.vk_proof.polsC.push( PolF.affine(pC) );
console.log(s);
if (global.gc) {
if (s%100 == 0) global.gc();
}
}
setup.polsLen=PolF._next2Power(circuit.nConstraints+1);
// Calculate Z polynomial
// Z = 1
const bits= log2(circuit.nConstraints)+1;
const rt1 = PolF.w[bits];
let rt = bigInt(1);
setup.vk_proof.polZ = [F.one];
for (let c=0; c<circuit.nConstraints; c++) {
// Z = Z * (x - p_c)
setup.vk_proof.polZ = PolF.mul(
setup.vk_proof.polZ,
[F.neg(rt), F.one] );
rt = F.mul(rt, rt1);
}
setup.vk_proof.polZ = PolF.affine(setup.vk_proof.polZ);
function log2( V )
{
return( ( ( V & 0xFFFF0000 ) !== 0 ? ( V &= 0xFFFF0000, 16 ) : 0 ) | ( ( V & 0xFF00FF00 ) !== 0 ? ( V &= 0xFF00FF00, 8 ) : 0 ) | ( ( V & 0xF0F0F0F0 ) !== 0 ? ( V &= 0xF0F0F0F0, 4 ) : 0 ) | ( ( V & 0xCCCCCCCC ) !== 0 ? ( V &= 0xCCCCCCCC, 2 ) : 0 ) | ( ( V & 0xAAAAAAAA ) !== 0 ) );
}
}
function calculateEncriptedValuesAtT(setup, circuit) {
setup.vk_proof.A = [];
setup.vk_proof.B = [];
setup.vk_proof.C = [];
setup.vk_proof.Ap = [];
setup.vk_proof.Bp = [];
setup.vk_proof.Cp = [];
setup.vk_proof.Kp = [];
setup.vk_verifier.A = [];
setup.toxic.ka = F.random();
setup.toxic.kb = F.random();
setup.toxic.kc = F.random();
setup.toxic.kbeta = F.random();
setup.toxic.kgamma = F.random();
const gb = F.mul(setup.toxic.kbeta, setup.toxic.kgamma);
setup.vk_verifier.vk_a = G2.affine(G2.mulScalar( G2.g, setup.toxic.ka));
setup.vk_verifier.vk_b = G1.affine(G1.mulScalar( G1.g, setup.toxic.kb));
setup.vk_verifier.vk_c = G2.affine(G2.mulScalar( G2.g, setup.toxic.kc));
setup.vk_verifier.vk_gb_1 = G1.affine(G1.mulScalar( G1.g, gb));
setup.vk_verifier.vk_gb_2 = G2.affine(G2.mulScalar( G2.g, gb));
setup.vk_verifier.vk_g = G2.affine(G2.mulScalar( G2.g, setup.toxic.kgamma));
for (let s=0; s<circuit.nVars; s++) {
// A[i] = G1 * polA(t)
const at = F.affine(PolF.eval(setup.vk_proof.polsA[s], setup.toxic.t));
const A = G1.affine(G1.mulScalar(G1.g, at));
setup.vk_proof.A.push(A);
if (s <= setup.vk_proof.nPublic) {
setup.vk_verifier.A.push(A);
}
// B1[i] = G1 * polB(t)
const bt = F.affine(PolF.eval(setup.vk_proof.polsB[s], setup.toxic.t));
const B1 = G1.affine(G1.mulScalar(G1.g, bt));
// B2[i] = G2 * polB(t)
const B2 = G2.affine(G2.mulScalar(G2.g, bt));
setup.vk_proof.B.push(B2);
// C[i] = G1 * polC(t)
const ct = F.affine(PolF.eval(setup.vk_proof.polsC[s], setup.toxic.t));
const C = G1.affine(G1.mulScalar( G1.g, ct));
setup.vk_proof.C.push (C);
// K = G1 * (A+B+C)
const kt = F.affine(F.add(F.add(at, bt), ct));
const K = G1.affine(G1.mulScalar( G1.g, kt));
const Ktest = G1.affine(G1.add(G1.add(A, B1), C));
if (!G1.equals(K, Ktest)) {
console.log ("=====FAIL======");
}
setup.vk_proof.Ap.push(G1.affine(G1.mulScalar(A, setup.toxic.ka)));
setup.vk_proof.Bp.push(G1.affine(G1.mulScalar(B1, setup.toxic.kb)));
setup.vk_proof.Cp.push(G1.affine(G1.mulScalar(C, setup.toxic.kc)));
setup.vk_proof.Kp.push(G1.affine(G1.mulScalar(K, setup.toxic.kbeta)));
}
setup.vk_verifier.vk_z = G2.affine(G2.mulScalar(
G2.g,
PolF.eval(setup.vk_proof.polZ, setup.toxic.t)));
}
function calculateHexps(setup, circuit) {
let maxA = 0;
let maxB = 0;
let maxC = 0;
for (let s=0; s<circuit.nVars; s++) {
maxA = Math.max(maxA, setup.vk_proof.polsA[s].length);
maxB = Math.max(maxB, setup.vk_proof.polsB[s].length);
maxC = Math.max(maxC, setup.vk_proof.polsC[s].length);
}
let maxFull = Math.max(maxA + maxB - 1, maxC);
const maxH = maxFull - setup.vk_proof.polZ.length + 1;
setup.vk_proof.hExps = new Array(maxH);
setup.vk_proof.hExps[0] = G1.g;
let eT = setup.toxic.t;
for (let i=1; i<maxH; i++) {
setup.vk_proof.hExps[i] = G1.affine(G1.mulScalar(G1.g, eT));
eT = F.mul(eT, setup.toxic.t);
}
}
/*
function unrat(p) {
const res = new Array(p.length);
for (let i=0; i<p.length; i++) {
res[i] = RatPolF.F.toF(p[i]);
}
return res;
}
*/

@ -3,17 +3,17 @@
This file is part of zksnark JavaScript library. This file is part of zksnark JavaScript library.
zksnark JavaScript library is a free software: you can redistribute it and/or 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 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) Free Software Foundation, either version 3 of the License, or (at your option)
any later version. any later version.
zksnark JavaScript library is distributed in the hope that it will be useful, zksnark JavaScript library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details. 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/>. zksnark JavaScript library. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -49,14 +49,6 @@ module.exports = function isValid(vk_verifier, proof, publicSignals) {
bn128.pairing( proof.pi_cp , G2.g ))) bn128.pairing( proof.pi_cp , G2.g )))
return false; return false;
if (! bn128.F12.equals(
bn128.pairing( full_pi_a , proof.pi_b ),
bn128.F12.mul(
bn128.pairing( proof.pi_h , vk_verifier.vk_z ),
bn128.pairing( proof.pi_c , G2.g ),
)))
return false;
if (! bn128.F12.equals( if (! bn128.F12.equals(
bn128.F12.mul( bn128.F12.mul(
bn128.pairing( G1.add(full_pi_a, proof.pi_c) , vk_verifier.vk_gb_2 ), bn128.pairing( G1.add(full_pi_a, proof.pi_c) , vk_verifier.vk_gb_2 ),
@ -65,6 +57,15 @@ module.exports = function isValid(vk_verifier, proof, publicSignals) {
bn128.pairing( proof.pi_kp , vk_verifier.vk_g ))) bn128.pairing( proof.pi_kp , vk_verifier.vk_g )))
return false; return false;
if (! bn128.F12.equals(
bn128.pairing( full_pi_a , proof.pi_b ),
bn128.F12.mul(
bn128.pairing( proof.pi_h , vk_verifier.vk_z ),
bn128.pairing( proof.pi_c , G2.g ),
)))
return false;
return true; return true;

1161222
test/circuit/sha256_2.json Normal file

File diff suppressed because one or more lines are too long

@ -3,17 +3,17 @@
This file is part of zksnark JavaScript library. This file is part of zksnark JavaScript library.
zksnark JavaScript library is a free software: you can redistribute it and/or 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 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) Free Software Foundation, either version 3 of the License, or (at your option)
any later version. any later version.
zksnark JavaScript library is distributed in the hope that it will be useful, zksnark JavaScript library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details. 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/>. zksnark JavaScript library. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -128,6 +128,12 @@ describe("Polynomial field", () => {
const v = PF.eval(p, bigInt(2)); const v = PF.eval(p, bigInt(2));
assert(PF.F.equals(v, bigInt(0))); assert(PF.F.equals(v, bigInt(0)));
}); });
it("Should evaluate bigger number", () => {
const PF = new PolField(new ZqField(r));
const p = [bigInt(1), bigInt(2), bigInt(3)];
const v = PF.eval(p, bigInt(2));
assert(PF.F.equals(v, bigInt(17)));
});
it("Should create lagrange polynomial minmal", () => { it("Should create lagrange polynomial minmal", () => {
const PF = new PolField(new ZqField(r)); const PF = new PolField(new ZqField(r));
@ -168,5 +174,44 @@ describe("Polynomial field", () => {
assert(PF.equals(a, c)); assert(PF.equals(a, c));
}); });
it("Should test roots", () => {
const PF = new PolField(new ZqField(r));
let rt;
rt = PF.oneRoot(256, 16);
for (let i=0; i<8; i++) {
rt = PF.F.mul(rt, rt);
}
assert(rt.equals(PF.F.one));
rt = PF.oneRoot(256, 15);
for (let i=0; i<8; i++) {
rt = PF.F.mul(rt, rt);
}
assert(rt.equals(PF.F.one));
rt = PF.oneRoot(8, 3);
for (let i=0; i<3; i++) {
rt = PF.F.mul(rt, rt);
}
assert(rt.equals(PF.F.one));
rt = PF.oneRoot(8, 0);
assert(rt.equals(PF.F.one));
});
it("Should create a polynomial with values at roots with fft", () => {
const PF = new PolField(new ZqField(r));
const a = [bigInt(1), bigInt(2), bigInt(3), bigInt(4), bigInt(5),bigInt(6), bigInt(7)];
const p = PF.ifft(a);
for (let i=0; i<a.length; i++) {
const s = PF.F.affine(PF.eval(p, PF.oneRoot(8,i)));
assert(s.equals(a[i]));
}
});
}); });

@ -3,17 +3,17 @@
This file is part of zksnark JavaScript library. This file is part of zksnark JavaScript library.
zksnark JavaScript library is a free software: you can redistribute it and/or 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 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) Free Software Foundation, either version 3 of the License, or (at your option)
any later version. any later version.
zksnark JavaScript library is distributed in the hope that it will be useful, zksnark JavaScript library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details. 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/>. zksnark JavaScript library. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -24,6 +24,13 @@ const bigInt = require("../src/bigint.js");
const Circuit = require("../src/circuit.js"); const Circuit = require("../src/circuit.js");
const zkSnark = require("../index.js"); const zkSnark = require("../index.js");
const BN128 = require("../src/bn128.js");
const PolField = require("../src/polfield.js");
const ZqField = require("../src/zqfield.js");
const bn128 = new BN128();
const PolF = new PolField(new ZqField(bn128.r));
const G1 = bn128.G1;
const G2 = bn128.G2;
const assert = chai.assert; const assert = chai.assert;
@ -60,9 +67,11 @@ function unstringifyBigInts(o) {
} }
} }
describe("zkSnark", () => { describe("zkSnark", () => {
it("Load a circuit, create trusted setup, create a proof and validate it", () => { it("Load a circuit, create trusted setup, create a proof and validate it", () => {
const cirDef = JSON.parse(fs.readFileSync(path.join(__dirname, "circuit", "sum.json"), "utf8")); const cirDef = JSON.parse(fs.readFileSync(path.join(__dirname, "circuit", "sum.json"), "utf8"));
const cir = new Circuit(cirDef); const cir = new Circuit(cirDef);
@ -71,17 +80,145 @@ describe("zkSnark", () => {
fs.writeFileSync("vk_proof.json", JSON.stringify(strSetup.vk_proof), "utf-8"); fs.writeFileSync("vk_proof.json", JSON.stringify(strSetup.vk_proof), "utf-8");
fs.writeFileSync("vk_verifier.json", JSON.stringify(strSetup.vk_verifier), "utf-8"); fs.writeFileSync("vk_verifier.json", JSON.stringify(strSetup.vk_verifier), "utf-8");
function polT2S(p) {
const p_T = new Array(setup.vk_proof.domainSize).fill(bigInt(0));
for (let c in p) {
p_T[c] = p[c];
}
return PolF.ifft(p_T);
}
/*
const setup = {};
setup.vk_proof = unstringifyBigInts(JSON.parse(fs.readFileSync("vk_proof.json", "utf8")));
setup.vk_verifier = unstringifyBigInts(JSON.parse(fs.readFileSync("vk_verifier.json", "utf8")));
*/
const witness = cir.calculateWitness({"a": "33", "b": "34"});
const {proof, publicSignals} = zkSnark.genProof(setup.vk_proof, witness);
/*
const polA = new Array(cir.nVars);
const polB = new Array(cir.nVars);
const polC = new Array(cir.nVars);
for (let i=0; i<cir.nVars; i++) {
polA[i] = polT2S(setup.vk_proof.polsA[i]);
polB[i] = polT2S(setup.vk_proof.polsB[i]);
polC[i] = polT2S(setup.vk_proof.polsC[i]);
}
PolF._setRoots(setup.vk_proof.domainBits);
for (let c=0; c<setup.vk_proof.domainSize; c++) {
let A = bigInt(0);
let B = bigInt(0);
let C = bigInt(0);
for (let s=0; s<cir.nVars; s++) {
A = PolF.F.add(A, PolF.F.mul(PolF.eval(polA[s], PolF.roots[setup.vk_proof.domainBits][c]), witness[s]));
B = PolF.F.add(B, PolF.F.mul(PolF.eval(polB[s], PolF.roots[setup.vk_proof.domainBits][c]), witness[s]));
C = PolF.F.add(C, PolF.F.mul(PolF.eval(polC[s], PolF.roots[setup.vk_proof.domainBits][c]), witness[s]));
}
assert(PolF.F.equals(PolF.F.mul(A,B), C));
}
let A = bigInt(0);
let B = bigInt(0);
let C = bigInt(0);
for (let s=0; s<cir.nVars; s++) {
A = PolF.F.add(A, PolF.F.mul(PolF.eval(polA[s], setup.toxic.t), witness[s]));
B = PolF.F.add(B, PolF.F.mul(PolF.eval(polB[s], setup.toxic.t), witness[s]));
C = PolF.F.add(C, PolF.F.mul(PolF.eval(polC[s], setup.toxic.t), witness[s]));
}
let A2 = bigInt(0);
let B2 = bigInt(0);
let C2 = bigInt(0);
const u = PolF.evaluateLagrangePolynomials(setup.vk_proof.domainBits, setup.toxic.t);
for (let s=0; s<cir.nVars; s++) {
let at = PolF.F.zero;
for (let c in setup.vk_proof.polsA[s]) {
at = PolF.F.add(at, PolF.F.mul(u[c], setup.vk_proof.polsA[s][c]));
}
A2 = PolF.F.add(A2, PolF.F.mul(at, witness[s]));
let bt = PolF.F.zero;
for (let c in setup.vk_proof.polsB[s]) {
bt = PolF.F.add(bt, PolF.F.mul(u[c], setup.vk_proof.polsB[s][c]));
}
B2 = PolF.F.add(B2, PolF.F.mul(bt, witness[s]));
let ct = PolF.F.zero;
for (let c in setup.vk_proof.polsC[s]) {
ct = PolF.F.add(ct, PolF.F.mul(u[c], setup.vk_proof.polsC[s][c]));
}
C2 = PolF.F.add(C2, PolF.F.mul(ct, witness[s]));
}
A=PolF.F.affine(A);
B=PolF.F.affine(B);
C=PolF.F.affine(C);
A2=PolF.F.affine(A2);
B2=PolF.F.affine(B2);
C2=PolF.F.affine(C2);
assert(PolF.F.equals(C,C2));
assert(PolF.F.equals(B,B2));
assert(PolF.F.equals(A,A2));
const ABC = PolF.F.affine(PolF.F.sub(PolF.F.mul(A,B), C));
assert.equal(witness[cir.getSignalIdx("main.out")].toString(), "67");
const H = PolF.eval(proof.h, setup.toxic.t).affine();
const Z = PolF.F.sub(PolF.F.exp(setup.toxic.t, setup.vk_proof.domainSize), bigInt(1));
const HZ = PolF.F.affine(PolF.F.mul(H,Z));
assert(PolF.F.equals(ABC, HZ));
const gH = G1.affine(G1.mulScalar( G1.g, H));
const gZ = G2.affine(G2.mulScalar( G2.g, Z));
const gA = G1.affine(G1.mulScalar( G1.g, A));
const gB = G2.affine(G2.mulScalar( G2.g, B));
const gC = G1.affine(G1.mulScalar( G1.g, C));
assert(G1.equals(gH, proof.pi_h));
assert(G2.equals(gZ, setup.vk_verifier.vk_z));
assert(G2.equals(gB, proof.pi_b));
assert(G1.equals(gC, proof.pi_c));
// assert(G1.equals(gA, proof.pi_a));
*/
assert( zkSnark.isValid(setup.vk_verifier, proof, publicSignals));
}).timeout(10000000);
it("validate sha256_2", () => {
const cirDef = JSON.parse(fs.readFileSync(path.join(__dirname, "circuit", "sha256_2.json"), "utf8"));
const cir = new Circuit(cirDef);
console.log("Start setup: "+Date().toString());
const setup = zkSnark.setup(cir);
const strSetup = stringifyBigInts(setup);
fs.writeFileSync("vk_proof.json", JSON.stringify(strSetup.vk_proof), "utf-8");
fs.writeFileSync("vk_verifier.json", JSON.stringify(strSetup.vk_verifier), "utf-8");
/* /*
const setup = {}; const setup = {};
setup.vk_proof = unstringifyBigInts(JSON.parse(fs.readFileSync("vk_proof.json", "utf8"))); setup.vk_proof = unstringifyBigInts(JSON.parse(fs.readFileSync("vk_proof.json", "utf8")));
setup.vk_verifier = unstringifyBigInts(JSON.parse(fs.readFileSync("vk_verifier.json", "utf8"))); setup.vk_verifier = unstringifyBigInts(JSON.parse(fs.readFileSync("vk_verifier.json", "utf8")));
*/ */
const witness = cir.calculateWitness({"a": "33", "b": "34"}); const witness = cir.calculateWitness({"a": "1", "b": "2"});
assert.equal(witness[cir.getSignalIdx("main.out")].toString(), "67"); // assert.equal(witness[cir.getSignalIdx("main.out")].toString(), "67");
console.log("Start calculating the proof: "+Date().toString());
const {proof, publicSignals} = zkSnark.genProof(setup.vk_proof, witness); const {proof, publicSignals} = zkSnark.genProof(setup.vk_proof, witness);
console.log("Start verifiying: "+ Date().toString());
assert( zkSnark.isValid(setup.vk_verifier, proof, publicSignals)); assert( zkSnark.isValid(setup.vk_verifier, proof, publicSignals));
}).timeout(10000000); }).timeout(10000000);
}); });

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long