Important optimization for the trusted setup
This commit is contained in:
parent
3343981187
commit
16ff407765
189
src/polfield.js
189
src/polfield.js
@ -3,28 +3,29 @@
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
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 ].
|
||||
*/
|
||||
|
||||
const bigInt = require("./bigint.js");
|
||||
const assert = require("assert");
|
||||
|
||||
class PolField {
|
||||
constructor (F) {
|
||||
@ -52,6 +53,35 @@ class PolField {
|
||||
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) {
|
||||
@ -117,12 +147,14 @@ class PolField {
|
||||
mulFFT(a,b) {
|
||||
const longestN = Math.max(a.length, b.length);
|
||||
const bitsResult = log2(longestN-1)+2;
|
||||
this._setRoots(bitsResult);
|
||||
|
||||
const m = 1 << bitsResult;
|
||||
const ea = this.extend(a,m);
|
||||
const eb = this.extend(b,m);
|
||||
|
||||
const ta = this._fft(ea, bitsResult, 0, 1, false);
|
||||
const tb = this._fft(eb, bitsResult, 0, 1, false);
|
||||
const ta = __fft(this, ea, bitsResult, 0, 1, false);
|
||||
const tb = __fft(this, eb, bitsResult, 0, 1, false);
|
||||
|
||||
const tres = new Array(m);
|
||||
|
||||
@ -130,7 +162,7 @@ class PolField {
|
||||
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 resn = new Array(m);
|
||||
@ -159,7 +191,7 @@ class PolField {
|
||||
}
|
||||
}
|
||||
|
||||
eval(p, x) {
|
||||
eval2(p, x) {
|
||||
let v = this.F.zero;
|
||||
let ix = this.F.one;
|
||||
for (let i=0; i<p.length; i++) {
|
||||
@ -169,6 +201,26 @@ class PolField {
|
||||
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) {
|
||||
let roots = [this.F.one];
|
||||
for (let i=0; i<points.length; i++) {
|
||||
@ -188,6 +240,38 @@ class PolField {
|
||||
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) {
|
||||
|
||||
const n = 1 << bits;
|
||||
@ -354,6 +438,62 @@ class PolField {
|
||||
|
||||
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 )
|
||||
@ -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 ) );
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
@ -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/>.
|
||||
*/
|
||||
|
||||
@ -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]));
|
||||
}
|
||||
|
||||
/*
|
||||
let polA = [];
|
||||
let polB = [];
|
||||
let polC = [];
|
||||
@ -91,11 +92,15 @@ module.exports = function genProof(vk_proof, witness) {
|
||||
[witness[s]] ));
|
||||
}
|
||||
|
||||
|
||||
let polFull = PolF.sub(PolF.mul( polA, polB), polC);
|
||||
|
||||
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++) {
|
||||
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_h = G1.affine(proof.pi_h);
|
||||
|
||||
proof.h=h;
|
||||
|
||||
const publicSignals = witness.slice(1, vk_proof.nPublic+1);
|
||||
|
||||
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;
|
||||
}
|
||||
|
247
src/setup.js
247
src/setup.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/>.
|
||||
*/
|
||||
|
||||
@ -43,7 +43,11 @@ module.exports = function setup(circuit) {
|
||||
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();
|
||||
calculateEncriptedValuesAtT(setup, circuit);
|
||||
calculateHexps(setup, circuit);
|
||||
@ -51,128 +55,80 @@ module.exports = function 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]]);
|
||||
function calculatePolinomials(setup, circuit) {
|
||||
|
||||
setup.vk_proof.polsA = new Array(circuit.nVars);
|
||||
setup.vk_proof.polsB = new Array(circuit.nVars);
|
||||
setup.vk_proof.polsC = new Array(circuit.nVars);
|
||||
for (let i=0; i<circuit.nVars; i++) {
|
||||
setup.vk_proof.polsA[i] = {};
|
||||
setup.vk_proof.polsB[i] = {};
|
||||
setup.vk_proof.polsC[i] = {};
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
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));
|
||||
const spolB = PolF.mulScalar(mpol, factorB);
|
||||
setup.vk_proof.polsB[s] = PolF.add(setup.vk_proof.polsB[s], spolB);
|
||||
|
||||
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);
|
||||
for (let s in circuit.constraints[c][0]) {
|
||||
setup.vk_proof.polsA[s][c] = bigInt(circuit.constraints[c][0][s]);
|
||||
}
|
||||
for (let s in circuit.constraints[c][1]) {
|
||||
setup.vk_proof.polsB[s][c] = bigInt(circuit.constraints[c][1][s]);
|
||||
}
|
||||
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]);
|
||||
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)] );
|
||||
/**
|
||||
* add and process the constraints
|
||||
* input_i * 0 = 0
|
||||
* to ensure soundness of input consistency
|
||||
*/
|
||||
for (let i = 0; i < circuit.nPubInputs + circuit.nOutputs + 1; ++i)
|
||||
{
|
||||
setup.vk_proof.polsA[i][circuit.nConstraints + i] = F.one;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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 = [];
|
||||
|
||||
const v = calculateValuesAtT(setup, circuit);
|
||||
setup.vk_proof.A = new Array(circuit.nVars);
|
||||
setup.vk_proof.B = new Array(circuit.nVars);
|
||||
setup.vk_proof.C = new Array(circuit.nVars);
|
||||
setup.vk_proof.Ap = new Array(circuit.nVars);
|
||||
setup.vk_proof.Bp = new Array(circuit.nVars);
|
||||
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.kb = F.random();
|
||||
@ -192,37 +148,34 @@ function calculateEncriptedValuesAtT(setup, circuit) {
|
||||
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));
|
||||
const A = G1.affine(G1.mulScalar(G1.g, v.a_t[s]));
|
||||
|
||||
setup.vk_proof.A.push(A);
|
||||
setup.vk_proof.A[s] = A;
|
||||
|
||||
if (s <= setup.vk_proof.nPublic) {
|
||||
setup.vk_verifier.A.push(A);
|
||||
setup.vk_verifier.A[s]=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));
|
||||
const B1 = G1.affine(G1.mulScalar(G1.g, v.b_t[s]));
|
||||
|
||||
// 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)
|
||||
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);
|
||||
const C = G1.affine(G1.mulScalar( G1.g, v.c_t[s]));
|
||||
setup.vk_proof.C[s] =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));
|
||||
|
||||
|
||||
|
||||
// Comment this lines to improve the process
|
||||
const Ktest = G1.affine(G1.add(G1.add(A, B1), C));
|
||||
|
||||
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.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_proof.Ap[s] = G1.affine(G1.mulScalar(A, setup.toxic.ka));
|
||||
setup.vk_proof.Bp[s] = G1.affine(G1.mulScalar(B1, setup.toxic.kb));
|
||||
setup.vk_proof.Cp[s] = G1.affine(G1.mulScalar(C, setup.toxic.kc));
|
||||
setup.vk_proof.Kp[s] = 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)));
|
||||
v.z_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;
|
||||
const maxH = setup.vk_proof.domainSize;
|
||||
|
||||
setup.vk_proof.hExps = new Array(maxH);
|
||||
setup.vk_proof.hExps[0] = G1.g;
|
||||
@ -264,12 +207,4 @@ function calculateHexps(setup, circuit) {
|
||||
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
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.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
@ -49,14 +49,6 @@ module.exports = function isValid(vk_verifier, proof, publicSignals) {
|
||||
bn128.pairing( proof.pi_cp , G2.g )))
|
||||
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(
|
||||
bn128.F12.mul(
|
||||
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 )))
|
||||
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;
|
||||
|
1161222
test/circuit/sha256_2.json
Normal file
1161222
test/circuit/sha256_2.json
Normal file
File diff suppressed because one or more lines are too long
57
test/pols.js
57
test/pols.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/>.
|
||||
*/
|
||||
|
||||
@ -128,6 +128,12 @@ describe("Polynomial field", () => {
|
||||
const v = PF.eval(p, bigInt(2));
|
||||
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", () => {
|
||||
const PF = new PolField(new ZqField(r));
|
||||
|
||||
@ -168,5 +174,44 @@ describe("Polynomial field", () => {
|
||||
|
||||
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]));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
153
test/zksnark.js
153
test/zksnark.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/>.
|
||||
*/
|
||||
|
||||
@ -24,6 +24,13 @@ const bigInt = require("../src/bigint.js");
|
||||
|
||||
const Circuit = require("../src/circuit.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;
|
||||
|
||||
@ -60,9 +67,11 @@ function unstringifyBigInts(o) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
describe("zkSnark", () => {
|
||||
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 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_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 = {};
|
||||
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 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);
|
||||
|
||||
console.log("Start verifiying: "+ Date().toString());
|
||||
assert( zkSnark.isValid(setup.vk_verifier, proof, publicSignals));
|
||||
}).timeout(10000000);
|
||||
});
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user