diff --git a/src/plonk_prove.js b/src/plonk_prove.js index 81fa170..c53f53b 100644 --- a/src/plonk_prove.js +++ b/src/plonk_prove.js @@ -63,10 +63,9 @@ export default async function plonk16Prove(zkeyFileName, witnessFileName, logger await calculateAdditions(); let A,B,C,Z; + let A4, B4, C4, Z4; let pol_a,pol_b,pol_c, pol_z, pol_t, pol_r; let proof = {}; - if (logger) logger.debug("Reading L Points"); - const lagrangeBases = await binFileUtils.readSection(fdZKey, sectionsZKey, 14); const sigmaBuff = new BigBuffer(zkey.domainSize*n8r*4*3); let o = sectionsZKey[12][0].p + zkey.domainSize*n8r; @@ -82,12 +81,10 @@ export default async function plonk16Prove(zkeyFileName, witnessFileName, logger const pol_s2 = new BigBuffer(zkey.domainSize*n8r); await fdZKey.readToBuffer(pol_s2, 0 , zkey.domainSize*n8r, sectionsZKey[12][0].p + 5*zkey.domainSize*n8r); - const PTau = await binFileUtils.readSection(fdZKey, sectionsZKey, 15); + const PTau = await binFileUtils.readSection(fdZKey, sectionsZKey, 14); - let alpha, beta, gamma, xi; - let xim; - const b=[]; + const ch = {}; await round1(); await round2(); @@ -112,14 +109,14 @@ export default async function plonk16Prove(zkeyFileName, witnessFileName, logger publicSignals.push(Scalar.fromRprLE(pub)); } - proof.A = G1.toObject(G1.toAffine(proof.A)); - proof.B = G1.toObject(G1.toAffine(proof.B)); - proof.C = G1.toObject(G1.toAffine(proof.C)); - proof.Z = G1.toObject(G1.toAffine(proof.Z)); + proof.A = G1.toObject(proof.A); + proof.B = G1.toObject(proof.B); + proof.C = G1.toObject(proof.C); + proof.Z = G1.toObject(proof.Z); - proof.T1 = G1.toObject(G1.toAffine(proof.T1)); - proof.T2 = G1.toObject(G1.toAffine(proof.T2)); - proof.T3 = G1.toObject(G1.toAffine(proof.T3)); + proof.T1 = G1.toObject(proof.T1); + proof.T2 = G1.toObject(proof.T2); + proof.T3 = G1.toObject(proof.T3); proof.eval_a = Fr.toObject(proof.eval_a); proof.eval_b = Fr.toObject(proof.eval_b); @@ -130,8 +127,8 @@ export default async function plonk16Prove(zkeyFileName, witnessFileName, logger proof.eval_t = Fr.toObject(proof.eval_t); proof.eval_r = Fr.toObject(proof.eval_r); - proof.Wxi = G1.toObject(G1.toAffine(proof.Wxi)); - proof.Wxiw = G1.toObject(G1.toAffine(proof.Wxiw)); + proof.Wxi = G1.toObject(proof.Wxi); + proof.Wxiw = G1.toObject(proof.Wxiw); proof = stringifyBigInts(proof); publicSignals = stringifyBigInts(publicSignals); @@ -161,9 +158,9 @@ export default async function plonk16Prove(zkeyFileName, witnessFileName, logger } async function buildABC() { - const A = new BigBuffer(zkey.domainSize * n8r); - const B = new BigBuffer(zkey.domainSize * n8r); - const C = new BigBuffer(zkey.domainSize * n8r); + let A = new BigBuffer(zkey.domainSize * n8r); + let B = new BigBuffer(zkey.domainSize * n8r); + let C = new BigBuffer(zkey.domainSize * n8r); const aMap = await binFileUtils.readSection(fdZKey, sectionsZKey, 4); const bMap = await binFileUtils.readSection(fdZKey, sectionsZKey, 5); @@ -177,7 +174,11 @@ export default async function plonk16Prove(zkeyFileName, witnessFileName, logger const iC = readUInt32(cMap, i*4); C.set(getWitness(iC), i*n8r); } - + + A = await Fr.batchToMontgomery(A); + B = await Fr.batchToMontgomery(B); + C = await Fr.batchToMontgomery(C); + return [A,B,C]; } @@ -198,32 +199,21 @@ export default async function plonk16Prove(zkeyFileName, witnessFileName, logger } async function round1() { + ch.b = []; for (let i=1; i<=9; i++) { - b[i] = curve.Fr.random(); - b[i] = curve.Fr.e(i); - // b[i] = curve.Fr.zero; + ch.b[i] = curve.Fr.random(); } - + [A, B, C] = await buildABC(); + + [pol_a, A4] = await to4T(A, [ch.b[2], ch.b[1]]); + [pol_b, B4] = await to4T(B, [ch.b[4], ch.b[3]]); + [pol_c, C4] = await to4T(C, [ch.b[6], ch.b[5]]); + - proof.A = await curve.G1.multiExpAffine(lagrangeBases, A, logger, "multiexp A"); - proof.B = await curve.G1.multiExpAffine(lagrangeBases, B, logger, "multiexp B"); - proof.C = await curve.G1.multiExpAffine(lagrangeBases, C, logger, "multiexp C"); - - proof.A = G1.add(proof.A, G1.timesFr(zkey.XtoMplus1, b[1])); - proof.A = G1.sub(proof.A, G1.timesFr(zkey.X, b[1])); - proof.A = G1.add(proof.A, G1.timesFr(zkey.XtoM, b[2])); - proof.A = G1.sub(proof.A, G1.timesFr(G1.one, b[2])); - - proof.B = G1.add(proof.B, G1.timesFr(zkey.XtoMplus1, b[3])); - proof.B = G1.sub(proof.B, G1.timesFr(zkey.X, b[3])); - proof.B = G1.add(proof.B, G1.timesFr(zkey.XtoM, b[4])); - proof.B = G1.sub(proof.B, G1.timesFr(G1.one, b[4])); - - proof.C = G1.add(proof.C, G1.timesFr(zkey.XtoMplus1, b[5])); - proof.C = G1.sub(proof.C, G1.timesFr(zkey.X, b[5])); - proof.C = G1.add(proof.C, G1.timesFr(zkey.XtoM, b[6])); - proof.C = G1.sub(proof.C, G1.timesFr(G1.one, b[6])); + proof.A = await expTau(pol_a, "multiexp A"); + proof.B = await expTau(pol_b, "multiexp B"); + proof.C = await expTau(pol_c, "multiexp C"); } async function round2() { @@ -233,18 +223,14 @@ export default async function plonk16Prove(zkeyFileName, witnessFileName, logger G1.toRprUncompressed(transcript1, G1.F.n8*2, proof.B); G1.toRprUncompressed(transcript1, G1.F.n8*4, proof.C); - beta = hashToFr(transcript1); - if (logger) logger.debug("beta: " + Fr.toString(beta)); + ch.beta = hashToFr(transcript1); + if (logger) logger.debug("beta: " + Fr.toString(ch.beta)); const transcript2 = new Uint8Array(n8r); - Fr.toRprBE(transcript2, 0, beta); - gamma = hashToFr(transcript2); - if (logger) logger.debug("gamma: " + Fr.toString(gamma)); + Fr.toRprBE(transcript2, 0, ch.beta); + ch.gamma = hashToFr(transcript2); + if (logger) logger.debug("gamma: " + Fr.toString(ch.gamma)); - A = await Fr.batchToMontgomery(A); - B = await Fr.batchToMontgomery(B); - C = await Fr.batchToMontgomery(C); - let numArr = new BigBuffer(Fr.n8*zkey.domainSize); let denArr = new BigBuffer(Fr.n8*zkey.domainSize); @@ -254,30 +240,30 @@ export default async function plonk16Prove(zkeyFileName, witnessFileName, logger let w = Fr.one; for (let i=0; i0)&&(Fr.isZero(p.slice(deg*n8r, deg*n8r+n8r)))) deg--; return deg; } + */ function printPol(P) { const n=(P.byteLength/n8r); @@ -362,14 +344,31 @@ export default async function plonk16Prove(zkeyFileName, witnessFileName, logger const transcript3 = new Uint8Array(G1.F.n8*2); G1.toRprUncompressed(transcript3, 0, proof.Z); - alpha = hashToFr(transcript3); + ch.alpha = hashToFr(transcript3); - if (logger) logger.debug("alpha: " + Fr.toString(alpha)); + if (logger) logger.debug("alpha: " + Fr.toString(ch.alpha)); - let A4; [pol_a, A4] = await to4T(A); - let B4; [pol_b, B4] = await to4T(B); - let C4; [pol_c, C4] = await to4T(C); - let Z4; [pol_z, Z4] = await to4T(Z); + + const Z1 = [ + Fr.zero, + Fr.add(Fr.e(-1), Fr.w[2]), + Fr.e(-2), + Fr.sub(Fr.e(-1), Fr.w[2]), + ]; + + const Z2 = [ + Fr.zero, + Fr.add(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])), + Fr.e(4), + Fr.sub(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])), + ]; + + const Z3 = [ + Fr.zero, + Fr.add(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])), + Fr.e(-8), + Fr.sub(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])), + ]; /* const Zw = new BigBuffer(zkey.domainSize*4*n8r); @@ -385,6 +384,7 @@ export default async function plonk16Prove(zkeyFileName, witnessFileName, logger console.log("degZw: " + degZw); */ const T = new BigBuffer(zkey.domainSize*4*n8r); + const Tz = new BigBuffer(zkey.domainSize*4*n8r); let w = Fr.one; for (let i=0; i (zkey.domainSize*3 +5) ) { + if (!Fr.isZero(a)) { + throw new Error("Tz Polynomial is not well calculated"); + } + } else { + t.set( + Fr.add( + t.slice(i*n8r, (i+1)*n8r), + a + ), + i*n8r + ); + } + } - t = await Fr.batchFromMontgomery(t); + pol_t = t.slice(0, (zkey.domainSize*3+6)*n8r); - proof.T1 = await curve.G1.multiExpAffine(PTau, t.slice(0, zkey.domainSize*n8r), logger, "multiexp T1"); - proof.T2 = await curve.G1.multiExpAffine(PTau, t.slice(zkey.domainSize*n8r, zkey.domainSize*2*n8r), logger, "multiexp T2"); - proof.T3 = await curve.G1.multiExpAffine(PTau, t.slice(zkey.domainSize*2*n8r, (zkey.domainSize*3)*n8r), logger, "multiexp T3"); + proof.T1 = await expTau( t.slice(0, zkey.domainSize*n8r) , "multiexp T1"); + proof.T2 = await expTau( t.slice(zkey.domainSize*n8r, zkey.domainSize*2*n8r) , "multiexp T2"); + proof.T3 = await expTau( t.slice(zkey.domainSize*2*n8r, (zkey.domainSize*3+6)*n8r) , "multiexp T3"); + function mul2(a,b, ap, bp, p) { + let r, rz; - async function to4T(A) { - const a = await Fr.ifft(A); - const a4 = new BigBuffer(n8r*zkey.domainSize*4); - a4.set(a, 0); - const A4 = await Fr.fft(a4); - return [a, A4]; + + const a_b = Fr.mul(a,b); + const a_bp = Fr.mul(a,bp); + const ap_b = Fr.mul(ap,b); + const ap_bp = Fr.mul(ap,bp); + + r = a_b; + + let a0 = Fr.add(a_bp, ap_b); + + let a1 = ap_bp; + + rz = a0; + if (p) { + rz = Fr.add(rz, Fr.mul(Z1[p], a1)); + } + + return [r, rz]; + } + + function mul4(a,b,c,d, ap, bp, cp, dp, p) { + let r, rz; + + + const a_b = Fr.mul(a,b); + const a_bp = Fr.mul(a,bp); + const ap_b = Fr.mul(ap,b); + const ap_bp = Fr.mul(ap,bp); + + const c_d = Fr.mul(c,d); + const c_dp = Fr.mul(c,dp); + const cp_d = Fr.mul(cp,d); + const cp_dp = Fr.mul(cp,dp); + + r = Fr.mul(a_b, c_d); + + let a0 = Fr.mul(ap_b, c_d); + a0 = Fr.add(a0, Fr.mul(a_bp, c_d)); + a0 = Fr.add(a0, Fr.mul(a_b, cp_d)); + a0 = Fr.add(a0, Fr.mul(a_b, c_dp)); + + let a1 = Fr.mul(ap_bp, c_d); + a1 = Fr.add(a1, Fr.mul(ap_b, cp_d)); + a1 = Fr.add(a1, Fr.mul(ap_b, c_dp)); + a1 = Fr.add(a1, Fr.mul(a_bp, cp_d)); + a1 = Fr.add(a1, Fr.mul(a_bp, c_dp)); + a1 = Fr.add(a1, Fr.mul(a_b, cp_dp)); + + let a2 = Fr.mul(a_bp, cp_dp); + a2 = Fr.add(a2, Fr.mul(ap_b, cp_dp)); + a2 = Fr.add(a2, Fr.mul(ap_bp, c_dp)); + a2 = Fr.add(a2, Fr.mul(ap_bp, cp_d)); + + let a3 = Fr.mul(ap_bp, cp_dp); + + rz = a0; + if (p) { + rz = Fr.add(rz, Fr.mul(Z1[p], a1)); + rz = Fr.add(rz, Fr.mul(Z2[p], a2)); + rz = Fr.add(rz, Fr.mul(Z3[p], a3)); + } + + return [r, rz]; } } @@ -523,74 +625,76 @@ export default async function plonk16Prove(zkeyFileName, witnessFileName, logger G1.toRprUncompressed(transcript4, 0, proof.T1); G1.toRprUncompressed(transcript4, G1.F.n8*2, proof.T2); G1.toRprUncompressed(transcript4, G1.F.n8*4, proof.T3); - xi = hashToFr(transcript4); + ch.xi = hashToFr(transcript4); - if (logger) logger.debug("xi: " + Fr.toString(xi)); + if (logger) logger.debug("xi: " + Fr.toString(ch.xi)); - proof.eval_a = evalPol(pol_a, xi); - proof.eval_b = evalPol(pol_b, xi); - proof.eval_c = evalPol(pol_c, xi); - proof.eval_s1 = evalPol(pol_s1, xi); - proof.eval_s2 = evalPol(pol_s2, xi); - proof.eval_t = evalPol(pol_t, xi); - proof.eval_zw = evalPol(pol_z, Fr.mul(xi, Fr.w[zkey.power])); + proof.eval_a = evalPol(pol_a, ch.xi); + proof.eval_b = evalPol(pol_b, ch.xi); + proof.eval_c = evalPol(pol_c, ch.xi); + proof.eval_s1 = evalPol(pol_s1, ch.xi); + proof.eval_s2 = evalPol(pol_s2, ch.xi); + proof.eval_t = evalPol(pol_t, ch.xi); + proof.eval_zw = evalPol(pol_z, Fr.mul(ch.xi, Fr.w[zkey.power])); const coef_ab = Fr.mul(proof.eval_a, proof.eval_b); let e2a = proof.eval_a; - const betaxi = Fr.mul(beta, xi); + const betaxi = Fr.mul(ch.beta, ch.xi); e2a = Fr.add( e2a, betaxi); - e2a = Fr.add( e2a, gamma); + e2a = Fr.add( e2a, ch.gamma); let e2b = proof.eval_b; e2b = Fr.add( e2b, Fr.mul(betaxi, zkey.k1)); - e2b = Fr.add( e2b, gamma); + e2b = Fr.add( e2b, ch.gamma); let e2c = proof.eval_c; e2c = Fr.add( e2c, Fr.mul(betaxi, zkey.k2)); - e2c = Fr.add( e2c, gamma); + e2c = Fr.add( e2c, ch.gamma); - const e2 = Fr.mul(Fr.mul(Fr.mul(e2a, e2b), e2c), alpha); + const e2 = Fr.mul(Fr.mul(Fr.mul(e2a, e2b), e2c), ch.alpha); let e3a = proof.eval_a; - e3a = Fr.add( e3a, Fr.mul(beta, proof.eval_s1)); - e3a = Fr.add( e3a, gamma); + e3a = Fr.add( e3a, Fr.mul(ch.beta, proof.eval_s1)); + e3a = Fr.add( e3a, ch.gamma); let e3b = proof.eval_b; - e3b = Fr.add( e3b, Fr.mul(beta, proof.eval_s2)); - e3b = Fr.add( e3b, gamma); + e3b = Fr.add( e3b, Fr.mul(ch.beta, proof.eval_s2)); + e3b = Fr.add( e3b, ch.gamma); let e3 = Fr.mul(e3a, e3b); - e3 = Fr.mul(e3, beta); + e3 = Fr.mul(e3, ch.beta); e3 = Fr.mul(e3, proof.eval_zw); - e3 = Fr.mul(e3, alpha); + e3 = Fr.mul(e3, ch.alpha); - xim= xi; - for (let i=0; i