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

275 lines
9.2 KiB

/*
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: {}
};
calculatePolynomials(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++) {
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);
}
}
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 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;
}
*/