Fflonk refactor zk (#325)

* zk refactored

* removed unnecessary import MulZ from fflonk_prove.js

* add #blinding factors in domain size calc

* fix typo

* remove unnecessary omega

* remove unnecessary C0 evaluations from zkey
This commit is contained in:
Xavier Pinsach
2023-03-10 11:20:59 +01:00
committed by GitHub
parent 28cda564d3
commit 2e436d7f43
3 changed files with 36 additions and 73 deletions

View File

@@ -447,12 +447,5 @@ Currently, there are 17 defined sections:
... ... ┃ C0 coefficients
┏━━━━━━━━━━━━━┓ ┃
┃ fs bytes ┃ C0 coefficient_{Domain size * 8} ┃
┣━━━━━━━━━━━━━┫ ━┫
┃ fs bytes ┃ C0 evaluation_1 ┃
┗━━━━━━━━━━━━━┛ ┃
... ... ┃ C0 evaluations
┏━━━━━━━━━━━━━┓ ┃
┃ fs bytes ┃ C0 evaluation_{Domain size + 16} ┃
┗━━━━━━━━━━━━━┛ ━┛
````

View File

@@ -43,7 +43,6 @@ import { Keccak256Transcript } from "./Keccak256Transcript.js";
import { Proof } from "./proof.js";
import { Polynomial } from "./polynomial/polynomial.js";
import { Evaluations } from "./polynomial/evaluations.js";
import { MulZ } from "./mul_z.js";
import { CPolynomial } from "./polynomial/cpolynomial.js";
const { stringifyBigInts } = utils;
@@ -372,6 +371,14 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
buffers.C.set(getWitness(signalIdC), i_sFr);
}
// Blind a(X), b(X) and c(X) polynomials coefficients with blinding scalars b
buffers.A.set(challenges.b[1], sDomain - 64);
buffers.A.set(challenges.b[2], sDomain - 32);
buffers.B.set(challenges.b[3], sDomain - 64);
buffers.B.set(challenges.b[4], sDomain - 32);
buffers.C.set(challenges.b[5], sDomain - 64);
buffers.C.set(challenges.b[6], sDomain - 32);
buffers.A = await Fr.batchToMontgomery(buffers.A);
buffers.B = await Fr.batchToMontgomery(buffers.B);
buffers.C = await Fr.batchToMontgomery(buffers.C);
@@ -392,19 +399,14 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
if (logger) logger.info("··· Computing C fft");
evaluations.C = await Evaluations.fromPolynomial(polynomials.C, 4, curve, logger);
// Blind a(X), b(X) and c(X) polynomials coefficients with blinding scalars b
polynomials.A.blindCoefficients([challenges.b[2], challenges.b[1]]);
polynomials.B.blindCoefficients([challenges.b[4], challenges.b[3]]);
polynomials.C.blindCoefficients([challenges.b[6], challenges.b[5]]);
// Check degrees
if (polynomials.A.degree() >= zkey.domainSize + 2) {
if (polynomials.A.degree() >= zkey.domainSize) {
throw new Error("A Polynomial is not well calculated");
}
if (polynomials.B.degree() >= zkey.domainSize + 2) {
if (polynomials.B.degree() >= zkey.domainSize) {
throw new Error("B Polynomial is not well calculated");
}
if (polynomials.C.degree() >= zkey.domainSize + 2) {
if (polynomials.C.degree() >= zkey.domainSize) {
throw new Error("C Polynomial is not well calculated");
}
}
@@ -430,13 +432,10 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
const lagrangePolynomials = await binFileUtils.readSection(fdZKey, zkeySections, ZKEY_FF_LAGRANGE_SECTION);
evaluations.lagrange1 = new Evaluations(lagrangePolynomials, curve, logger);
// Reserve memory for buffers T0 and T0z
// Reserve memory for buffers T0
buffers.T0 = new BigBuffer(sDomain * 4);
buffers.T0z = new BigBuffer(sDomain * 4);
if (logger) logger.info("··· Computing T0 evaluations");
// Initial omega
let omega = Fr.one;
for (let i = 0; i < zkey.domainSize * 4; i++) {
if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` T0 evaluation ${i}/${zkey.domainSize * 4}`);
@@ -451,11 +450,6 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
const qo = evaluations.QO.getEvaluation(i);
const qc = evaluations.QC.getEvaluation(i);
// Compute blinding factors
const az = Fr.add(Fr.mul(challenges.b[1], omega), challenges.b[2]);
const bz = Fr.add(Fr.mul(challenges.b[3], omega), challenges.b[4]);
const cz = Fr.add(Fr.mul(challenges.b[5], omega), challenges.b[6]);
// Compute current public input
let pi = Fr.zero;
for (let j = 0; j < zkey.nPublic; j++) {
@@ -471,30 +465,20 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
// Compute first T0(X)·Z_H(X), so divide later the resulting polynomial by Z_H(X)
// expression 1 -> q_L(X)·a(X)
const e1 = Fr.mul(a, ql);
const e1z = Fr.mul(az, ql);
// expression 2 -> q_R(X)·b(X)
const e2 = Fr.mul(b, qr);
const e2z = Fr.mul(bz, qr);
// expression 3 -> q_M(X)·a(X)·b(X)
let [e3, e3z] = MulZ.mul2(a, b, az, bz, i % 4, Fr);
e3 = Fr.mul(e3, qm);
e3z = Fr.mul(e3z, qm);
const e3 = Fr.mul(Fr.mul(a, b), qm);
// expression 4 -> q_O(X)·c(X)
const e4 = Fr.mul(c, qo);
const e4z = Fr.mul(cz, qo);
// t0 = expressions 1 + expression 2 + expression 3 + expression 4 + qc + pi
const t0 = Fr.add(e1, Fr.add(e2, Fr.add(e3, Fr.add(e4, Fr.add(qc, pi)))));
const t0z = Fr.add(e1z, Fr.add(e2z, Fr.add(e3z, e4z)));
buffers.T0.set(t0, i * sFr);
buffers.T0z.set(t0z, i * sFr);
// Next omega
omega = Fr.mul(omega, Fr.w[zkey.power + 2]);
}
if (logger) logger.info("buffer T0: " + buffers.T0.byteLength / sFr);
@@ -510,27 +494,12 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
if (logger) logger.info("··· Computing T0 / ZH");
polynomials.T0.divByZerofier(zkey.domainSize, Fr.one);
// Compute the coefficients of the polynomial T0z(X) from buffers.T0z
if (logger) logger.info("··· Computing T0z ifft");
polynomials.T0z = await Polynomial.fromEvaluations(buffers.T0z, curve, logger);
if (logger) logger.info("T0z length: " + polynomials.T0z.length());
if (logger) logger.info("T0z degree: " + polynomials.T0z.degree());
// Add the polynomial T0z to T0 to get the final polynomial T0
polynomials.T0.add(polynomials.T0z);
if (logger) logger.info("T0 length: " + polynomials.T0.length());
if (logger) logger.info("T0 degree: " + polynomials.T0.degree());
// Check degree
if (polynomials.T0.degree() >= 2 * zkey.domainSize + 2) {
if (polynomials.T0.degree() >= 2 * zkey.domainSize - 2) {
throw new Error(`T0 Polynomial is not well calculated (degree is ${polynomials.T0.degree()} and must be less than ${2 * zkey.domainSize + 2}`);
}
delete buffers.T0;
delete buffers.T0z;
delete polynomials.T0z;
}
async function computeC1() {
@@ -543,7 +512,7 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
polynomials.C1 = C1.getPolynomial();
// Check degree
if (polynomials.C1.degree() >= 8 * zkey.domainSize + 8) {
if (polynomials.C1.degree() >= 8 * zkey.domainSize - 8) {
throw new Error("C1 Polynomial is not well calculated");
}
}
@@ -734,7 +703,7 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
if (logger) logger.info("··· Computing T1z ifft");
polynomials.T1z = await Polynomial.fromEvaluations(buffers.T1z, curve, logger);
// Add the polynomial T0z to T0 to get the final polynomial T0
// Add the polynomial T1z to T1 to get the final polynomial T1
polynomials.T1.add(polynomials.T1z);
// Check degree
@@ -768,9 +737,6 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
const z = evaluations.Z.getEvaluation(i);
const zW = evaluations.Z.getEvaluation((zkey.domainSize * 4 + 4 + i) % (zkey.domainSize * 4));
const ap = Fr.add(Fr.mul(challenges.b[1], omega), challenges.b[2]);
const bp = Fr.add(Fr.mul(challenges.b[3], omega), challenges.b[4]);
const cp = Fr.add(Fr.mul(challenges.b[5], omega), challenges.b[6]);
const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omega2), Fr.mul(challenges.b[8], omega)), challenges.b[9]);
const zWp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omegaW2), Fr.mul(challenges.b[8], omegaW)), challenges.b[9]);
@@ -794,7 +760,9 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
let e13 = Fr.add(c, Fr.mul(betaX, zkey.k2));
e13 = Fr.add(e13, challenges.gamma);
const [e1, e1z] = MulZ.mul4(e11, e12, e13, z, ap, bp, cp, zp, i % 4, Fr);
let e1 = Fr.mul(Fr.mul(Fr.mul(e11, e12), e13), z);
let e1z = Fr.mul(Fr.mul(Fr.mul(e11, e12), e13), zp);
// const [e1, e1z] = MulZ.mul4(e11, e12, e13, z, ap, bp, cp, zp, i % 4, Fr);
// expression 2 -> (a(X) + beta·sigma1(X) + gamma)(b(X) + beta·sigma2(X) + gamma)(c(X) + beta·sigma3(X) + gamma)z(Xω)
let e21 = Fr.add(a, Fr.mul(challenges.beta, sigma1));
@@ -806,7 +774,9 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
let e23 = Fr.add(c, Fr.mul(challenges.beta, sigma3));
e23 = Fr.add(e23, challenges.gamma);
const [e2, e2z] = MulZ.mul4(e21, e22, e23, zW, ap, bp, cp, zWp, i % 4, Fr);
let e2 = Fr.mul(Fr.mul(Fr.mul(e21, e22), e23), zW);
let e2z = Fr.mul(Fr.mul(Fr.mul(e21, e22), e23), zWp);
// const [e2, e2z] = MulZ.mul4(e21, e22, e23, zW, ap, bp, cp, zWp, i % 4, Fr);
let t2 = Fr.sub(e1, e2);
let t2z = Fr.sub(e1z, e2z);
@@ -834,7 +804,7 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
polynomials.T2.add(polynomials.T2z);
// Check degree
if (polynomials.T2.degree() >= 3 * zkey.domainSize + 6) {
if (polynomials.T2.degree() >= 3 * zkey.domainSize) {
throw new Error("T2 Polynomial is not well calculated");
}
@@ -852,7 +822,7 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
polynomials.C2 = C2.getPolynomial();
// Check degree
if (polynomials.C2.degree() >= 9 * zkey.domainSize + 18) {
if (polynomials.C2.degree() >= 9 * zkey.domainSize) {
throw new Error("C2 Polynomial is not well calculated");
}
}
@@ -1079,8 +1049,7 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
polynomials.F.add(f2);
polynomials.F.add(f3);
// Check degree < 9n + 12
if (polynomials.F.degree() >= 9 * zkey.domainSize + 12) {
if (polynomials.F.degree() >= 9 * zkey.domainSize - 6) {
throw new Error("F Polynomial is not well calculated");
}
}
@@ -1117,7 +1086,7 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
throw new Error(`Degree of L(X)/(ZTS2(y)(X-y)) remainder is ${polRemainder.degree()} and should be 0`);
}
if (polynomials.L.degree() >= 9 * zkey.domainSize + 17) {
if (polynomials.L.degree() >= 9 * zkey.domainSize - 1) {
throw new Error("Degree of L(X)/(ZTS2(y)(X-y)) is not correct");
}
@@ -1184,7 +1153,7 @@ export default async function fflonkProve(zkeyFileName, witnessFileName, logger)
polynomials.L.sub(polynomials.F);
// Check degree
if (polynomials.L.degree() >= 9 * zkey.domainSize + 18) {
if (polynomials.L.degree() >= 9 * zkey.domainSize) {
throw new Error("L Polynomial is not well calculated");
}

View File

@@ -108,7 +108,8 @@ export default async function fflonkSetup(r1csFilename, ptauFilename, zkeyFilena
// As the t polynomial is n+5 whe need at least a power of 4
//TODO check!!!!
settings.cirPower = Math.max(FF_T_POL_DEG_MIN, log2(plonkConstraints.length - 1) + 1);
// NOTE : plonkConstraints + 2 = #constraints + blinding coefficients for each wire polynomial
settings.cirPower = Math.max(FF_T_POL_DEG_MIN, log2((plonkConstraints.length + 2) - 1) + 1);
settings.domainSize = 2 ** settings.cirPower;
if (pTauSections[2][0].size < (settings.domainSize * 9 + 18) * sG1) {
@@ -348,11 +349,16 @@ export default async function fflonkSetup(r1csFilename, ptauFilename, zkeyFilena
buildSigma(plonkConstraints[i][0], i);
buildSigma(plonkConstraints[i][1], settings.domainSize + i);
buildSigma(plonkConstraints[i][2], settings.domainSize * 2 + i);
} else {
} else if (i < settings.domainSize - 2) {
buildSigma(0, i);
buildSigma(0, settings.domainSize + i);
buildSigma(0, settings.domainSize * 2 + i);
} else {
sigma.set(w, i * sFr);
sigma.set(Fr.mul(w, k1), (settings.domainSize + i) * sFr);
sigma.set(Fr.mul(w, k2), (settings.domainSize * 2 + i) * sFr);
}
w = Fr.mul(w, Fr.w[settings.cirPower]);
if ((logger) && (i !== 0) && (i % 500000 === 0)) {
@@ -448,15 +454,12 @@ export default async function fflonkSetup(r1csFilename, ptauFilename, zkeyFilena
polynomials.C0 = C0.getPolynomial();
// Check degree
if (polynomials.C0.degree() > 8 * settings.domainSize - 1) {
if (polynomials.C0.degree() >= 8 * settings.domainSize) {
throw new Error("C0 Polynomial is not well calculated");
}
evaluations.C0 = await Evaluations.fromPolynomial(polynomials.C0, 2, curve, logger);
await startWriteSection(fdZKey, ZKEY_FF_C0_SECTION);
await fdZKey.write(polynomials.C0.coef);
await fdZKey.write(evaluations.C0.eval);
await endWriteSection(fdZKey);
}
@@ -552,8 +555,6 @@ export default async function fflonkSetup(r1csFilename, ptauFilename, zkeyFilena
return Fr.exp(firstRoot, 2 ** (28 - power));
}
}