Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

snarkjs

Package Overview
Dependencies
Maintainers
1
Versions
136
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

snarkjs - npm Package Compare versions

Comparing version 0.6.11 to 0.7.0

browser_tests/package-lock.json

91

.vscode/launch.json

@@ -16,5 +16,96 @@ {

},
{
"type": "node",
"request": "launch",
"name": "groth16 setup",
"skipFiles": [
"<node_internals>/**"
],
"program": "cli.js",
"args": [
"groth16", "setup",
"test/groth16/circuit.r1cs",
"test/plonk_circuit/powersOfTau15_final.ptau",
"test/groth16/circuit.zkey"
]
},
{
"type": "node",
"request": "launch",
"name": "groth16 prove",
"skipFiles": [
"<node_internals>/**"
],
"program": "cli.js",
"args": [
"groth16", "prove",
"test/groth16/circuit.zkey",
"test/groth16/witness.wtns",
"test/groth16/proof.json",
"test/groth16/public.json",
"-v"
]
},
{
"type": "node",
"request": "launch",
"name": "groth16 export vk",
"skipFiles": [
"<node_internals>/**"
],
"program": "cli.js",
"args": [
"zkev",
"test/groth16/circuit.zkey",
"test/groth16/verification_key.json",
]
},
{
"type": "node",
"request": "launch",
"name": "groth16 verify",
"skipFiles": [
"<node_internals>/**"
],
"program": "cli.js",
"args": [
"groth16", "verify",
"test/groth16/verification_key.json",
"test/groth16/public.json",
"test/groth16/proof.json",
"-v"
]
},
{
"type": "node",
"request": "launch",
"name": "groth16 solidity verifier",
"skipFiles": [
"<node_internals>/**"
],
"program": "cli.js",
"args": [
"zkesv",
"test/groth16/circuit.zkey",
"test/groth16/verifier.sol",
]
},
{
"type": "node",
"request": "launch",
"name": "groth16 solidity calldata",
"skipFiles": [
"<node_internals>/**"
],
"program": "cli.js",
"args": [
"zkesc",
"test/groth16/public.json",
"test/groth16/proof.json",
]
},
{
"type": "node",
"request": "launch",
"name": "plonk setup",

@@ -21,0 +112,0 @@ "skipFiles": [

63

cli.js

@@ -715,3 +715,6 @@ /*

return await powersOfTau.newAccumulator(curve, power, ptauName, logger);
// Discard firstChallengeHash
await powersOfTau.newAccumulator(curve, power, ptauName, logger);
return 0;
}

@@ -733,3 +736,6 @@

return await powersOfTau.exportChallenge(ptauName, challengeName, logger);
// Discard curChallengeHash
await powersOfTau.exportChallenge(ptauName, challengeName, logger);
return 0;
}

@@ -754,3 +760,5 @@

return await powersOfTau.challengeContribute(curve, challengeName, responseName, options.entropy, logger);
await powersOfTau.challengeContribute(curve, challengeName, responseName, options.entropy, logger);
return 0;
}

@@ -777,2 +785,3 @@

// TODO: This seems wrong
if (res) return res;

@@ -812,3 +821,6 @@ if (!doCheck) return;

return await powersOfTau.beacon(oldPtauName, newPtauName, options.name, beaconHashStr, numIterationsExp, logger);
// Discard hashResponse
await powersOfTau.beacon(oldPtauName, newPtauName, options.name, beaconHashStr, numIterationsExp, logger);
return 0;
}

@@ -825,3 +837,6 @@

return await powersOfTau.contribute(oldPtauName, newPtauName, options.name, options.entropy, logger);
// Discard hashResponse
await powersOfTau.contribute(oldPtauName, newPtauName, options.name, options.entropy, logger);
return 0;
}

@@ -838,3 +853,5 @@

return await powersOfTau.preparePhase2(oldPtauName, newPtauName, logger);
await powersOfTau.preparePhase2(oldPtauName, newPtauName, logger);
return 0;
}

@@ -851,3 +868,5 @@

return await powersOfTau.convert(oldPtauName, newPtauName, logger);
await powersOfTau.convert(oldPtauName, newPtauName, logger);
return 0;
}

@@ -868,3 +887,6 @@

return await powersOfTau.truncate(ptauName, template, logger);
// Discard `true`
await powersOfTau.truncate(ptauName, template, logger);
return 0;
}

@@ -914,3 +936,6 @@

return zkey.newZKey(r1csName, ptauName, zkeyName, logger);
// Discard csHash
await zkey.newZKey(r1csName, ptauName, zkeyName, logger);
return 0;
}

@@ -933,4 +958,5 @@

return zkey.exportBellman(zkeyName, mpcparamsName, logger);
await zkey.exportBellman(zkeyName, mpcparamsName, logger);
return 0;
}

@@ -1038,3 +1064,6 @@

return zkey.contribute(zkeyOldName, zkeyNewName, options.name, options.entropy, logger);
// Discard contribuionHash
await zkey.contribute(zkeyOldName, zkeyNewName, options.name, options.entropy, logger);
return 0;
}

@@ -1056,3 +1085,6 @@

return await zkey.beacon(zkeyOldName, zkeyNewName, options.name, beaconHashStr, numIterationsExp, logger);
// Discard contribuionHash
await zkey.beacon(zkeyOldName, zkeyNewName, options.name, beaconHashStr, numIterationsExp, logger);
return 0;
}

@@ -1078,3 +1110,6 @@

return zkey.bellmanContribute(curve, challengeName, responseName, options.entropy, logger);
// Discard contributionHash
await zkey.bellmanContribute(curve, challengeName, responseName, options.entropy, logger);
return 0;
}

@@ -1109,2 +1144,3 @@

// TODO: Make plonk.setup reject instead of returning -1 or null
return plonk.setup(r1csName, ptauName, zkeyName, logger);

@@ -1184,2 +1220,3 @@ }

// TODO: Make fflonk.setup return valuable information or nothing at all
return await fflonk.setup(r1csFilename, ptauFilename, zkeyFilename, logger);

@@ -1186,0 +1223,0 @@ }

{
"name": "snarkjs",
"type": "module",
"version": "0.6.11",
"version": "0.7.0",
"description": "zkSNARKs implementation in JavaScript",

@@ -48,3 +48,3 @@ "main": "./build/main.cjs",

"fastfile": "0.0.20",
"ffjavascript": "0.2.57",
"ffjavascript": "0.2.59",
"js-sha3": "^0.8.0",

@@ -51,0 +51,0 @@ "logplease": "^1.2.15",

@@ -14,3 +14,3 @@ {

"ethers": "^5.7.2",
"ffjavascript": "0.2.57",
"ffjavascript": "0.2.59",
"hardhat": "^2.14.0",

@@ -17,0 +17,0 @@ "mocha": "^10.2.0",

@@ -35,7 +35,47 @@ import { expect } from "chai";

it("Groth16 smart contract", async () => {
it("Groth16 smart contract 1 input", async () => {
expect(await groth16Verify(
path.join("../test", "groth16", "circuit.r1cs"),
path.join("../test", "groth16", "witness.wtns")
)).to.be.equal(true);
});
it("Groth16 smart contract 3 inputs", async () => {
expect(await groth16Verify(
path.join("../test", "circuit2", "circuit.r1cs"),
path.join("../test", "circuit2", "witness.wtns")
)).to.be.equal(true);
});
it("Plonk smart contract 1 input", async () => {
expect(await plonkVerify(
path.join("../test", "plonk_circuit", "circuit.r1cs"),
path.join("../test", "plonk_circuit", "witness.wtns")
)).to.be.equal(true);
});
it("Plonk smart contract 3 inputs", async () => {
expect(await plonkVerify(
path.join("../test", "circuit2", "circuit.r1cs"),
path.join("../test", "circuit2", "witness.wtns")
)).to.be.equal(true);
});
it("Fflonk smart contract 1 input", async () => {
expect(await fflonkVerify(
path.join("../test", "fflonk", "circuit.r1cs"),
path.join("../test", "fflonk", "witness.wtns")
)).to.be.equal(true);
});
it("Fflonk smart contract 3 inputs", async () => {
expect(await fflonkVerify(
path.join("../test", "circuit2", "circuit.r1cs"),
path.join("../test", "circuit2", "witness.wtns")
)).to.be.equal(true);
});
async function groth16Verify(r1csFilename, wtnsFilename) {
const solidityVerifierFilename = path.join("contracts", "groth16.sol");
const r1csFilename = path.join("../test", "groth16", "circuit.r1cs");
const wtnsFilename = path.join("../test", "groth16", "witness.wtns");
const zkeyFilename = { type: "mem" };

@@ -58,14 +98,11 @@

// Deploy mock groth16 verifier
const VerifierFactory = await ethers.getContractFactory("Verifier");
const VerifierFactory = await ethers.getContractFactory("Groth16Verifier");
verifierContract = await VerifierFactory.deploy();
// Verifiy the proof in the smart contract
expect(await verifierContract.verifyProof(proofA, proofB, proofC, publicInputs)).to.be.equal(true);
});
return await verifierContract.verifyProof(proofA, proofB, proofC, publicInputs);
}
it("plonk smart contract", async () => {
async function plonkVerify(r1csFilename, wtnsFilename) {
const solidityVerifierFilename = path.join("contracts", "plonk.sol");
const r1csFilename = path.join("../test", "plonk_circuit", "circuit.r1cs");
const wtnsFilename = path.join("../test", "plonk_circuit", "witness.wtns");
const zkeyFilename = { type: "mem" };

@@ -88,5 +125,3 @@

// Verifiy the proof in the smart contract
const arrayStrings = Array(25).fill("bytes32");
const proof = ethers.utils.defaultAbiCoder.encode(
arrayStrings,
const proof =
[

@@ -118,14 +153,10 @@ ethers.utils.hexZeroPad(ethers.BigNumber.from(proofJson.A[0]).toHexString(), 32),

ethers.utils.hexZeroPad(ethers.BigNumber.from(proofJson.eval_zw).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proofJson.eval_r).toHexString(), 32),
],
);
];
expect(await verifierContract.verifyProof(proof, publicInputs)).to.be.equal(true);
});
return await verifierContract.verifyProof(proof, publicInputs);
};
it("fflonk smart contract", async () => {
async function fflonkVerify(r1csFilename, wtnsFilename) {
const solidityVerifierFilename = path.join("contracts", "fflonk.sol");
const r1csFilename = path.join("../test", "fflonk", "circuit.r1cs");
const wtnsFilename = path.join("../test", "fflonk", "witness.wtns");
const zkeyFilename = { type: "mem" };

@@ -149,5 +180,4 @@

const { evaluations, polynomials } = proofJson;
const arrayStrings = Array(24).fill("bytes32");
const proof = ethers.utils.defaultAbiCoder.encode(
arrayStrings,
const proof =
[

@@ -178,7 +208,6 @@ ethers.utils.hexZeroPad(ethers.BigNumber.from(polynomials.C1[0]).toHexString(), 32),

ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.inv).toHexString(), 32),
],
);
];
expect(await verifierContract.verifyProof(proof, publicInputs)).to.be.equal(true);
});
});
return await verifierContract.verifyProof(proof, publicInputs);
};
});

@@ -32,3 +32,3 @@ /*

while (nstr.length < 64) nstr = "0" + nstr;
nstr = `"0x${nstr}"`;
nstr = `0x${nstr}`;
return nstr;

@@ -51,28 +51,13 @@ }

const proofBuff = new Uint8Array(G1.F.n8 * 2 * 4 + Fr.n8 * 16);
G1.toRprUncompressed(proofBuff, 0, G1.e(proof.polynomials.C1));
G1.toRprUncompressed(proofBuff, G1.F.n8 * 2, G1.e(proof.polynomials.C2));
G1.toRprUncompressed(proofBuff, G1.F.n8 * 4, G1.e(proof.polynomials.W1));
G1.toRprUncompressed(proofBuff, G1.F.n8 * 6, G1.e(proof.polynomials.W2));
Fr.toRprBE(proofBuff, G1.F.n8 * 8, Fr.e(proof.evaluations.ql));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8, Fr.e(proof.evaluations.qr));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8 * 2, Fr.e(proof.evaluations.qm));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8 * 3, Fr.e(proof.evaluations.qo));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8 * 4, Fr.e(proof.evaluations.qc));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8 * 5, Fr.e(proof.evaluations.s1));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8 * 6, Fr.e(proof.evaluations.s2));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8 * 7, Fr.e(proof.evaluations.s3));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8 * 8, Fr.e(proof.evaluations.a));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8 * 9, Fr.e(proof.evaluations.b));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8 * 10, Fr.e(proof.evaluations.c));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8 * 11, Fr.e(proof.evaluations.z));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8 * 12, Fr.e(proof.evaluations.zw));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8 * 13, Fr.e(proof.evaluations.t1w));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8 * 14, Fr.e(proof.evaluations.t2w));
Fr.toRprBE(proofBuff, G1.F.n8 * 8 + Fr.n8 * 15, Fr.e(proof.evaluations.inv));
const proofHex = Array.from(proofBuff).map(i2hex).join("");
return `0x${proofHex},[${inputs}]`;
return `[${p256(proof.polynomials.C1[0])}, ${p256(proof.polynomials.C1[1])},` +
`${p256(proof.polynomials.C2[0])},${p256(proof.polynomials.C2[1])},` +
`${p256(proof.polynomials.W1[0])},${p256(proof.polynomials.W1[1])},` +
`${p256(proof.polynomials.W2[0])},${p256(proof.polynomials.W2[1])},` +
`${p256(proof.evaluations.ql)},${p256(proof.evaluations.qr)},${p256(proof.evaluations.qm)},` +
`${p256(proof.evaluations.qo)},${p256(proof.evaluations.qc)},${p256(proof.evaluations.s1)},` +
`${p256(proof.evaluations.s2)},${p256(proof.evaluations.s3)},${p256(proof.evaluations.a)},` +
`${p256(proof.evaluations.b)},${p256(proof.evaluations.c)},${p256(proof.evaluations.z)},` +
`${p256(proof.evaluations.zw)},${p256(proof.evaluations.t1w)},${p256(proof.evaluations.t2w)},` +
`${p256(proof.evaluations.inv)}],` +
`[${inputs}]`;
}

@@ -1193,13 +1193,7 @@ /*

// · denominator needed in the verifier when computing L_i^{S0}(X), L_i^{S1}(X) and L_i^{S2}(X)
for (let i = 0; i < 8; i++) {
toInverse["LiS0_" + (i + 1)] = computeLiS0(i);
}
computeLiS0(toInverse, roots.S0.h0w8, challenges.y, curve);
for (let i = 0; i < 4; i++) {
toInverse["LiS1_" + (i + 1)] = computeLiS1(i);
}
computeLiS1(toInverse, roots.S1.h1w4, challenges.y, curve);
for (let i = 0; i < 6; i++) {
toInverse["LiS2_" + (i + 1)] = computeLiS2(i);
}
computeLiS2(toInverse, roots.S2.h2w3, roots.S2.h3w3, challenges.y, challenges.xi, challenges.xiw, curve);

@@ -1212,4 +1206,3 @@ // · L_i i=1 to num public inputs, needed in step 6 and 7 of the verifier to compute L_1(xi) and PI(xi)

toInverse["Li_" + (i + 1)] = Fr.mul(Fr.e(zkey.domainSize), Fr.sub(challenges.xi, w));
w = Fr.mul(w, zkey.w);
w = Fr.mul(w, Fr.w[zkey.power]);
}

@@ -1219,44 +1212,77 @@

for (const element of Object.values(toInverse)) {
mulAccumulator = Fr.mul(mulAccumulator, element);
if(Array.isArray(element)) {
for (const subElement of element) {
mulAccumulator = Fr.mul(mulAccumulator, subElement);
}
} else {
mulAccumulator = Fr.mul(mulAccumulator, element);
}
}
return Fr.inv(mulAccumulator);
function computeLiS0(i) {
// Compute L_i^{(S0)}(y)
let idx = i;
let den = Fr.one;
for (let j = 0; j < 7; j++) {
idx = (idx + 1) % 8;
den = Fr.mul(den, Fr.sub(roots.S0.h0w8[i], roots.S0.h0w8[idx]));
function computeLiS0(toInverse, roots, x, curve) {
const Fr = curve.Fr;
const len = roots.length;
const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2));
const Li = [];
for (let i = 0; i < len; i++) {
const den2 = roots[((len - 1) * i) % len];
const den3 = Fr.sub(x, roots[i]);
toInverse[["LiS0_" + (i + 1)]] = Fr.mul(Fr.mul(den1, den2), den3);
}
return den;
return Li;
}
function computeLiS1(i) {
// Compute L_i^{(S1)}(y)
let idx = i;
let den = Fr.one;
for (let j = 0; j < 3; j++) {
idx = (idx + 1) % 4;
function computeLiS1(toInverse, roots, x, curve) {
const Fr = curve.Fr;
const len = roots.length;
const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2));
const Li = [];
for (let i = 0; i < len; i++) {
const den2 = roots[((len - 1) * i) % len];
const den3 = Fr.sub(x, roots[i]);
toInverse[["LiS1_" + (i + 1)]] = Fr.mul(Fr.mul(den1, den2), den3);
den = Fr.mul(den, Fr.sub(roots.S1.h1w4[i], roots.S1.h1w4[idx]));
}
return den;
return Li;
}
function computeLiS2(i) {
// Compute L_i^{(S1)}(y)
let idx = i;
let den = Fr.one;
for (let j = 0; j < 5; j++) {
idx = (idx + 1) % 6;
const root1 = i < 3 ? roots.S2.h2w3[i] : roots.S2.h3w3[i - 3];
const root2 = idx < 3 ? roots.S2.h2w3[idx] : roots.S2.h3w3[idx - 3];
den = Fr.mul(den, Fr.sub(root1, root2));
function computeLiS2(toInverse, S2, S2p, value, xi, xiw, curve) {
const Fr = curve.Fr;
const Li = [];
const _3h2 = Fr.mul(Fr.e(3), S2[0]);
const xisubxiw = Fr.sub(xi, xiw);
let den1 = Fr.mul(_3h2, xisubxiw);
for (let i = 0; i < 3; i++) {
const den2 = S2[2 * i % 3];
const den3 = Fr.sub(value, S2[i]);
toInverse[["LiS2_" + (i + 1)]] = Fr.mul(den1,Fr.mul(den2, den3));
}
return den;
const _3h3 = Fr.mul(Fr.e(3), S2p[0]);
const xiwsubxi = Fr.sub(xiw, xi);
den1 = Fr.mul(_3h3, xiwsubxi);
for (let i = 0; i < 3; i++) {
const den2 = S2p[2 * i % 3];
const den3 = Fr.sub(value, S2p[i]);
toInverse[["LiS2_" + (i + 1 + 3)]] = Fr.mul(den1,Fr.mul(den2, den3));
}
return Li;
}
}
}
}

@@ -24,3 +24,3 @@ /*

import { Keccak256Transcript } from "./Keccak256Transcript.js";
import { Polynomial } from "./polynomial/polynomial.js";
import { Scalar } from "ffjavascript";

@@ -66,11 +66,19 @@ const { unstringifyBigInts } = utils;

if (!commitmentsBelongToG1(curve, proof, vk)) {
logger.error("Proof is not well constructed");
if (logger) logger.error("Proof commitments are not valid");
return false;
}
// TODO
// STEP 2 - Validate that all evaluations ∈ F
if (logger) logger.info("> Checking evaluations belong to F");
if (!evaluationsAreValid(curve, proof)) {
if (logger) logger.error("Proof evaluations are not valid.");
return false;
}
// TODO
// STEP 3 - Validate that w_i ∈ F for i ∈ [l]
if (logger) logger.info("> Checking public inputs belong to F");
if (!publicInputsAreValid(curve, publicSignals)) {
if (logger) logger.error("Public inputs are not valid.");
return false;
}

@@ -97,3 +105,3 @@ // STEP 4 - Compute the challenges: beta, gamma, xi, alpha and y ∈ F

if (logger) logger.info("> Computing r0(y)");
const r0 = computeR0(proof, challenges, roots, pi, curve, logger);
const r0 = computeR0(proof, challenges, roots, curve, logger);

@@ -158,2 +166,37 @@ // STEP 9 - Compute polynomial r1 ∈ F_{<4}[X]

function checkValueBelongToField(curve, value) {
return Scalar.lt(value, curve.r);
}
function checkEvaluationIsValid(curve, evaluation) {
return checkValueBelongToField(curve, Scalar.fromRprLE(evaluation));
}
function evaluationsAreValid(curve, proof) {
return checkEvaluationIsValid(curve, proof.evaluations.ql)
&& checkEvaluationIsValid(curve, proof.evaluations.qr)
&& checkEvaluationIsValid(curve, proof.evaluations.qm)
&& checkEvaluationIsValid(curve, proof.evaluations.qo)
&& checkEvaluationIsValid(curve, proof.evaluations.qc)
&& checkEvaluationIsValid(curve, proof.evaluations.s1)
&& checkEvaluationIsValid(curve, proof.evaluations.s2)
&& checkEvaluationIsValid(curve, proof.evaluations.s3)
&& checkEvaluationIsValid(curve, proof.evaluations.a)
&& checkEvaluationIsValid(curve, proof.evaluations.b)
&& checkEvaluationIsValid(curve, proof.evaluations.c)
&& checkEvaluationIsValid(curve, proof.evaluations.z)
&& checkEvaluationIsValid(curve, proof.evaluations.zw)
&& checkEvaluationIsValid(curve, proof.evaluations.t1w)
&& checkEvaluationIsValid(curve, proof.evaluations.t2w);
}
function publicInputsAreValid(curve, publicInputs) {
for(let i = 0; i < publicInputs.length; i++) {
if(!checkValueBelongToField(curve, publicInputs[i])) {
return false;
}
}
return true;
}
function computeChallenges(curve, proof, vk, publicSignals, logger) {

@@ -238,2 +281,3 @@ const Fr = curve.Fr;

challenges.xi = Fr.mul(Fr.square(roots.S2.h2w3[0]), roots.S2.h2w3[0]);
challenges.xiw = Fr.mul(challenges.xi, Fr.w[vk.power]);

@@ -318,11 +362,13 @@ challenges.xiN = challenges.xi;

function computeR0(proof, challenges, roots, pi, curve, logger) {
function computeR0(proof, challenges, roots, curve, logger) {
const Fr = curve.Fr;
const Li = computeLagrangeLiSi(roots.S0.h0w8, challenges.y, challenges.xi, curve);
// r0(y) = ∑_1^8 C_0(h_0 ω_8^{i-1}) L_i(y). To this end we need to compute
// Compute the 8 C0 values
if (logger) logger.info("··· Computing C0(h_0ω_8^i) values");
if (logger) logger.info("··· Computing r0(y)");
let c0Values = [];
let res = Fr.zero;
for (let i = 0; i < 8; i++) {

@@ -335,25 +381,14 @@ let coefValues = [];

c0Values[i] = Fr.add(proof.evaluations.ql, Fr.mul(proof.evaluations.qr, coefValues[1]));
c0Values[i] = Fr.add(c0Values[i], Fr.mul(proof.evaluations.qo, coefValues[2]));
c0Values[i] = Fr.add(c0Values[i], Fr.mul(proof.evaluations.qm, coefValues[3]));
c0Values[i] = Fr.add(c0Values[i], Fr.mul(proof.evaluations.qc, coefValues[4]));
c0Values[i] = Fr.add(c0Values[i], Fr.mul(proof.evaluations.s1, coefValues[5]));
c0Values[i] = Fr.add(c0Values[i], Fr.mul(proof.evaluations.s2, coefValues[6]));
c0Values[i] = Fr.add(c0Values[i], Fr.mul(proof.evaluations.s3, coefValues[7]));
}
let c0 = Fr.add(proof.evaluations.ql, Fr.mul(proof.evaluations.qr, coefValues[1]));
c0 = Fr.add(c0, Fr.mul(proof.evaluations.qo, coefValues[2]));
c0 = Fr.add(c0, Fr.mul(proof.evaluations.qm, coefValues[3]));
c0 = Fr.add(c0, Fr.mul(proof.evaluations.qc, coefValues[4]));
c0 = Fr.add(c0, Fr.mul(proof.evaluations.s1, coefValues[5]));
c0 = Fr.add(c0, Fr.mul(proof.evaluations.s2, coefValues[6]));
c0 = Fr.add(c0, Fr.mul(proof.evaluations.s3, coefValues[7]));
// Interpolate a polynomial with the points computed previously
const R0 = Polynomial.lagrangePolynomialInterpolation(
[roots.S0.h0w8[0], roots.S0.h0w8[1], roots.S0.h0w8[2], roots.S0.h0w8[3],
roots.S0.h0w8[4], roots.S0.h0w8[5], roots.S0.h0w8[6], roots.S0.h0w8[7]],
c0Values, curve);
// Check the degree of r1(X) < 4
if (R0.degree() > 7) {
throw new Error("R0 Polynomial is not well calculated");
res = Fr.add(res, Fr.mul(c0, Li[i]));
}
// Evaluate the polynomial in challenges.y
if (logger) logger.info("··· Computing evaluation r0(y)");
return R0.evaluate(challenges.y);
return res;
}

@@ -364,2 +399,4 @@

const Li = computeLagrangeLiSi(roots.S1.h1w4, challenges.y, challenges.xi, curve);
// r1(y) = ∑_1^4 C_1(h_1 ω_4^{i-1}) L_i(y). To this end we need to compute

@@ -383,24 +420,14 @@ // Z1 = {C1(h_1}, C1(h_1 ω_4), C1(h_1 ω_4^2), C1(h_1 ω_4^3)}

let c1Values = [];
let res = Fr.zero;
for (let i = 0; i < 4; i++) {
c1Values[i] = proof.evaluations.a;
c1Values[i] = Fr.add(c1Values[i], Fr.mul(roots.S1.h1w4[i], proof.evaluations.b));
let c1 = proof.evaluations.a;
c1 = Fr.add(c1, Fr.mul(roots.S1.h1w4[i], proof.evaluations.b));
const h1w4Squared = Fr.square(roots.S1.h1w4[i]);
c1Values[i] = Fr.add(c1Values[i], Fr.mul(h1w4Squared, proof.evaluations.c));
c1Values[i] = Fr.add(c1Values[i], Fr.mul(Fr.mul(h1w4Squared, roots.S1.h1w4[i]), t0));
}
c1 = Fr.add(c1, Fr.mul(h1w4Squared, proof.evaluations.c));
c1 = Fr.add(c1, Fr.mul(Fr.mul(h1w4Squared, roots.S1.h1w4[i]), t0));
// Interpolate a polynomial with the points computed previously
const R1 = Polynomial.lagrangePolynomialInterpolation(
[roots.S1.h1w4[0], roots.S1.h1w4[1], roots.S1.h1w4[2], roots.S1.h1w4[3]],
c1Values, curve);
// Check the degree of r1(X) < 4
if (R1.degree() > 3) {
throw new Error("R1 Polynomial is not well calculated");
res = Fr.add(res, Fr.mul(c1, Li[i]));
}
// Evaluate the polynomial in challenges.y
if (logger) logger.info("··· Computing evaluation r1(y)");
return R1.evaluate(challenges.y);
return res;
}

@@ -411,2 +438,4 @@

const LiS2 = computeLagrangeLiS2([roots.S2.h2w3, roots.S2.h3w3], challenges.y, challenges.xi, challenges.xiw, curve);
// r2(y) = ∑_1^3 C_2(h_2 ω_3^{i-1}) L_i(y) + ∑_1^3 C_2(h_3 ω_3^{i-1}) L_{i+3}(y). To this end we need to compute

@@ -444,6 +473,8 @@ // Z2 = {[C2(h_2}, C2(h_2 ω_3), C2(h_2 ω_3^2)], [C2(h_3}, C2(h_3 ω_3), C2(h_3 ω_3^2)]}

if (logger) logger.info("··· Computing C2(h_2ω_3^i) values");
let c2Values = [];
let res = Fr.zero;
for (let i = 0; i < 3; i++) {
c2Values[i] = Fr.add(proof.evaluations.z, Fr.mul(roots.S2.h2w3[i], t1));
c2Values[i] = Fr.add(c2Values[i], Fr.mul(Fr.square(roots.S2.h2w3[i]), t2));
let c2 = Fr.add(proof.evaluations.z, Fr.mul(roots.S2.h2w3[i], t1));
c2 = Fr.add(c2, Fr.mul(Fr.square(roots.S2.h2w3[i]), t2));
res = Fr.add(res, Fr.mul(c2, LiS2[i]));
}

@@ -453,21 +484,9 @@

for (let i = 0; i < 3; i++) {
c2Values[i + 3] = Fr.add(proof.evaluations.zw, Fr.mul(roots.S2.h3w3[i], proof.evaluations.t1w));
c2Values[i + 3] = Fr.add(c2Values[i + 3], Fr.mul(Fr.square(roots.S2.h3w3[i]), proof.evaluations.t2w));
}
let c2 = Fr.add(proof.evaluations.zw, Fr.mul(roots.S2.h3w3[i], proof.evaluations.t1w));
c2 = Fr.add(c2, Fr.mul(Fr.square(roots.S2.h3w3[i]), proof.evaluations.t2w));
// Interpolate a polynomial with the points computed previously
if (logger) logger.info("··· Computing r2(xi)");
const R2 = Polynomial.lagrangePolynomialInterpolation(
[roots.S2.h2w3[0], roots.S2.h2w3[1], roots.S2.h2w3[2],
roots.S2.h3w3[0], roots.S2.h3w3[1], roots.S2.h3w3[2]],
c2Values, curve);
// Check the degree of r2(X) < 6
if (R2.degree() > 5) {
throw new Error("R2 Polynomial is not well calculated");
res = Fr.add(res, Fr.mul(c2, LiS2[i + 3]));
}
// Evaluate the polynomial in challenges.y
if (logger) logger.info("··· Computing evaluation r2(y)");
return R2.evaluate(challenges.y);
return res;
}

@@ -535,2 +554,57 @@

return await curve.pairingEq(G1.neg(A1), A2, B1, B2);
}
}
export function computeLagrangeLiSi(roots, x, xi, curve) {
const Fr = curve.Fr;
const len = roots.length;
const num = Fr.sub(Fr.exp(x, len), xi);
const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2));
const Li = [];
for (let i = 0; i < len; i++) {
const den2 = roots[((len - 1) * i) % len];
const den3 = Fr.sub(x, roots[i]);
Li[i] = Fr.div(num, Fr.mul(Fr.mul(den1, den2), den3));
}
return Li;
}
export function computeLagrangeLiS2(roots, value, xi0, xi1, curve) {
const Fr = curve.Fr;
const Li = [];
const len = roots[0].length;
const n = len * roots.length;
const num1 = Fr.exp(value, n);
const num2 = Fr.mul(Fr.add(xi0, xi1), Fr.exp(value, len));
const num3 = Fr.mul(xi0, xi1);
const num = Fr.add(Fr.sub(num1, num2), num3);
let den1 = Fr.mul(Fr.mul(Fr.e(len), roots[0][0]), Fr.sub(xi0, xi1));
for (let i = 0; i < len; i++) {
const den2 = roots[0][(len - 1) * i % len];
const den3 = Fr.sub(value, roots[0][i]);
const den = Fr.mul(den1,Fr.mul(den2, den3));
Li[i] = Fr.div(num, den);
}
den1 = Fr.mul(Fr.mul(Fr.e(len), roots[1][0]), Fr.sub(xi1, xi0));
for (let i = 0; i < len; i++) {
const den2 = roots[1][(len - 1) * i % len];
const den3 = Fr.sub(value, roots[1][i]);
const den = Fr.mul(den1,Fr.mul(den2, den3));
Li[i + len] = Fr.div(num, den);
}
return Li;
}

@@ -44,2 +44,7 @@ /*

if (!publicInputsAreValid(curve, publicSignals)) {
if (logger) logger.error("Public inputs are not valid.");
return false;
}
for (let i=0; i<publicSignals.length; i++) {

@@ -58,2 +63,7 @@ const buffP = curve.G1.fromObject(vk_verifier.IC[i+1]);

if (!isWellConstructed(curve, {pi_a, pi_b, pi_c})) {
if(logger) logger.error("Proof commitments are not valid.");
return false;
}
const vk_gamma_2 = curve.G2.fromObject(vk_verifier.vk_gamma_2);

@@ -80,1 +90,19 @@ const vk_delta_2 = curve.G2.fromObject(vk_verifier.vk_delta_2);

}
function isWellConstructed(curve, proof) {
const G1 = curve.G1;
const G2 = curve.G2;
return G1.isValid(proof.pi_a)
&& G2.isValid(proof.pi_b)
&& G1.isValid(proof.pi_c);
}
function publicInputsAreValid(curve, publicInputs) {
for(let i = 0; i < publicInputs.length; i++) {
if(!Scalar.lt(publicInputs[i], curve.r)) {
return false;
}
}
return true;
}

@@ -117,2 +117,29 @@ /*

export function getRandomBytes(n) {
let array = new Uint8Array(n);
if (typeof globalThis.crypto !== "undefined") { // Supported
globalThis.crypto.getRandomValues(array);
} else { // NodeJS
crypto.randomFillSync(array);
}
return array;
}
export async function sha256digest(data) {
if (typeof globalThis.crypto !== "undefined" && typeof globalThis.crypto.subtle !== "undefined") { // Supported
const buffer = await globalThis.crypto.subtle.digest("SHA-256", data.buffer);
return new Uint8Array(buffer);
} else { // NodeJS
return crypto.createHash("sha256").update(data).digest();
}
}
/**
* @param {Uint8Array} data
* @param {number} offset
*/
export function readUInt32BE(data, offset) {
return new DataView(data.buffer).getUint32(offset, false);
}
export async function getRandomRng(entropy) {

@@ -124,10 +151,10 @@ // Generate a random Rng

const hasher = Blake2b(64);
hasher.update(crypto.randomBytes(64));
hasher.update(getRandomBytes(64));
const enc = new TextEncoder(); // always utf-8
hasher.update(enc.encode(entropy));
const hash = Buffer.from(hasher.digest());
const hash = hasher.digest();
const seed = [];
for (let i=0;i<8;i++) {
seed[i] = hash.readUInt32BE(i*4);
seed[i] = readUInt32BE(hash, i*4);
}

@@ -138,3 +165,3 @@ const rng = new ChaCha(seed);

export function rngFromBeaconParams(beaconHash, numIterationsExp) {
export async function rngFromBeaconParams(beaconHash, numIterationsExp) {
let nIterationsInner;

@@ -153,3 +180,3 @@ let nIterationsOuter;

for (let j=0; j<nIterationsInner; j++) {
curHash = crypto.createHash("sha256").update(curHash).digest();
curHash = await sha256digest(curHash);
}

@@ -156,0 +183,0 @@ }

@@ -49,25 +49,18 @@ /*

const proofBuff = new Uint8Array(G1.F.n8*2*9 + Fr.n8*7);
G1.toRprUncompressed(proofBuff, 0, G1.e(proof.A));
G1.toRprUncompressed(proofBuff, G1.F.n8*2, G1.e(proof.B));
G1.toRprUncompressed(proofBuff, G1.F.n8*4, G1.e(proof.C));
G1.toRprUncompressed(proofBuff, G1.F.n8*6, G1.e(proof.Z));
G1.toRprUncompressed(proofBuff, G1.F.n8*8, G1.e(proof.T1));
G1.toRprUncompressed(proofBuff, G1.F.n8*10, G1.e(proof.T2));
G1.toRprUncompressed(proofBuff, G1.F.n8*12, G1.e(proof.T3));
G1.toRprUncompressed(proofBuff, G1.F.n8*14, G1.e(proof.Wxi));
G1.toRprUncompressed(proofBuff, G1.F.n8*16, G1.e(proof.Wxiw));
Fr.toRprBE(proofBuff, G1.F.n8*18 , Fr.e(proof.eval_a));
Fr.toRprBE(proofBuff, G1.F.n8*18 + Fr.n8, Fr.e(proof.eval_b));
Fr.toRprBE(proofBuff, G1.F.n8*18 + Fr.n8*2, Fr.e(proof.eval_c));
Fr.toRprBE(proofBuff, G1.F.n8*18 + Fr.n8*3, Fr.e(proof.eval_s1));
Fr.toRprBE(proofBuff, G1.F.n8*18 + Fr.n8*4, Fr.e(proof.eval_s2));
Fr.toRprBE(proofBuff, G1.F.n8*18 + Fr.n8*5, Fr.e(proof.eval_zw));
Fr.toRprBE(proofBuff, G1.F.n8*18 + Fr.n8*6, Fr.e(proof.eval_r));
const proofHex = Array.from(proofBuff).map(i2hex).join("");
const S="0x"+proofHex+",["+inputs+"]";
return S;
return `[${p256(proof.A[0])}, ${p256(proof.A[1])},` +
`${p256(proof.B[0])},${p256(proof.B[1])},` +
`${p256(proof.C[0])},${p256(proof.C[1])},` +
`${p256(proof.Z[0])},${p256(proof.Z[1])},` +
`${p256(proof.T1[0])},${p256(proof.T1[1])},` +
`${p256(proof.T2[0])},${p256(proof.T2[1])},` +
`${p256(proof.T3[0])},${p256(proof.T3[1])},` +
`${p256(proof.Wxi[0])},${p256(proof.Wxi[1])},` +
`${p256(proof.Wxiw[0])},${p256(proof.Wxiw[1])},` +
`${p256(proof.eval_a)},` +
`${p256(proof.eval_b)},` +
`${p256(proof.eval_c)},` +
`${p256(proof.eval_s1)},` +
`${p256(proof.eval_s2)},` +
`${p256(proof.eval_zw)}]` +
`[${inputs}]`;
}

@@ -25,16 +25,36 @@ /*

import * as wtnsUtils from "./wtns_utils.js";
import { getCurveFromQ as getCurve } from "./curves.js";
import { Scalar, utils, BigBuffer } from "ffjavascript";
const {stringifyBigInts} = utils;
import jsSha3 from "js-sha3";
const { keccak256 } = jsSha3;
import { Proof } from "./proof.js";
import { Keccak256Transcript } from "./Keccak256Transcript.js";
import { MulZ } from "./mul_z.js";
import { ZKEY_PL_HEADER_SECTION,
ZKEY_PL_ADDITIONS_SECTION,
ZKEY_PL_A_MAP_SECTION,
ZKEY_PL_B_MAP_SECTION,
ZKEY_PL_C_MAP_SECTION,
ZKEY_PL_QM_SECTION,
ZKEY_PL_QL_SECTION,
ZKEY_PL_QR_SECTION,
ZKEY_PL_QO_SECTION,
ZKEY_PL_QC_SECTION,
ZKEY_PL_SIGMA_SECTION,
ZKEY_PL_LAGRANGE_SECTION,
ZKEY_PL_PTAU_SECTION,
} from "./plonk_constants.js";
import { Polynomial } from "./polynomial/polynomial.js";
import { Evaluations } from "./polynomial/evaluations.js";
export default async function plonk16Prove(zkeyFileName, witnessFileName, logger) {
const {fd: fdWtns, sections: sectionsWtns} = await binFileUtils.readBinFile(witnessFileName, "wtns", 2, 1<<25, 1<<23);
// Read witness file
if (logger) logger.debug("> Reading witness file");
const wtns = await wtnsUtils.readHeader(fdWtns, sectionsWtns);
const {fd: fdZKey, sections: sectionsZKey} = await binFileUtils.readBinFile(zkeyFileName, "zkey", 2, 1<<25, 1<<23);
// Read zkey file
if (logger) logger.debug("> Reading zkey file");
const {fd: fdZKey, sections: zkeySections} = await binFileUtils.readBinFile(zkeyFileName, "zkey", 2, 1<<25, 1<<23);
const zkey = await zkeyUtils.readHeader(fdZKey, sectionsZKey);
const zkey = await zkeyUtils.readHeader(fdZKey, zkeySections);
if (zkey.protocol != "plonk") {

@@ -53,8 +73,24 @@ throw new Error("zkey file is not plonk");

const curve = zkey.curve;
const Fr = curve.Fr;
const G1 = curve.G1;
const n8r = curve.Fr.n8;
const sDomain = zkey.domainSize * n8r;
if (logger) logger.debug("Reading Wtns");
if (logger) {
logger.debug("----------------------------");
logger.debug(" PLONK PROVE SETTINGS");
logger.debug(` Curve: ${curve.name}`);
logger.debug(` Circuit power: ${zkey.power}`);
logger.debug(` Domain size: ${zkey.domainSize}`);
logger.debug(` Vars: ${zkey.nVars}`);
logger.debug(` Public vars: ${zkey.nPublic}`);
logger.debug(` Constraints: ${zkey.nConstraints}`);
logger.debug(` Additions: ${zkey.nAdditions}`);
logger.debug("----------------------------");
}
//Read witness data
if (logger) logger.debug("> Reading witness file data");
const buffWitness = await binFileUtils.readSection(fdWtns, sectionsWtns, 2);
// First element in plonk is not used and can be any value. (But always the same).

@@ -65,35 +101,58 @@ // We set it to zero to go faster in the exponentiations.

let buffers = {};
let polynomials = {};
let evaluations = {};
let challenges = {};
let proof = new Proof(curve, logger);
const transcript = new Keccak256Transcript(curve);
if (logger) logger.debug(`> Reading Section ${ZKEY_PL_ADDITIONS_SECTION}. Additions`);
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 Section ${ZKEY_PL_SIGMA_SECTION}. Sigma1, Sigma2 & Sigma 3`);
if (logger) logger.debug("··· Reading Sigma polynomials ");
polynomials.Sigma1 = new Polynomial(new BigBuffer(sDomain), curve, logger);
polynomials.Sigma2 = new Polynomial(new BigBuffer(sDomain), curve, logger);
polynomials.Sigma3 = new Polynomial(new BigBuffer(sDomain), curve, logger);
const sigmaBuff = new BigBuffer(zkey.domainSize*n8r*4*3);
let o = sectionsZKey[12][0].p + zkey.domainSize*n8r;
await fdZKey.readToBuffer(sigmaBuff, 0 , zkey.domainSize*n8r*4, o);
o += zkey.domainSize*n8r*5;
await fdZKey.readToBuffer(sigmaBuff, zkey.domainSize*n8r*4 , zkey.domainSize*n8r*4, o);
o += zkey.domainSize*n8r*5;
await fdZKey.readToBuffer(sigmaBuff, zkey.domainSize*n8r*8 , zkey.domainSize*n8r*4, o);
await fdZKey.readToBuffer(polynomials.Sigma1.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p);
await fdZKey.readToBuffer(polynomials.Sigma2.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 5 * sDomain);
await fdZKey.readToBuffer(polynomials.Sigma3.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 10 * sDomain);
const pol_s1 = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_s1, 0 , zkey.domainSize*n8r, sectionsZKey[12][0].p);
if (logger) logger.debug("··· Reading Sigma evaluations");
evaluations.Sigma1 = new Evaluations(new BigBuffer(sDomain * 4), curve, logger);
evaluations.Sigma2 = new Evaluations(new BigBuffer(sDomain * 4), curve, logger);
evaluations.Sigma3 = new Evaluations(new BigBuffer(sDomain * 4), curve, 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);
await fdZKey.readToBuffer(evaluations.Sigma1.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + sDomain);
await fdZKey.readToBuffer(evaluations.Sigma2.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 6 * sDomain);
await fdZKey.readToBuffer(evaluations.Sigma3.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 11 * sDomain);
const PTau = await binFileUtils.readSection(fdZKey, sectionsZKey, 14);
if (logger) logger.debug(`> Reading Section ${ZKEY_PL_PTAU_SECTION}. Powers of Tau`);
const PTau = await binFileUtils.readSection(fdZKey, zkeySections, ZKEY_PL_PTAU_SECTION);
let publicSignals = [];
const ch = {};
for (let i=1; i<= zkey.nPublic; i++) {
const pub = buffWitness.slice(i*Fr.n8, i*Fr.n8+Fr.n8);
publicSignals.push(Scalar.fromRprLE(pub));
}
if (logger) logger.debug("");
if (logger) logger.debug("> ROUND 1");
await round1();
if (logger) logger.debug("> ROUND 2");
await round2();
if (logger) logger.debug("> ROUND 3");
await round3();
if (logger) logger.debug("> ROUND 4");
await round4();
if (logger) logger.debug("> ROUND 5");
await round5();
///////////////////////

@@ -103,88 +162,47 @@ // Final adjustments //

proof.protocol = "plonk";
proof.curve = curve.name;
await fdZKey.close();
await fdWtns.close();
let publicSignals = [];
// Prepare proof
let _proof = proof.toObjectProof(false);
_proof.protocol = "plonk";
_proof.curve = curve.name;
if (logger) logger.debug("PLONK PROVER FINISHED");
for (let i=1; i<= zkey.nPublic; i++) {
const pub = buffWitness.slice(i*Fr.n8, i*Fr.n8+Fr.n8);
publicSignals.push(Scalar.fromRprLE(pub));
}
return {
proof: stringifyBigInts(_proof),
publicSignals: stringifyBigInts(publicSignals)
};
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(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);
proof.eval_c = Fr.toObject(proof.eval_c);
proof.eval_s1 = Fr.toObject(proof.eval_s1);
proof.eval_s2 = Fr.toObject(proof.eval_s2);
proof.eval_zw = Fr.toObject(proof.eval_zw);
proof.eval_t = Fr.toObject(proof.eval_t);
proof.eval_r = Fr.toObject(proof.eval_r);
proof.Wxi = G1.toObject(proof.Wxi);
proof.Wxiw = G1.toObject(proof.Wxiw);
delete proof.eval_t;
proof = stringifyBigInts(proof);
publicSignals = stringifyBigInts(publicSignals);
return {proof, publicSignals};
async function calculateAdditions() {
const additionsBuff = await binFileUtils.readSection(fdZKey, sectionsZKey, 3);
if (logger) logger.debug("··· Computing additions");
const additionsBuff = await binFileUtils.readSection(fdZKey, zkeySections, ZKEY_PL_ADDITIONS_SECTION);
const sSum = 8+curve.Fr.n8*2;
// sizes: wireId_x = 4 bytes (32 bits), factor_x = field size bits
// Addition form: wireId_a wireId_b factor_a factor_b (size is 4 + 4 + sFr + sFr)
const sSum = 8 + n8r * 2;
for (let i=0; i<zkey.nAdditions; i++) {
const ai= readUInt32(additionsBuff, i*sSum);
const bi= readUInt32(additionsBuff, i*sSum+4);
const ac= additionsBuff.slice(i*sSum+8, i*sSum+8+n8r);
const bc= additionsBuff.slice(i*sSum+8+n8r, i*sSum+8+n8r*2);
const aw= getWitness(ai);
const bw= getWitness(bi);
for (let i = 0; i < zkey.nAdditions; i++) {
if (logger && (0 !== i) && (i % 100000 === 0)) logger.debug(` addition ${i}/${zkey.nAdditions}`);
const r = curve.Fr.add(
curve.Fr.mul(ac, aw),
curve.Fr.mul(bc, bw)
);
buffInternalWitness.set(r, n8r*i);
}
// Read addition values
let offset = i * sSum;
const signalId1 = readUInt32(additionsBuff, offset);
offset += 4;
const signalId2 = readUInt32(additionsBuff, offset);
offset += 4;
const factor1 = additionsBuff.slice(offset, offset + n8r);
offset += n8r;
const factor2 = additionsBuff.slice(offset, offset + n8r);
}
// Get witness value
const witness1 = getWitness(signalId1);
const witness2 = getWitness(signalId2);
async function buildABC() {
let A = new BigBuffer(zkey.domainSize * n8r);
let B = new BigBuffer(zkey.domainSize * n8r);
let C = new BigBuffer(zkey.domainSize * n8r);
//Calculate final result
const result = Fr.add(Fr.mul(factor1, witness1), Fr.mul(factor2, witness2));
const aMap = await binFileUtils.readSection(fdZKey, sectionsZKey, 4);
const bMap = await binFileUtils.readSection(fdZKey, sectionsZKey, 5);
const cMap = await binFileUtils.readSection(fdZKey, sectionsZKey, 6);
for (let i=0; i<zkey.nConstrains; i++) {
const iA = readUInt32(aMap, i*4);
A.set(getWitness(iA), i*n8r);
const iB = readUInt32(bMap, i*4);
B.set(getWitness(iB), i*n8r);
const iC = readUInt32(cMap, i*4);
C.set(getWitness(iC), i*n8r);
buffInternalWitness.set(result, n8r * i);
}
A = await Fr.batchToMontgomery(A);
B = await Fr.batchToMontgomery(B);
C = await Fr.batchToMontgomery(C);
return [A,B,C];
}

@@ -209,99 +227,213 @@

async function round1() {
ch.b = [];
// STEP 1.1 - Generate random blinding scalars (b1, ..., b11) ∈ F
challenges.b = [];
for (let i=1; i<=11; i++) {
ch.b[i] = curve.Fr.random();
challenges.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]]);
// STEP 1.2 - Compute wire polynomials a(X), b(X) and c(X)
if (logger) logger.debug("> Computing A, B, C wire polynomials");
await computeWirePolynomials();
proof.A = await expTau(pol_a, "multiexp A");
proof.B = await expTau(pol_b, "multiexp B");
proof.C = await expTau(pol_c, "multiexp C");
// STEP 1.3 - Compute [a]_1, [b]_1, [c]_1
if (logger) logger.debug("> Computing A, B, C MSM");
let commitA = await polynomials.A.multiExponentiation(PTau, "A");
let commitB = await polynomials.B.multiExponentiation(PTau, "B");
let commitC = await polynomials.C.multiExponentiation(PTau, "C");
// First output of the prover is ([A]_1, [B]_1, [C]_1)
proof.addPolynomial("A", commitA);
proof.addPolynomial("B", commitB);
proof.addPolynomial("C", commitC);
return 0;
}
async function computeWirePolynomials() {
if (logger) logger.debug("··· Reading data from zkey file");
// Build A, B and C evaluations buffer from zkey and witness files
buffers.A = new BigBuffer(sDomain);
buffers.B = new BigBuffer(sDomain);
buffers.C = new BigBuffer(sDomain);
// Read zkey file to the buffers
const aMapBuff = await binFileUtils.readSection(fdZKey, zkeySections, ZKEY_PL_A_MAP_SECTION);
const bMapBuff = await binFileUtils.readSection(fdZKey, zkeySections, ZKEY_PL_B_MAP_SECTION);
const cMapBuff = await binFileUtils.readSection(fdZKey, zkeySections, ZKEY_PL_C_MAP_SECTION);
// Compute all witness from signal ids and set them to A,B & C buffers
for (let i = 0; i < zkey.nConstraints; i++) {
const i_sFr = i * n8r;
const offset = i * 4;
// Compute A value from a signal id
const signalIdA = readUInt32(aMapBuff, offset);
buffers.A.set(getWitness(signalIdA), i_sFr);
// Compute B value from a signal id
const signalIdB = readUInt32(bMapBuff, offset);
buffers.B.set(getWitness(signalIdB), i_sFr);
// Compute C value from a signal id
const signalIdC = readUInt32(cMapBuff, offset);
buffers.C.set(getWitness(signalIdC), i_sFr);
}
buffers.A = await Fr.batchToMontgomery(buffers.A);
buffers.B = await Fr.batchToMontgomery(buffers.B);
buffers.C = await Fr.batchToMontgomery(buffers.C);
// Compute the coefficients of the wire polynomials a(X), b(X) and c(X) from A,B & C buffers
if (logger) logger.debug("··· Computing A ifft");
polynomials.A = await Polynomial.fromEvaluations(buffers.A, curve, logger);
if (logger) logger.debug("··· Computing B ifft");
polynomials.B = await Polynomial.fromEvaluations(buffers.B, curve, logger);
if (logger) logger.debug("··· Computing C ifft");
polynomials.C = await Polynomial.fromEvaluations(buffers.C, curve, logger);
// Compute extended evaluations of a(X), b(X) and c(X) polynomials
if (logger) logger.debug("··· Computing A fft");
evaluations.A = await Evaluations.fromPolynomial(polynomials.A, 4, curve, logger);
if (logger) logger.debug("··· Computing B fft");
evaluations.B = await Evaluations.fromPolynomial(polynomials.B, 4, curve, logger);
if (logger) logger.debug("··· 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) {
throw new Error("A Polynomial is not well calculated");
}
if (polynomials.B.degree() >= zkey.domainSize + 2) {
throw new Error("B Polynomial is not well calculated");
}
if (polynomials.C.degree() >= zkey.domainSize + 2) {
throw new Error("C Polynomial is not well calculated");
}
}
async function round2() {
// STEP 2.1 - Compute permutation challenge beta and gamma ∈ F
// Compute permutation challenge beta
if (logger) logger.debug("> Computing challenges beta and gamma");
transcript.reset();
const transcript1 = new Uint8Array(zkey.nPublic*n8r + G1.F.n8*2*3);
for (let i=0; i<zkey.nPublic; i++) {
Fr.toRprBE(transcript1, i*n8r, A.slice((i)*n8r, (i+1)*n8r));
transcript.addPolCommitment(zkey.Qm);
transcript.addPolCommitment(zkey.Ql);
transcript.addPolCommitment(zkey.Qr);
transcript.addPolCommitment(zkey.Qo);
transcript.addPolCommitment(zkey.Qc);
transcript.addPolCommitment(zkey.S1);
transcript.addPolCommitment(zkey.S2);
transcript.addPolCommitment(zkey.S3);
// Add A to the transcript
for (let i = 0; i < zkey.nPublic; i++) {
transcript.addScalar(buffers.A.slice(i * n8r, i * n8r + n8r));
}
G1.toRprUncompressed(transcript1, zkey.nPublic*n8r + 0, proof.A);
G1.toRprUncompressed(transcript1, zkey.nPublic*n8r + G1.F.n8*2, proof.B);
G1.toRprUncompressed(transcript1, zkey.nPublic*n8r + G1.F.n8*4, proof.C);
ch.beta = hashToFr(transcript1);
if (logger) logger.debug("beta: " + Fr.toString(ch.beta));
// Add A, B, C to the transcript
transcript.addPolCommitment(proof.getPolynomial("A"));
transcript.addPolCommitment(proof.getPolynomial("B"));
transcript.addPolCommitment(proof.getPolynomial("C"));
challenges.beta = transcript.getChallenge();
if (logger) logger.debug("··· challenges.beta: " + Fr.toString(challenges.beta, 16));
// Compute permutation challenge gamma
transcript.reset();
transcript.addScalar(challenges.beta);
challenges.gamma = transcript.getChallenge();
if (logger) logger.debug("··· challenges.gamma: " + Fr.toString(challenges.gamma, 16));
const transcript2 = new Uint8Array(n8r);
Fr.toRprBE(transcript2, 0, ch.beta);
ch.gamma = hashToFr(transcript2);
if (logger) logger.debug("gamma: " + Fr.toString(ch.gamma));
let numArr = new BigBuffer(Fr.n8*zkey.domainSize);
let denArr = new BigBuffer(Fr.n8*zkey.domainSize);
// STEP 2.2 - Compute permutation polynomial z(X)
if (logger) logger.debug("> Computing Z polynomial");
await computeZ();
// STEP 2.3 - Compute permutation [z]_1
if (logger) logger.debug("> Computing Z MSM");
let commitZ = await polynomials.Z.multiExponentiation(PTau, "Z");
// Second output of the prover is ([Z]_1)
proof.addPolynomial("Z", commitZ);
}
async function computeZ() {
if (logger) logger.debug("··· Computing Z evaluations");
let numArr = new BigBuffer(sDomain);
let denArr = new BigBuffer(sDomain);
// Set the first values to 1
numArr.set(Fr.one, 0);
denArr.set(Fr.one, 0);
// Set initial omega
let w = Fr.one;
for (let i=0; i<zkey.domainSize; i++) {
let n1 = A.slice(i*n8r, (i+1)*n8r);
n1 = Fr.add( n1, Fr.mul(ch.beta, w) );
n1 = Fr.add( n1, ch.gamma );
for (let i = 0; i < zkey.domainSize; i++) {
const i_n8r = i * n8r;
const a = buffers.A.slice(i_n8r, i_n8r + n8r);
const b = buffers.B.slice(i_n8r, i_n8r + n8r);
const c = buffers.C.slice(i_n8r, i_n8r + n8r);
let n2 = B.slice(i*n8r, (i+1)*n8r);
n2 = Fr.add( n2, Fr.mul(zkey.k1, Fr.mul(ch.beta, w) ));
n2 = Fr.add( n2, ch.gamma );
// Z(X) := numArr / denArr
// numArr := (a + beta·ω + gamma)(b + beta·ω·k1 + gamma)(c + beta·ω·k2 + gamma)
const betaw = Fr.mul(challenges.beta, w);
let n3 = C.slice(i*n8r, (i+1)*n8r);
n3 = Fr.add( n3, Fr.mul(zkey.k2, Fr.mul(ch.beta, w) ));
n3 = Fr.add( n3, ch.gamma );
let n1 = Fr.add(a, betaw);
n1 = Fr.add(n1, challenges.gamma);
const num = Fr.mul(n1, Fr.mul(n2, n3));
let n2 = Fr.add(b, Fr.mul(zkey.k1, betaw));
n2 = Fr.add(n2, challenges.gamma);
let d1 = A.slice(i*n8r, (i+1)*n8r);
d1 = Fr.add(d1, Fr.mul( sigmaBuff.slice(i*n8r*4, i*n8r*4 + n8r) , ch.beta));
d1 = Fr.add(d1, ch.gamma);
let n3 = Fr.add(c, Fr.mul(zkey.k2, betaw));
n3 = Fr.add(n3, challenges.gamma);
let d2 = B.slice(i*n8r, (i+1)*n8r);
d2 = Fr.add(d2, Fr.mul( sigmaBuff.slice((zkey.domainSize + i)*4*n8r, (zkey.domainSize + i)*4*n8r+n8r) , ch.beta));
d2 = Fr.add(d2, ch.gamma);
let num = Fr.mul(n1, Fr.mul(n2, n3));
let d3 = C.slice(i*n8r, (i+1)*n8r);
d3 = Fr.add(d3, Fr.mul( sigmaBuff.slice((zkey.domainSize*2 + i)*4*n8r, (zkey.domainSize*2 + i)*4*n8r + n8r) , ch.beta));
d3 = Fr.add(d3, ch.gamma);
// denArr := (a + beta·sigma1 + gamma)(b + beta·sigma2 + gamma)(c + beta·sigma3 + gamma)
let d1 = Fr.add(a, Fr.mul(evaluations.Sigma1.getEvaluation(i * 4), challenges.beta));
d1 = Fr.add(d1, challenges.gamma);
const den = Fr.mul(d1, Fr.mul(d2, d3));
let d2 = Fr.add(b, Fr.mul(evaluations.Sigma2.getEvaluation(i * 4), challenges.beta));
d2 = Fr.add(d2, challenges.gamma);
numArr.set(
Fr.mul(
numArr.slice(i*n8r,(i+1)*n8r) ,
num
),
((i+1)%zkey.domainSize)*n8r
);
let d3 = Fr.add(c, Fr.mul(evaluations.Sigma3.getEvaluation(i * 4), challenges.beta));
d3 = Fr.add(d3, challenges.gamma);
denArr.set(
Fr.mul(
denArr.slice(i*n8r,(i+1)*n8r) ,
den
),
((i+1)%zkey.domainSize)*n8r
);
let den = Fr.mul(d1, Fr.mul(d2, d3));
// Multiply current num value with the previous one saved in numArr
num = Fr.mul(numArr.slice(i_n8r, i_n8r + n8r), num);
numArr.set(num, ((i + 1) % zkey.domainSize) * n8r);
// Multiply current den value with the previous one saved in denArr
den = Fr.mul(denArr.slice(i_n8r, i_n8r + n8r), den);
denArr.set(den, ((i + 1) % zkey.domainSize) * n8r);
w = Fr.mul(w, Fr.w[zkey.power]);
}
// Compute the inverse of denArr to compute in the next command the
// division numArr/denArr by multiplying num · 1/denArr
denArr = await Fr.batchInverse(denArr);
// TODO: Do it in assembly and in parallel
for (let i=0; i<zkey.domainSize; i++) {
numArr.set( Fr.mul( numArr.slice(i*n8r, (i+1)*n8r), denArr.slice(i*n8r, (i+1)*n8r) ) ,i*n8r);
// Multiply numArr · denArr where denArr was inverted in the previous command
for (let i = 0; i < zkey.domainSize; i++) {
const i_sFr = i * n8r;
const z = Fr.mul(numArr.slice(i_sFr, i_sFr + n8r), denArr.slice(i_sFr, i_sFr + n8r));
numArr.set(z, i_sFr);
}
// From now on the values saved on numArr will be Z(X) buffer
buffers.Z = numArr;
if (!Fr.eq(numArr.slice(0, n8r), Fr.one)) {

@@ -311,118 +443,122 @@ throw new Error("Copy constraints does not match");

Z = numArr;
// Compute polynomial coefficients z(X) from buffers.Z
if (logger) logger.debug("··· Computing Z ifft");
polynomials.Z = await Polynomial.fromEvaluations(buffers.Z, curve, logger);
[pol_z, Z4] = await to4T(Z, [ch.b[9], ch.b[8], ch.b[7]]);
// Compute extended evaluations of z(X) polynomial
if (logger) logger.debug("··· Computing Z fft");
evaluations.Z = await Evaluations.fromPolynomial(polynomials.Z, 4, curve, logger);
proof.Z = await expTau( pol_z, "multiexp Z");
// Blind z(X) polynomial coefficients with blinding scalars b
polynomials.Z.blindCoefficients([challenges.b[9], challenges.b[8], challenges.b[7]]);
// Check degree
if (polynomials.Z.degree() >= zkey.domainSize + 3) {
throw new Error("Z Polynomial is not well calculated");
}
delete buffers.Z;
}
async function round3() {
if (logger) logger.debug("> Computing challenge alpha");
/*
async function checkDegree(P) {
const p = await curve.Fr.ifft(P);
let deg = (P.byteLength/n8r)-1;
while ((deg>0)&&(Fr.isZero(p.slice(deg*n8r, deg*n8r+n8r)))) deg--;
return deg;
}
// STEP 3.1 - Compute evaluation challenge alpha ∈ F
transcript.reset();
transcript.addScalar(challenges.beta);
transcript.addScalar(challenges.gamma);
transcript.addPolCommitment(proof.getPolynomial("Z"));
function printPol(P) {
const n=(P.byteLength/n8r);
console.log("[");
for (let i=0; i<n; i++) {
console.log(Fr.toString(P.slice(i*n8r, i*n8r+n8r)));
}
console.log("]");
}
*/
challenges.alpha = transcript.getChallenge();
challenges.alpha2 = Fr.square(challenges.alpha);
if (logger) logger.debug("··· challenges.alpha: " + Fr.toString(challenges.alpha, 16));
if (logger) logger.debug("phse3: Reading QM4");
const QM4 = new BigBuffer(zkey.domainSize*4*n8r);
await fdZKey.readToBuffer(QM4, 0 , zkey.domainSize*n8r*4, sectionsZKey[7][0].p + zkey.domainSize*n8r);
// Compute quotient polynomial T(X)
if (logger) logger.debug("> Computing T polynomial");
await computeT();
if (logger) logger.debug("phse3: Reading QL4");
const QL4 = new BigBuffer(zkey.domainSize*4*n8r);
await fdZKey.readToBuffer(QL4, 0 , zkey.domainSize*n8r*4, sectionsZKey[8][0].p + zkey.domainSize*n8r);
// Compute [T1]_1, [T2]_1, [T3]_1
if (logger) logger.debug("> Computing T MSM");
let commitT1 = await polynomials.T1.multiExponentiation(PTau, "T1");
let commitT2 = await polynomials.T2.multiExponentiation(PTau, "T2");
let commitT3 = await polynomials.T3.multiExponentiation(PTau, "T3");
if (logger) logger.debug("phse3: Reading QR4");
const QR4 = new BigBuffer(zkey.domainSize*4*n8r);
await fdZKey.readToBuffer(QR4, 0 , zkey.domainSize*n8r*4, sectionsZKey[9][0].p + zkey.domainSize*n8r);
// Third output of the prover is ([T1]_1, [T2]_1, [T3]_1)
proof.addPolynomial("T1", commitT1);
proof.addPolynomial("T2", commitT2);
proof.addPolynomial("T3", commitT3);
}
if (logger) logger.debug("phse3: Reading QO4");
const QO4 = new BigBuffer(zkey.domainSize*4*n8r);
await fdZKey.readToBuffer(QO4, 0 , zkey.domainSize*n8r*4, sectionsZKey[10][0].p + zkey.domainSize*n8r);
async function computeT() {
if (logger)
logger.debug(`··· Reading sections ${ZKEY_PL_QL_SECTION}, ${ZKEY_PL_QR_SECTION}` +
`, ${ZKEY_PL_QM_SECTION}, ${ZKEY_PL_QO_SECTION}, ${ZKEY_PL_QC_SECTION}. Q selectors`);
// Reserve memory for Q's evaluations
evaluations.QL = new Evaluations(new BigBuffer(sDomain * 4), curve, logger);
evaluations.QR = new Evaluations(new BigBuffer(sDomain * 4), curve, logger);
evaluations.QM = new Evaluations(new BigBuffer(sDomain * 4), curve, logger);
evaluations.QO = new Evaluations(new BigBuffer(sDomain * 4), curve, logger);
evaluations.QC = new Evaluations(new BigBuffer(sDomain * 4), curve, logger);
if (logger) logger.debug("phse3: Reading QC4");
const QC4 = new BigBuffer(zkey.domainSize*4*n8r);
await fdZKey.readToBuffer(QC4, 0 , zkey.domainSize*n8r*4, sectionsZKey[11][0].p + zkey.domainSize*n8r);
// Read Q's evaluations from zkey file
await fdZKey.readToBuffer(evaluations.QL.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QL_SECTION][0].p + sDomain);
await fdZKey.readToBuffer(evaluations.QR.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QR_SECTION][0].p + sDomain);
await fdZKey.readToBuffer(evaluations.QM.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QM_SECTION][0].p + sDomain);
await fdZKey.readToBuffer(evaluations.QO.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QO_SECTION][0].p + sDomain);
await fdZKey.readToBuffer(evaluations.QC.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QC_SECTION][0].p + sDomain);
const lPols = await binFileUtils.readSection(fdZKey, sectionsZKey, 13);
// Read Lagrange polynomials & evaluations from zkey file
evaluations.Lagrange = new Evaluations(new BigBuffer(sDomain * 4 * zkey.nPublic), curve, logger);
const transcript3 = new Uint8Array(G1.F.n8*2);
G1.toRprUncompressed(transcript3, 0, proof.Z);
for (let i = 0; i < zkey.nPublic; i++) {
await fdZKey.readToBuffer(evaluations.Lagrange.eval, i * sDomain * 4, sDomain * 4, zkeySections[ZKEY_PL_LAGRANGE_SECTION][0].p + i * 5 * sDomain + sDomain);
}
ch.alpha = hashToFr(transcript3);
buffers.T = new BigBuffer(sDomain * 4);
buffers.Tz = new BigBuffer(sDomain * 4);
if (logger) logger.debug("alpha: " + Fr.toString(ch.alpha));
if (logger) logger.debug("··· Computing T evaluations");
let w = Fr.one;
for (let i = 0; i < zkey.domainSize * 4; i++) {
if (logger && (0 !== i) && (i % 100000 === 0))
logger.debug(` T evaluation ${i}/${zkey.domainSize * 4}`);
const Z1 = [
Fr.zero,
Fr.add(Fr.e(-1), Fr.w[2]),
Fr.e(-2),
Fr.sub(Fr.e(-1), Fr.w[2]),
];
const a = evaluations.A.getEvaluation(i);
const b = evaluations.B.getEvaluation(i);
const c = evaluations.C.getEvaluation(i);
const z = evaluations.Z.getEvaluation(i);
const zw = evaluations.Z.getEvaluation((zkey.domainSize * 4 + 4 + i) % (zkey.domainSize * 4));
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 qm = evaluations.QM.getEvaluation(i);
const ql = evaluations.QL.getEvaluation(i);
const qr = evaluations.QR.getEvaluation(i);
const qo = evaluations.QO.getEvaluation(i);
const qc = evaluations.QC.getEvaluation(i);
const s1 = evaluations.Sigma1.getEvaluation(i);
const s2 = evaluations.Sigma2.getEvaluation(i);
const s3 = evaluations.Sigma3.getEvaluation(i);
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 ap = Fr.add(challenges.b[2], Fr.mul(challenges.b[1], w));
const bp = Fr.add(challenges.b[4], Fr.mul(challenges.b[3], w));
const cp = Fr.add(challenges.b[6], Fr.mul(challenges.b[5], w));
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*4; i++) {
if ((i%4096 == 0)&&(logger)) logger.debug(`calculating t ${i}/${zkey.domainSize*4}`);
const a = A4.slice(i*n8r, i*n8r+n8r);
const b = B4.slice(i*n8r, i*n8r+n8r);
const c = C4.slice(i*n8r, i*n8r+n8r);
const z = Z4.slice(i*n8r, i*n8r+n8r);
const zw = Z4.slice(((i+zkey.domainSize*4+4)%(zkey.domainSize*4)) *n8r, ((i+zkey.domainSize*4+4)%(zkey.domainSize*4)) *n8r +n8r);
const qm = QM4.slice(i*n8r, i*n8r+n8r);
const ql = QL4.slice(i*n8r, i*n8r+n8r);
const qr = QR4.slice(i*n8r, i*n8r+n8r);
const qo = QO4.slice(i*n8r, i*n8r+n8r);
const qc = QC4.slice(i*n8r, i*n8r+n8r);
const s1 = sigmaBuff.slice(i*n8r, i*n8r+n8r);
const s2 = sigmaBuff.slice((i+zkey.domainSize*4)*n8r, (i+zkey.domainSize*4)*n8r+n8r);
const s3 = sigmaBuff.slice((i+zkey.domainSize*8)*n8r, (i+zkey.domainSize*8)*n8r+n8r);
const ap = Fr.add(ch.b[2], Fr.mul(ch.b[1], w));
const bp = Fr.add(ch.b[4], Fr.mul(ch.b[3], w));
const cp = Fr.add(ch.b[6], Fr.mul(ch.b[5], w));
const w2 = Fr.square(w);
const zp = Fr.add(Fr.add(Fr.mul(ch.b[7], w2), Fr.mul(ch.b[8], w)), ch.b[9]);
const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], w2), Fr.mul(challenges.b[8], w)), challenges.b[9]);
const wW = Fr.mul(w, Fr.w[zkey.power]);
const wW2 = Fr.square(wW);
const zWp = Fr.add(Fr.add(Fr.mul(ch.b[7], wW2), Fr.mul(ch.b[8], wW)), ch.b[9]);
const zWp = Fr.add(Fr.add(Fr.mul(challenges.b[7], wW2), Fr.mul(challenges.b[8], wW)), challenges.b[9]);
let pl = Fr.zero;
for (let j=0; j<zkey.nPublic; j++) {
pl = Fr.sub(pl, Fr.mul(
lPols.slice( (j*5*zkey.domainSize+ zkey.domainSize+ i)*n8r, (j*5*zkey.domainSize+ zkey.domainSize + i+1)*n8r),
A.slice(j*n8r, (j+1)*n8r)
));
let pi = Fr.zero;
for (let j = 0; j < zkey.nPublic; j++) {
const offset = (j * 4 * zkey.domainSize) + i;
const lPol = evaluations.Lagrange.getEvaluation(offset);
const aVal = buffers.A.slice(j * n8r, (j + 1) * n8r);
pi = Fr.sub(pi, Fr.mul(lPol, aVal));
}
let [e1, e1z] = mul2(a, b, ap, bp, i%4);
// e1 := a(X)b(X)qM(X) + a(X)qL(X) + b(X)qR(X) + c(X)qO(X) + PI(X) + qC(X)
let [e1, e1z] = MulZ.mul2(a, b, ap, bp, i % 4, Fr);
e1 = Fr.mul(e1, qm);

@@ -440,477 +576,321 @@ e1z = Fr.mul(e1z, qm);

e1 = Fr.add(e1, pl);
e1 = Fr.add(e1, pi);
e1 = Fr.add(e1, qc);
const betaw = Fr.mul(ch.beta, w);
let e2a =a;
// e2 := α[(a(X) + βX + γ)(b(X) + βk1X + γ)(c(X) + βk2X + γ)z(X)]
const betaw = Fr.mul(challenges.beta, w);
let e2a = a;
e2a = Fr.add(e2a, betaw);
e2a = Fr.add(e2a, ch.gamma);
e2a = Fr.add(e2a, challenges.gamma);
let e2b =b;
let e2b = b;
e2b = Fr.add(e2b, Fr.mul(betaw, zkey.k1));
e2b = Fr.add(e2b, ch.gamma);
e2b = Fr.add(e2b, challenges.gamma);
let e2c =c;
let e2c = c;
e2c = Fr.add(e2c, Fr.mul(betaw, zkey.k2));
e2c = Fr.add(e2c, ch.gamma);
e2c = Fr.add(e2c, challenges.gamma);
let e2d = z;
let [e2, e2z] = mul4(e2a, e2b, e2c, e2d, ap, bp, cp, zp, i%4);
e2 = Fr.mul(e2, ch.alpha);
e2z = Fr.mul(e2z, ch.alpha);
let [e2, e2z] = MulZ.mul4(e2a, e2b, e2c, e2d, ap, bp, cp, zp, i % 4, Fr);
e2 = Fr.mul(e2, challenges.alpha);
e2z = Fr.mul(e2z, challenges.alpha);
// e3 := α[(a(X) + βSσ1(X) + γ)(b(X) + βSσ2(X) + γ)(c(X) + βSσ3(X) + γ)z(Xω)]
let e3a = a;
e3a = Fr.add(e3a, Fr.mul(ch.beta, s1));
e3a = Fr.add(e3a, ch.gamma);
e3a = Fr.add(e3a, Fr.mul(challenges.beta, s1));
e3a = Fr.add(e3a, challenges.gamma);
let e3b = b;
e3b = Fr.add(e3b, Fr.mul(ch.beta,s2));
e3b = Fr.add(e3b, ch.gamma);
e3b = Fr.add(e3b, Fr.mul(challenges.beta, s2));
e3b = Fr.add(e3b, challenges.gamma);
let e3c = c;
e3c = Fr.add(e3c, Fr.mul(ch.beta,s3));
e3c = Fr.add(e3c, ch.gamma);
e3c = Fr.add(e3c, Fr.mul(challenges.beta, s3));
e3c = Fr.add(e3c, challenges.gamma);
let e3d = zw;
let [e3, e3z] = mul4(e3a, e3b, e3c, e3d, ap, bp, cp, zWp, i%4);
let [e3, e3z] = MulZ.mul4(e3a, e3b, e3c, e3d, ap, bp, cp, zWp, i % 4, Fr);
e3 = Fr.mul(e3, ch.alpha);
e3z = Fr.mul(e3z, ch.alpha);
e3 = Fr.mul(e3, challenges.alpha);
e3z = Fr.mul(e3z, challenges.alpha);
// e4 := α^2(z(X)−1)L1(X)
let e4 = Fr.sub(z, Fr.one);
e4 = Fr.mul(e4, lPols.slice( (zkey.domainSize + i)*n8r, (zkey.domainSize+i+1)*n8r));
e4 = Fr.mul(e4, Fr.mul(ch.alpha, ch.alpha));
e4 = Fr.mul(e4, evaluations.Lagrange.getEvaluation(i));
e4 = Fr.mul(e4, challenges.alpha2);
let e4z = Fr.mul(zp, lPols.slice( (zkey.domainSize + i)*n8r, (zkey.domainSize+i+1)*n8r));
e4z = Fr.mul(e4z, Fr.mul(ch.alpha, ch.alpha));
let e4z = Fr.mul(zp, evaluations.Lagrange.getEvaluation(i));
e4z = Fr.mul(e4z, challenges.alpha2);
let e = Fr.add(Fr.sub(Fr.add(e1, e2), e3), e4);
let ez = Fr.add(Fr.sub(Fr.add(e1z, e2z), e3z), e4z);
T.set(e, i*n8r);
Tz.set(ez, i*n8r);
let t = Fr.add(Fr.sub(Fr.add(e1, e2), e3), e4);
let tz = Fr.add(Fr.sub(Fr.add(e1z, e2z), e3z), e4z);
w = Fr.mul(w, Fr.w[zkey.power+2]);
buffers.T.set(t, i * n8r);
buffers.Tz.set(tz, i * n8r);
w = Fr.mul(w, Fr.w[zkey.power + 2]);
}
if (logger) logger.debug("ifft T");
let t = await Fr.ifft(T);
// Compute the coefficients of the polynomial T0(X) from buffers.T0
if (logger)
logger.debug("··· Computing T ifft");
polynomials.T = await Polynomial.fromEvaluations(buffers.T, curve, logger);
if (logger) logger.debug("dividing T/Z");
for (let i=0; i<zkey.domainSize; i++) {
t.set(Fr.neg(t.slice(i*n8r, i*n8r+n8r)), i*n8r);
}
// Divide the polynomial T0 by Z_H(X)
if (logger)
logger.debug("··· Computing T / ZH");
polynomials.T.divZh(zkey.domainSize, 4);
for (let i=zkey.domainSize; i<zkey.domainSize*4; i++) {
const a = Fr.sub(
t.slice((i-zkey.domainSize)*n8r, (i-zkey.domainSize)*n8r + n8r),
t.slice(i*n8r, i*n8r+n8r)
);
t.set(a, i*n8r);
if (i > (zkey.domainSize*3 -4) ) {
if (!Fr.isZero(a)) {
throw new Error("T Polynomial is not divisible");
}
}
}
// Compute the coefficients of the polynomial Tz(X) from buffers.Tz
if (logger)
logger.debug("··· Computing Tz ifft");
polynomials.Tz = await Polynomial.fromEvaluations(buffers.Tz, curve, logger);
if (logger) logger.debug("ifft Tz");
const tz = await Fr.ifft(Tz);
for (let i=0; i<zkey.domainSize*4; i++) {
const a = tz.slice(i*n8r, (i+1)*n8r);
if (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
);
}
// Add the polynomial T1z to T1 to get the final polynomial T1
polynomials.T.add(polynomials.Tz);
// Check degree
if (polynomials.T.degree() >= zkey.domainSize * 3 + 6) {
throw new Error("T Polynomial is not well calculated");
}
pol_t = t.slice(0, (zkey.domainSize * 3 + 6) * n8r);
// t(x) has degree 3n + 5, we are going to split t(x) into three smaller polynomials:
// t'_low and t'_mid with a degree < n and t'_high with a degree n+5
// such that t(x) = t'_low(X) + X^n t'_mid(X) + X^{2n} t'_hi(X)
// T1' and T2' with a degree < n and T3' with a degree n+5
// such that t(x) = T1'(X) + X^n T2'(X) + X^{2n} T3'(X)
// To randomize the parts we use blinding scalars b_10 and b_11 in a way that doesn't change t(X):
// t_low(X) = t'_low(X) + b_10 X^n
// t_mid(X) = t'_mid(X) - b_10 + b_11 X^n
// t_high(X) = t'_high(X) - b_11
// T1(X) = T1'(X) + b_10 X^n
// T2(X) = T2'(X) - b_10 + b_11 X^n
// T3(X) = T3'(X) - b_11
// such that
// t(X) = t_low(X) + X^n t_mid(X) + X^2n t_high(X)
// t(X) = T1(X) + X^n T2(X) + X^2n T3(X)
if (logger) logger.debug("··· Computing T1, T2, T3 polynomials");
polynomials.T1 = new Polynomial(new BigBuffer((zkey.domainSize + 1) * n8r), curve, logger);
polynomials.T2 = new Polynomial(new BigBuffer((zkey.domainSize + 1) * n8r), curve, logger);
polynomials.T3 = new Polynomial(new BigBuffer((zkey.domainSize + 6) * n8r), curve, logger);
// compute t_low(X)
let polTLow = new BigBuffer((zkey.domainSize + 1) * n8r);
polTLow.set(t.slice(0, zkey.domainSize * n8r), 0);
polynomials.T1.coef.set(polynomials.T.coef.slice(0, sDomain), 0);
polynomials.T2.coef.set(polynomials.T.coef.slice(sDomain, sDomain * 2), 0);
polynomials.T3.coef.set(polynomials.T.coef.slice(sDomain * 2, sDomain * 3 + 6 * n8r), 0);
// Add blinding scalar b_10 as a new coefficient n
polTLow.set(ch.b[10], zkey.domainSize * n8r);
polynomials.T1.setCoef(zkey.domainSize, challenges.b[10]);
// compute t_mid(X)
let polTMid = new BigBuffer((zkey.domainSize + 1) * n8r);
polTMid.set(t.slice(zkey.domainSize * n8r, zkey.domainSize * 2 * n8r), 0);
// Subtract blinding scalar b_10 to the lowest coefficient of t_mid
const lowestMid = Fr.sub(polTMid.slice(0, n8r), ch.b[10]);
polTMid.set(lowestMid, 0);
// Add blinding scalar b_11 as a new coefficient n
polTMid.set(ch.b[11], zkey.domainSize * n8r);
const lowestMid = Fr.sub(polynomials.T2.getCoef(0), challenges.b[10]);
polynomials.T2.setCoef(0, lowestMid);
polynomials.T2.setCoef(zkey.domainSize, challenges.b[11]);
// compute t_high(X)
let polTHigh = new BigBuffer((zkey.domainSize + 6) * n8r);
polTHigh.set(t.slice(zkey.domainSize * 2 * n8r, (zkey.domainSize * 3 + 6) * n8r), 0);
//Subtract blinding scalar b_11 to the lowest coefficient of t_high
const lowestHigh = Fr.sub(polTHigh.slice(0, n8r), ch.b[11]);
polTHigh.set(lowestHigh, 0);
const lowestHigh = Fr.sub(polynomials.T3.getCoef(0), challenges.b[11]);
polynomials.T3.setCoef(0, lowestHigh);
}
proof.T1 = await expTau(polTLow, "multiexp T1");
proof.T2 = await expTau(polTMid, "multiexp T2");
proof.T3 = await expTau(polTHigh, "multiexp T3");
async function round4() {
if (logger) logger.debug("> Computing challenge xi");
function mul2(a,b, ap, bp, p) {
let r, rz;
// STEP 4.1 - Compute evaluation challenge xi ∈ F
transcript.reset();
transcript.addScalar(challenges.alpha);
transcript.addPolCommitment(proof.getPolynomial("T1"));
transcript.addPolCommitment(proof.getPolynomial("T2"));
transcript.addPolCommitment(proof.getPolynomial("T3"));
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);
challenges.xi = transcript.getChallenge();
challenges.xiw = Fr.mul(challenges.xi, Fr.w[zkey.power]);
if (logger) logger.debug("··· challenges.xi: " + Fr.toString(challenges.xi, 16));
r = a_b;
// Fourth output of the prover is ( a(xi), b(xi), c(xi), s1(xi), s2(xi), z(xiw) )
proof.addEvaluation("eval_a", polynomials.A.evaluate(challenges.xi));
proof.addEvaluation("eval_b", polynomials.B.evaluate(challenges.xi));
proof.addEvaluation("eval_c", polynomials.C.evaluate(challenges.xi));
proof.addEvaluation("eval_s1", polynomials.Sigma1.evaluate(challenges.xi));
proof.addEvaluation("eval_s2", polynomials.Sigma2.evaluate(challenges.xi));
proof.addEvaluation("eval_zw", polynomials.Z.evaluate(challenges.xiw));
}
let a0 = Fr.add(a_bp, ap_b);
async function round5() {
if (logger) logger.debug("> Computing challenge v");
// STEP 5.1 - Compute evaluation challenge v ∈ F
transcript.reset();
transcript.addScalar(challenges.xi);
transcript.addScalar(proof.getEvaluation("eval_a"));
transcript.addScalar(proof.getEvaluation("eval_b"));
transcript.addScalar(proof.getEvaluation("eval_c"));
transcript.addScalar(proof.getEvaluation("eval_s1"));
transcript.addScalar(proof.getEvaluation("eval_s2"));
transcript.addScalar(proof.getEvaluation("eval_zw"));
let a1 = ap_bp;
challenges.v = [];
challenges.v[1] = transcript.getChallenge();
if (logger) logger.debug("··· challenges.v: " + Fr.toString(challenges.v[1], 16));
rz = a0;
if (p) {
rz = Fr.add(rz, Fr.mul(Z1[p], a1));
}
return [r, rz];
for (let i = 2; i < 6; i++) {
challenges.v[i] = Fr.mul(challenges.v[i - 1], challenges.v[1]);
}
function mul4(a,b,c,d, ap, bp, cp, dp, p) {
let r, rz;
// STEP 5.2 Compute linearisation polynomial r(X)
if (logger) logger.debug("> Computing linearisation polynomial R(X)");
await computeR();
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);
//STEP 5.3 Compute opening proof polynomial Wxi(X)
if (logger) logger.debug("> Computing opening proof polynomial Wxi(X) polynomial");
computeWxi();
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);
//STEP 5.4 Compute opening proof polynomial Wxiw(X)
if (logger) logger.debug("> Computing opening proof polynomial Wxiw(X) polynomial");
computeWxiw();
r = Fr.mul(a_b, c_d);
if (logger) logger.debug("> Computing Wxi, Wxiw MSM");
let commitWxi = await polynomials.Wxi.multiExponentiation(PTau, "Wxi");
let commitWxiw = await polynomials.Wxiw.multiExponentiation(PTau, "Wxiw");
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];
}
// Fifth output of the prover is ([Wxi]_1, [Wxiw]_1)
proof.addPolynomial("Wxi", commitWxi);
proof.addPolynomial("Wxiw", commitWxiw);
}
async function round4() {
const pol_qm = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_qm, 0 , zkey.domainSize*n8r, sectionsZKey[7][0].p);
async function computeR() {
const Fr = curve.Fr;
// Reserve memory for Q's polynomials
polynomials.QL = new Polynomial(new BigBuffer(sDomain), curve, logger);
polynomials.QR = new Polynomial(new BigBuffer(sDomain), curve, logger);
polynomials.QM = new Polynomial(new BigBuffer(sDomain), curve, logger);
polynomials.QO = new Polynomial(new BigBuffer(sDomain), curve, logger);
polynomials.QC = new Polynomial(new BigBuffer(sDomain), curve, logger);
const pol_ql = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_ql, 0 , zkey.domainSize*n8r, sectionsZKey[8][0].p);
const pol_qr = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_qr, 0 , zkey.domainSize*n8r, sectionsZKey[9][0].p);
const pol_qo = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_qo, 0 , zkey.domainSize*n8r, sectionsZKey[10][0].p);
const pol_qc = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_qc, 0 , zkey.domainSize*n8r, sectionsZKey[11][0].p);
const pol_s3 = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_s3, 0 , zkey.domainSize*n8r, sectionsZKey[12][0].p + 10*zkey.domainSize*n8r);
const transcript4 = new Uint8Array(G1.F.n8*2*3);
G1.toRprUncompressed(transcript4, 0, proof.T1);
G1.toRprUncompressed(transcript4, G1.F.n8*2, proof.T2);
G1.toRprUncompressed(transcript4, G1.F.n8*4, proof.T3);
ch.xi = hashToFr(transcript4);
if (logger) logger.debug("xi: " + Fr.toString(ch.xi));
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);
// Read Q's evaluations from zkey file
await fdZKey.readToBuffer(polynomials.QL.coef, 0, sDomain, zkeySections[ZKEY_PL_QL_SECTION][0].p);
await fdZKey.readToBuffer(polynomials.QR.coef, 0, sDomain, zkeySections[ZKEY_PL_QR_SECTION][0].p);
await fdZKey.readToBuffer(polynomials.QM.coef, 0, sDomain, zkeySections[ZKEY_PL_QM_SECTION][0].p);
await fdZKey.readToBuffer(polynomials.QO.coef, 0, sDomain, zkeySections[ZKEY_PL_QO_SECTION][0].p);
await fdZKey.readToBuffer(polynomials.QC.coef, 0, sDomain, zkeySections[ZKEY_PL_QC_SECTION][0].p);
let e2a = proof.eval_a;
const betaxi = Fr.mul(ch.beta, ch.xi);
e2a = Fr.add( e2a, betaxi);
e2a = Fr.add( e2a, ch.gamma);
challenges.xin = challenges.xi;
for (let i = 0; i < zkey.power; i++) {
challenges.xin = Fr.square(challenges.xin);
}
let e2b = proof.eval_b;
e2b = Fr.add( e2b, Fr.mul(betaxi, zkey.k1));
e2b = Fr.add( e2b, ch.gamma);
challenges.zh = Fr.sub(challenges.xin, Fr.one);
let e2c = proof.eval_c;
e2c = Fr.add( e2c, Fr.mul(betaxi, zkey.k2));
e2c = Fr.add( e2c, ch.gamma);
const L = [];
const e2 = Fr.mul(Fr.mul(Fr.mul(e2a, e2b), e2c), ch.alpha);
const n = Fr.e(zkey.domainSize);
let w = Fr.one;
for (let i = 1; i <= Math.max(1, zkey.nPublic); i++) {
L[i] = Fr.div(Fr.mul(w, challenges.zh), Fr.mul(n, Fr.sub(challenges.xi, w)));
w = Fr.mul(w, Fr.w[zkey.power]);
}
let e3a = proof.eval_a;
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(ch.beta, proof.eval_s2));
e3b = Fr.add( e3b, ch.gamma);
let e3 = Fr.mul(e3a, e3b);
e3 = Fr.mul(e3, ch.beta);
e3 = Fr.mul(e3, proof.eval_zw);
e3 = Fr.mul(e3, ch.alpha);
ch.xim= ch.xi;
for (let i=0; i<zkey.power; i++) ch.xim = Fr.mul(ch.xim, ch.xim);
const eval_l1 = Fr.div(
Fr.sub(ch.xim, Fr.one),
Fr.mul(Fr.sub(ch.xi, Fr.one), Fr.e(zkey.domainSize))
Fr.sub(challenges.xin, Fr.one),
Fr.mul(n, Fr.sub(challenges.xi, Fr.one))
);
const e4 = Fr.mul(eval_l1, Fr.mul(ch.alpha, ch.alpha));
const coefs3 = e3;
const coefz = Fr.add(e2, e4);
pol_r = new BigBuffer((zkey.domainSize+3)*n8r);
for (let i = 0; i<zkey.domainSize+3; i++) {
let v = Fr.mul(coefz, pol_z.slice(i*n8r,(i+1)*n8r));
if (i<zkey.domainSize) {
v = Fr.add(v, Fr.mul(coef_ab, pol_qm.slice(i*n8r,(i+1)*n8r)));
v = Fr.add(v, Fr.mul(proof.eval_a, pol_ql.slice(i*n8r,(i+1)*n8r)));
v = Fr.add(v, Fr.mul(proof.eval_b, pol_qr.slice(i*n8r,(i+1)*n8r)));
v = Fr.add(v, Fr.mul(proof.eval_c, pol_qo.slice(i*n8r,(i+1)*n8r)));
v = Fr.add(v, pol_qc.slice(i*n8r,(i+1)*n8r));
v = Fr.sub(v, Fr.mul(coefs3, pol_s3.slice(i*n8r,(i+1)*n8r)));
if (logger) {
logger.debug("Lagrange Evaluations: ");
for (let i=1; i<L.length; i++) {
logger.debug(`L${i}(xi)=` + Fr.toString(L[i], 16));
}
pol_r.set(v, i*n8r);
}
proof.eval_r = evalPol(pol_r, ch.xi);
}
let eval_pi = Fr.zero;
for (let i=0; i<publicSignals.length; i++) {
const w = Fr.e(publicSignals[i]);
eval_pi = Fr.sub(eval_pi, Fr.mul(w, L[i+1]));
}
async function round5() {
const transcript5 = new Uint8Array(n8r*7);
Fr.toRprBE(transcript5, 0, proof.eval_a);
Fr.toRprBE(transcript5, n8r, proof.eval_b);
Fr.toRprBE(transcript5, n8r*2, proof.eval_c);
Fr.toRprBE(transcript5, n8r*3, proof.eval_s1);
Fr.toRprBE(transcript5, n8r*4, proof.eval_s2);
Fr.toRprBE(transcript5, n8r*5, proof.eval_zw);
Fr.toRprBE(transcript5, n8r*6, proof.eval_r);
ch.v = [];
ch.v[1] = hashToFr(transcript5);
if (logger) logger.debug("v: " + Fr.toString(ch.v[1]));
if (logger) logger.debug("PI: " + Fr.toString(eval_pi, 16));
for (let i=2; i<=6; i++ ) ch.v[i] = Fr.mul(ch.v[i-1], ch.v[1]);
let pol_wxi = new BigBuffer((zkey.domainSize+6)*n8r);
// Compute constant parts of R(X)
const coef_ab = Fr.mul(proof.evaluations.eval_a, proof.evaluations.eval_b);
const xi2m = Fr.mul(ch.xim, ch.xim);
let e2a = proof.evaluations.eval_a;
const betaxi = Fr.mul(challenges.beta, challenges.xi);
e2a = Fr.add(e2a, betaxi);
e2a = Fr.add(e2a, challenges.gamma);
for (let i = 0; i < zkey.domainSize + 6; i++) {
let w = Fr.zero;
let e2b = proof.evaluations.eval_b;
e2b = Fr.add(e2b, Fr.mul(betaxi, zkey.k1));
e2b = Fr.add(e2b, challenges.gamma);
const polTHigh = pol_t.slice((zkey.domainSize * 2 + i) * n8r, (zkey.domainSize * 2 + i + 1) * n8r);
w = Fr.add(w, Fr.mul(xi2m, polTHigh));
let e2c = proof.evaluations.eval_c;
e2c = Fr.add(e2c, Fr.mul(betaxi, zkey.k2));
e2c = Fr.add(e2c, challenges.gamma);
if (i < zkey.domainSize + 3) {
w = Fr.add(w, Fr.mul(ch.v[1], pol_r.slice(i * n8r, (i + 1) * n8r)));
}
const e2 = Fr.mul(Fr.mul(Fr.mul(e2a, e2b), e2c), challenges.alpha);
if (i < zkey.domainSize + 2) {
w = Fr.add(w, Fr.mul(ch.v[2], pol_a.slice(i * n8r, (i + 1) * n8r)));
w = Fr.add(w, Fr.mul(ch.v[3], pol_b.slice(i * n8r, (i + 1) * n8r)));
w = Fr.add(w, Fr.mul(ch.v[4], pol_c.slice(i * n8r, (i + 1) * n8r)));
}
let e3a = proof.evaluations.eval_a;
e3a = Fr.add(e3a, Fr.mul(challenges.beta, proof.evaluations.eval_s1));
e3a = Fr.add(e3a, challenges.gamma);
if (i < zkey.domainSize) {
const polTLow = pol_t.slice(i * n8r, (i + 1) * n8r);
w = Fr.add(w, polTLow);
let e3b = proof.evaluations.eval_b;
e3b = Fr.add(e3b, Fr.mul(challenges.beta, proof.evaluations.eval_s2));
e3b = Fr.add(e3b, challenges.gamma);
const polTMid = pol_t.slice((zkey.domainSize + i) * n8r, (zkey.domainSize + i + 1) * n8r);
w = Fr.add(w, Fr.mul(ch.xim, polTMid));
let e3 = Fr.mul(e3a, e3b);
e3 = Fr.mul(e3, proof.evaluations.eval_zw);
e3 = Fr.mul(e3, challenges.alpha);
w = Fr.add(w, Fr.mul(ch.v[5], pol_s1.slice(i * n8r, (i + 1) * n8r)));
w = Fr.add(w, Fr.mul(ch.v[6], pol_s2.slice(i * n8r, (i + 1) * n8r)));
}
const e4 = Fr.mul(eval_l1, challenges.alpha2);
// b_10 and b_11 blinding scalars were applied on round 3 to randomize the polynomials t_low, t_mid, t_high
// Subtract blinding scalar b_10 and b_11 to the lowest coefficient
if (i === 0) {
w = Fr.sub(w, Fr.mul(xi2m, ch.b[11]));
w = Fr.sub(w, Fr.mul(ch.xim, ch.b[10]));
}
polynomials.R = new Polynomial(new BigBuffer((zkey.domainSize + 6) * n8r), curve, logger);
// Add blinding scalars b_10 and b_11 to the coefficient n
if (i === zkey.domainSize) {
w = Fr.add(w, ch.b[10]);
w = Fr.add(w, Fr.mul(ch.xim, ch.b[11]));
}
polynomials.R.add(polynomials.QM, coef_ab);
polynomials.R.add(polynomials.QL, proof.evaluations.eval_a);
polynomials.R.add(polynomials.QR, proof.evaluations.eval_b);
polynomials.R.add(polynomials.QO, proof.evaluations.eval_c);
polynomials.R.add(polynomials.QC);
polynomials.R.add(polynomials.Z, e2);
polynomials.R.sub(polynomials.Sigma3, Fr.mul(e3, challenges.beta));
polynomials.R.add(polynomials.Z, e4);
pol_wxi.set(w, i * n8r);
}
let tmp = Polynomial.fromPolynomial(polynomials.T3, curve, logger);
tmp.mulScalar(Fr.square(challenges.xin));
tmp.add(polynomials.T2, challenges.xin);
tmp.add(polynomials.T1);
tmp.mulScalar(challenges.zh);
let w0 = pol_wxi.slice(0, n8r);
w0 = Fr.sub(w0, proof.eval_t);
w0 = Fr.sub(w0, Fr.mul(ch.v[1], proof.eval_r));
w0 = Fr.sub(w0, Fr.mul(ch.v[2], proof.eval_a));
w0 = Fr.sub(w0, Fr.mul(ch.v[3], proof.eval_b));
w0 = Fr.sub(w0, Fr.mul(ch.v[4], proof.eval_c));
w0 = Fr.sub(w0, Fr.mul(ch.v[5], proof.eval_s1));
w0 = Fr.sub(w0, Fr.mul(ch.v[6], proof.eval_s2));
pol_wxi.set(w0, 0);
polynomials.R.sub(tmp);
pol_wxi= divPol1(pol_wxi, ch.xi);
let r0 = Fr.sub(eval_pi, Fr.mul(e3, Fr.add(proof.evaluations.eval_c, challenges.gamma)));
r0 = Fr.sub(r0, e4);
proof.Wxi = await expTau(pol_wxi, "multiexp Wxi");
if (logger) logger.debug("r0: " + Fr.toString(r0, 16));
let pol_wxiw = new BigBuffer((zkey.domainSize+3)*n8r);
for (let i=0; i<zkey.domainSize+3; i++) {
const w = pol_z.slice(i*n8r, (i+1)*n8r);
pol_wxiw.set(w, i*n8r);
}
w0 = pol_wxiw.slice(0, n8r);
w0 = Fr.sub(w0, proof.eval_zw);
pol_wxiw.set(w0, 0);
pol_wxiw= divPol1(pol_wxiw, Fr.mul(ch.xi, Fr.w[zkey.power]));
proof.Wxiw = await expTau(pol_wxiw, "multiexp Wxiw");
polynomials.R.addScalar(r0);
}
function hashToFr(transcript) {
const v = Scalar.fromRprBE(new Uint8Array(keccak256.arrayBuffer(transcript)));
return Fr.e(v);
}
function computeWxi() {
polynomials.Wxi = new Polynomial(new BigBuffer(sDomain + 6 * n8r), curve, logger);
polynomials.Wxi.add(polynomials.R);
polynomials.Wxi.add(polynomials.A, challenges.v[1]);
polynomials.Wxi.add(polynomials.B, challenges.v[2]);
polynomials.Wxi.add(polynomials.C, challenges.v[3]);
polynomials.Wxi.add(polynomials.Sigma1, challenges.v[4]);
polynomials.Wxi.add(polynomials.Sigma2, challenges.v[5]);
function evalPol(P, x) {
const n = P.byteLength / n8r;
if (n == 0) return Fr.zero;
let res = P.slice((n-1)*n8r, n*n8r);
for (let i=n-2; i>=0; i--) {
res = Fr.add(Fr.mul(res, x), P.slice(i*n8r, (i+1)*n8r));
}
return res;
}
polynomials.Wxi.subScalar(Fr.mul(challenges.v[1], proof.evaluations.eval_a));
polynomials.Wxi.subScalar(Fr.mul(challenges.v[2], proof.evaluations.eval_b));
polynomials.Wxi.subScalar(Fr.mul(challenges.v[3], proof.evaluations.eval_c));
polynomials.Wxi.subScalar(Fr.mul(challenges.v[4], proof.evaluations.eval_s1));
polynomials.Wxi.subScalar(Fr.mul(challenges.v[5], proof.evaluations.eval_s2));
function divPol1(P, d) {
const n = P.byteLength/n8r;
const res = new BigBuffer(n*n8r);
res.set(Fr.zero, (n-1) *n8r);
res.set(P.slice((n-1)*n8r, n*n8r), (n-2)*n8r);
for (let i=n-3; i>=0; i--) {
res.set(
Fr.add(
P.slice((i+1)*n8r, (i+2)*n8r),
Fr.mul(
d,
res.slice((i+1)*n8r, (i+2)*n8r)
)
),
i*n8r
);
}
if (!Fr.eq(
P.slice(0, n8r),
Fr.mul(
Fr.neg(d),
res.slice(0, n8r)
)
)) {
throw new Error("Polinomial does not divide");
}
return res;
polynomials.Wxi.divByZerofier(1, challenges.xi);
}
async function expTau(b, name) {
const n = b.byteLength/n8r;
const PTauN = PTau.slice(0, n*curve.G1.F.n8*2);
const bm = await curve.Fr.batchFromMontgomery(b);
let res = await curve.G1.multiExpAffine(PTauN, bm, logger, name);
res = curve.G1.toAffine(res);
return res;
}
async function computeWxiw() {
polynomials.Wxiw = Polynomial.fromPolynomial(polynomials.Z, curve, logger);
polynomials.Wxiw.subScalar(proof.evaluations.eval_zw);
async function to4T(A, pz) {
pz = pz || [];
let a = await Fr.ifft(A);
const a4 = new BigBuffer(n8r*zkey.domainSize*4);
a4.set(a, 0);
const a1 = new BigBuffer(n8r*(zkey.domainSize + pz.length));
a1.set(a, 0);
for (let i= 0; i<pz.length; i++) {
a1.set(
Fr.add(
a1.slice((zkey.domainSize+i)*n8r, (zkey.domainSize+i+1)*n8r),
pz[i]
),
(zkey.domainSize+i)*n8r
);
a1.set(
Fr.sub(
a1.slice(i*n8r, (i+1)*n8r),
pz[i]
),
i*n8r
);
}
const A4 = await Fr.fft(a4);
return [a1, A4];
polynomials.Wxiw.divByZerofier(1, challenges.xiw);
}
}

@@ -21,13 +21,12 @@ /*

/* Implementation of this paper: https://eprint.iacr.org/2019/953.pdf */
import { Scalar } from "ffjavascript";
import * as curves from "./curves.js";
import { utils } from "ffjavascript";
const {unstringifyBigInts} = utils;
import jsSha3 from "js-sha3";
const { keccak256 } = jsSha3;
import { Keccak256Transcript } from "./Keccak256Transcript.js";
export default async function plonkVerify(_vk_verifier, _publicSignals, _proof, logger) {
let vk_verifier = unstringifyBigInts(_vk_verifier);
let proof = unstringifyBigInts(_proof);
_proof = unstringifyBigInts(_proof);
let publicSignals = unstringifyBigInts(_publicSignals);

@@ -40,4 +39,7 @@

proof = fromObjectProof(curve,proof);
if (logger) logger.info("PLONK VERIFIER STARTED");
let proof = fromObjectProof(curve,_proof);
vk_verifier = fromObjectVk(curve, vk_verifier);
if (!isWellConstructed(curve, proof)) {

@@ -47,2 +49,3 @@ logger.error("Proof is not well constructed");

}
if (publicSignals.length != vk_verifier.nPublic) {

@@ -52,17 +55,18 @@ logger.error("Invalid number of public inputs");

}
const challanges = calculateChallanges(curve, proof, publicSignals);
const challenges = calculatechallenges(curve, proof, publicSignals, vk_verifier);
if (logger) {
logger.debug("beta: " + Fr.toString(challanges.beta, 16));
logger.debug("gamma: " + Fr.toString(challanges.gamma, 16));
logger.debug("alpha: " + Fr.toString(challanges.alpha, 16));
logger.debug("xi: " + Fr.toString(challanges.xi, 16));
logger.debug("v1: " + Fr.toString(challanges.v[1], 16));
logger.debug("v6: " + Fr.toString(challanges.v[6], 16));
logger.debug("u: " + Fr.toString(challanges.u, 16));
logger.debug("beta: " + Fr.toString(challenges.beta, 16));
logger.debug("gamma: " + Fr.toString(challenges.gamma, 16));
logger.debug("alpha: " + Fr.toString(challenges.alpha, 16));
logger.debug("xi: " + Fr.toString(challenges.xi, 16));
for(let i=1;i<6;i++) {
if (logger) logger.debug("v: " + Fr.toString(challenges.v[i], 16));
}
logger.debug("u: " + Fr.toString(challenges.u, 16));
}
const L = calculateLagrangeEvaluations(curve, challanges, vk_verifier);
const L = calculateLagrangeEvaluations(curve, challenges, vk_verifier);
if (logger) {
logger.debug("Lagrange Evaluations: ");
for (let i=1; i<L.length; i++) {
logger.debug(`L${i}(xi)=` + Fr.toString(L[i], 16));
logger.debug(`L${i}(xi)=` + Fr.toString(L[i], 16));
}

@@ -76,13 +80,13 @@ }

const pl = calculatePl(curve, publicSignals, L);
const pi = calculatePI(curve, publicSignals, L);
if (logger) {
logger.debug("Pl: " + Fr.toString(pl, 16));
logger.debug("PI(xi): " + Fr.toString(pi, 16));
}
const t = calculateT(curve, proof, challanges, pl, L[1]);
const r0 = calculateR0(curve, proof, challenges, pi, L[1]);
if (logger) {
logger.debug("t: " + Fr.toString(t, 16));
logger.debug("r0: " + Fr.toString(r0, 16));
}
const D = calculateD(curve, proof, challanges, vk_verifier, L[1]);
const D = calculateD(curve, proof, challenges, vk_verifier, L[1]);
if (logger) {

@@ -92,3 +96,3 @@ logger.debug("D: " + G1.toString(G1.toAffine(D), 16));

const F = calculateF(curve, proof, challanges, vk_verifier, D);
const F = calculateF(curve, proof, challenges, vk_verifier, D);
if (logger) {

@@ -98,3 +102,3 @@ logger.debug("F: " + G1.toString(G1.toAffine(F), 16));

const E = calculateE(curve, proof, challanges, vk_verifier, t);
const E = calculateE(curve, proof, challenges, r0);
if (logger) {

@@ -104,3 +108,3 @@ logger.debug("E: " + G1.toString(G1.toAffine(E), 16));

const res = await isValidPairing(curve, proof, challanges, vk_verifier, E, F);
const res = await isValidPairing(curve, proof, challenges, vk_verifier, E, F);

@@ -116,3 +120,2 @@ if (logger) {

return res;
}

@@ -138,3 +141,2 @@

res.eval_s2 = Fr.fromObject(proof.eval_s2);
res.eval_r = Fr.fromObject(proof.eval_r);
res.Wxi = G1.fromObject(proof.Wxi);

@@ -179,49 +181,65 @@ res.Wxiw = G1.fromObject(proof.Wxiw);

function calculateChallanges(curve, proof, publicSignals) {
const G1 = curve.G1;
function calculatechallenges(curve, proof, publicSignals, vk) {
const Fr = curve.Fr;
const n8r = curve.Fr.n8;
const res = {};
const transcript = new Keccak256Transcript(curve);
const transcript1 = new Uint8Array(publicSignals.length*n8r + G1.F.n8*2*3);
for (let i=0; i<publicSignals.length; i++) {
Fr.toRprBE(transcript1, i*n8r, Fr.e(publicSignals[i]));
// Challenge round 2: beta and gamma
transcript.addPolCommitment(vk.Qm);
transcript.addPolCommitment(vk.Ql);
transcript.addPolCommitment(vk.Qr);
transcript.addPolCommitment(vk.Qo);
transcript.addPolCommitment(vk.Qc);
transcript.addPolCommitment(vk.S1);
transcript.addPolCommitment(vk.S2);
transcript.addPolCommitment(vk.S3);
for (let i = 0; i < publicSignals.length; i++) {
transcript.addScalar(Fr.e(publicSignals[i]));
}
G1.toRprUncompressed(transcript1, publicSignals.length*n8r + 0, proof.A);
G1.toRprUncompressed(transcript1, publicSignals.length*n8r + G1.F.n8*2, proof.B);
G1.toRprUncompressed(transcript1, publicSignals.length*n8r + G1.F.n8*4, proof.C);
res.beta = hashToFr(curve, transcript1);
transcript.addPolCommitment(proof.A);
transcript.addPolCommitment(proof.B);
transcript.addPolCommitment(proof.C);
const transcript2 = new Uint8Array(n8r);
Fr.toRprBE(transcript2, 0, res.beta);
res.gamma = hashToFr(curve, transcript2);
res.beta = transcript.getChallenge();
const transcript3 = new Uint8Array(G1.F.n8*2);
G1.toRprUncompressed(transcript3, 0, proof.Z);
res.alpha = hashToFr(curve, transcript3);
transcript.reset();
transcript.addScalar(res.beta);
res.gamma = transcript.getChallenge();
const transcript4 = new Uint8Array(G1.F.n8*2*3);
G1.toRprUncompressed(transcript4, 0, proof.T1);
G1.toRprUncompressed(transcript4, G1.F.n8*2, proof.T2);
G1.toRprUncompressed(transcript4, G1.F.n8*4, proof.T3);
res.xi = hashToFr(curve, transcript4);
// Challenge round 3: alpha
transcript.reset();
transcript.addScalar(res.beta);
transcript.addScalar(res.gamma);
transcript.addPolCommitment(proof.Z);
res.alpha = transcript.getChallenge();
const transcript5 = new Uint8Array(n8r*7);
Fr.toRprBE(transcript5, 0, proof.eval_a);
Fr.toRprBE(transcript5, n8r, proof.eval_b);
Fr.toRprBE(transcript5, n8r*2, proof.eval_c);
Fr.toRprBE(transcript5, n8r*3, proof.eval_s1);
Fr.toRprBE(transcript5, n8r*4, proof.eval_s2);
Fr.toRprBE(transcript5, n8r*5, proof.eval_zw);
Fr.toRprBE(transcript5, n8r*6, proof.eval_r);
// Challenge round 4: xi
transcript.reset();
transcript.addScalar(res.alpha);
transcript.addPolCommitment(proof.T1);
transcript.addPolCommitment(proof.T2);
transcript.addPolCommitment(proof.T3);
res.xi = transcript.getChallenge();
// Challenge round 5: v
transcript.reset();
transcript.addScalar(res.xi);
transcript.addScalar(proof.eval_a);
transcript.addScalar(proof.eval_b);
transcript.addScalar(proof.eval_c);
transcript.addScalar(proof.eval_s1);
transcript.addScalar(proof.eval_s2);
transcript.addScalar(proof.eval_zw);
res.v = [];
res.v[1] = hashToFr(curve, transcript5);
res.v[1] = transcript.getChallenge();
for (let i=2; i<=6; i++ ) res.v[i] = Fr.mul(res.v[i-1], res.v[1]);
for (let i=2; i<6; i++ ) res.v[i] = Fr.mul(res.v[i-1], res.v[1]);
const transcript6 = new Uint8Array(G1.F.n8*2*2);
G1.toRprUncompressed(transcript6, 0, proof.Wxi);
G1.toRprUncompressed(transcript6, G1.F.n8*2, proof.Wxiw);
res.u = hashToFr(curve, transcript6);
// Challenge: u
transcript.reset();
transcript.addPolCommitment(proof.Wxi);
transcript.addPolCommitment(proof.Wxiw);
res.u = transcript.getChallenge();

@@ -231,6 +249,6 @@ return res;

function calculateLagrangeEvaluations(curve, challanges, vk) {
function calculateLagrangeEvaluations(curve, challenges, vk) {
const Fr = curve.Fr;
let xin = challanges.xi;
let xin = challenges.xi;
let domainSize = 1;

@@ -241,5 +259,6 @@ for (let i=0; i<vk.power; i++) {

}
challanges.xin = xin;
challenges.xin = xin;
challanges.zh = Fr.sub(xin, Fr.one);
challenges.zh = Fr.sub(xin, Fr.one);
const L = [];

@@ -250,3 +269,3 @@

for (let i=1; i<=Math.max(1, vk.nPublic); i++) {
L[i] = Fr.div(Fr.mul(w, challanges.zh), Fr.mul(n, Fr.sub(challanges.xi, w)));
L[i] = Fr.div(Fr.mul(w, challenges.zh), Fr.mul(n, Fr.sub(challenges.xi, w)));
w = Fr.mul(w, Fr.w[vk.power]);

@@ -258,145 +277,105 @@ }

function hashToFr(curve, transcript) {
const v = Scalar.fromRprBE(new Uint8Array(keccak256.arrayBuffer(transcript)));
return curve.Fr.e(v);
}
function calculatePl(curve, publicSignals, L) {
function calculatePI(curve, publicSignals, L) {
const Fr = curve.Fr;
let pl = Fr.zero;
for (let i=0; i<publicSignals.length; i++) {
let pi = Fr.zero;
for (let i=0; i<publicSignals.length; i++) {
const w = Fr.e(publicSignals[i]);
pl = Fr.sub(pl, Fr.mul(w, L[i+1]));
pi = Fr.sub(pi, Fr.mul(w, L[i+1]));
}
return pl;
return pi;
}
function calculateT(curve, proof, challanges, pl, l1) {
function calculateR0(curve, proof, challenges, pi, l1) {
const Fr = curve.Fr;
let num = proof.eval_r;
num = Fr.add(num, pl);
let e1 = proof.eval_a;
e1 = Fr.add(e1, Fr.mul(challanges.beta, proof.eval_s1));
e1 = Fr.add(e1, challanges.gamma);
const e1 = pi;
let e2 = proof.eval_b;
e2 = Fr.add(e2, Fr.mul(challanges.beta, proof.eval_s2));
e2 = Fr.add(e2, challanges.gamma);
const e2 = Fr.mul(l1, Fr.square(challenges.alpha));
let e3 = proof.eval_c;
e3 = Fr.add(e3, challanges.gamma);
let e3a = Fr.add(proof.eval_a, Fr.mul(challenges.beta, proof.eval_s1));
e3a = Fr.add(e3a, challenges.gamma);
let e = Fr.mul(Fr.mul(e1, e2), e3);
e = Fr.mul(e, proof.eval_zw);
e = Fr.mul(e, challanges.alpha);
let e3b = Fr.add(proof.eval_b, Fr.mul(challenges.beta, proof.eval_s2));
e3b = Fr.add(e3b, challenges.gamma);
num = Fr.sub(num, e);
let e3c = Fr.add(proof.eval_c, challenges.gamma);
num = Fr.sub(num, Fr.mul(l1, Fr.square(challanges.alpha)));
let e3 = Fr.mul(Fr.mul(e3a, e3b), e3c);
e3 = Fr.mul(e3, proof.eval_zw);
e3 = Fr.mul(e3, challenges.alpha);
const t = Fr.div(num, challanges.zh);
const r0 = Fr.sub(Fr.sub(e1, e2), e3);
return t;
return r0;
}
function calculateD(curve, proof, challanges, vk, l1) {
function calculateD(curve, proof, challenges, vk, l1) {
const G1 = curve.G1;
const Fr = curve.Fr;
let d1 = G1.timesFr(vk.Qm, Fr.mul(proof.eval_a, proof.eval_b));
d1 = G1.add(d1, G1.timesFr(vk.Ql, proof.eval_a));
d1 = G1.add(d1, G1.timesFr(vk.Qr, proof.eval_b));
d1 = G1.add(d1, G1.timesFr(vk.Qo, proof.eval_c));
d1 = G1.add(d1, vk.Qc);
let s1 = Fr.mul(Fr.mul(proof.eval_a, proof.eval_b), challanges.v[1]);
let res = G1.timesFr(vk.Qm, s1);
const betaxi = Fr.mul(challenges.beta, challenges.xi);
let s2 = Fr.mul(proof.eval_a, challanges.v[1]);
res = G1.add(res, G1.timesFr(vk.Ql, s2));
const d2a1 = Fr.add(Fr.add(proof.eval_a, betaxi), challenges.gamma);
const d2a2 = Fr.add(Fr.add(proof.eval_b, Fr.mul(betaxi, vk.k1)), challenges.gamma);
const d2a3 = Fr.add(Fr.add(proof.eval_c, Fr.mul(betaxi, vk.k2)), challenges.gamma);
let s3 = Fr.mul(proof.eval_b, challanges.v[1]);
res = G1.add(res, G1.timesFr(vk.Qr, s3));
const d2a = Fr.mul(Fr.mul(Fr.mul(d2a1, d2a2), d2a3), challenges.alpha);
let s4 = Fr.mul(proof.eval_c, challanges.v[1]);
res = G1.add(res, G1.timesFr(vk.Qo, s4));
const d2b = Fr.mul(l1, Fr.square(challenges.alpha));
res = G1.add(res, G1.timesFr(vk.Qc, challanges.v[1]));
const d2 = G1.timesFr(proof.Z, Fr.add(Fr.add(d2a, d2b), challenges.u));
const betaxi = Fr.mul(challanges.beta, challanges.xi);
let s6a = proof.eval_a;
s6a = Fr.add(s6a, betaxi);
s6a = Fr.add(s6a, challanges.gamma);
const d3a = Fr.add(Fr.add(proof.eval_a, Fr.mul(challenges.beta, proof.eval_s1)), challenges.gamma);
const d3b = Fr.add(Fr.add(proof.eval_b, Fr.mul(challenges.beta, proof.eval_s2)), challenges.gamma);
const d3c = Fr.mul(Fr.mul(challenges.alpha, challenges.beta), proof.eval_zw);
let s6b = proof.eval_b;
s6b = Fr.add(s6b, Fr.mul(betaxi, vk.k1));
s6b = Fr.add(s6b, challanges.gamma);
const d3 = G1.timesFr(vk.S3, Fr.mul(Fr.mul(d3a, d3b), d3c));
const d4low = proof.T1;
const d4mid = G1.timesFr(proof.T2, challenges.xin);
const d4high = G1.timesFr(proof.T3, Fr.square(challenges.xin));
let d4 = G1.add(d4low, G1.add(d4mid, d4high));
d4 = G1.timesFr(d4, challenges.zh);
let s6c = proof.eval_c;
s6c = Fr.add(s6c, Fr.mul(betaxi, vk.k2));
s6c = Fr.add(s6c, challanges.gamma);
const d = G1.sub(G1.sub(G1.add(d1, d2), d3), d4);
let s6 = Fr.mul(Fr.mul(s6a, s6b), s6c);
s6 = Fr.mul(s6, Fr.mul(challanges.alpha, challanges.v[1]));
let s6d = Fr.mul(Fr.mul(l1, Fr.square(challanges.alpha)), challanges.v[1]);
s6 = Fr.add(s6, s6d);
s6 = Fr.add(s6, challanges.u);
res = G1.add(res, G1.timesFr(proof.Z, s6));
let s7a = proof.eval_a;
s7a = Fr.add(s7a, Fr.mul(challanges.beta, proof.eval_s1));
s7a = Fr.add(s7a, challanges.gamma);
let s7b = proof.eval_b;
s7b = Fr.add(s7b, Fr.mul(challanges.beta, proof.eval_s2));
s7b = Fr.add(s7b, challanges.gamma);
let s7 = Fr.mul(s7a, s7b);
s7 = Fr.mul(s7, challanges.alpha);
s7 = Fr.mul(s7, challanges.v[1]);
s7 = Fr.mul(s7, challanges.beta);
s7 = Fr.mul(s7, proof.eval_zw);
res = G1.sub(res, G1.timesFr(vk.S3, s7));
return res;
return d;
}
function calculateF(curve, proof, challanges, vk, D) {
function calculateF(curve, proof, challenges, vk, D) {
const G1 = curve.G1;
const Fr = curve.Fr;
let res = proof.T1;
let res = G1.add(D, G1.timesFr(proof.A, challenges.v[1]));
res = G1.add(res, G1.timesFr(proof.B, challenges.v[2]));
res = G1.add(res, G1.timesFr(proof.C, challenges.v[3]));
res = G1.add(res, G1.timesFr(vk.S1, challenges.v[4]));
res = G1.add(res, G1.timesFr(vk.S2, challenges.v[5]));
res = G1.add(res, G1.timesFr(proof.T2, challanges.xin));
res = G1.add(res, G1.timesFr(proof.T3, Fr.square(challanges.xin)));
res = G1.add(res, D);
res = G1.add(res, G1.timesFr(proof.A, challanges.v[2]));
res = G1.add(res, G1.timesFr(proof.B, challanges.v[3]));
res = G1.add(res, G1.timesFr(proof.C, challanges.v[4]));
res = G1.add(res, G1.timesFr(vk.S1, challanges.v[5]));
res = G1.add(res, G1.timesFr(vk.S2, challanges.v[6]));
return res;
}
function calculateE(curve, proof, challanges, vk, t) {
function calculateE(curve, proof, challenges, r0) {
const G1 = curve.G1;
const Fr = curve.Fr;
let s = t;
let e = Fr.add(Fr.neg(r0), Fr.mul(challenges.v[1], proof.eval_a));
e = Fr.add(e, Fr.mul(challenges.v[2], proof.eval_b));
e = Fr.add(e, Fr.mul(challenges.v[3], proof.eval_c));
e = Fr.add(e, Fr.mul(challenges.v[4], proof.eval_s1));
e = Fr.add(e, Fr.mul(challenges.v[5], proof.eval_s2));
e = Fr.add(e, Fr.mul(challenges.u, proof.eval_zw));
s = Fr.add(s, Fr.mul(challanges.v[1], proof.eval_r));
s = Fr.add(s, Fr.mul(challanges.v[2], proof.eval_a));
s = Fr.add(s, Fr.mul(challanges.v[3], proof.eval_b));
s = Fr.add(s, Fr.mul(challanges.v[4], proof.eval_c));
s = Fr.add(s, Fr.mul(challanges.v[5], proof.eval_s1));
s = Fr.add(s, Fr.mul(challanges.v[6], proof.eval_s2));
s = Fr.add(s, Fr.mul(challanges.u, proof.eval_zw));
const res = G1.timesFr(G1.one, e);
const res = G1.timesFr(G1.one, s);
return res;
}
async function isValidPairing(curve, proof, challanges, vk, E, F) {
async function isValidPairing(curve, proof, challenges, vk, E, F) {
const G1 = curve.G1;

@@ -406,6 +385,6 @@ const Fr = curve.Fr;

let A1 = proof.Wxi;
A1 = G1.add(A1, G1.timesFr(proof.Wxiw, challanges.u));
A1 = G1.add(A1, G1.timesFr(proof.Wxiw, challenges.u));
let B1 = G1.timesFr(proof.Wxi, challanges.xi);
const s = Fr.mul(Fr.mul(challanges.u, challanges.xi), Fr.w[vk.power]);
let B1 = G1.timesFr(proof.Wxi, challenges.xi);
const s = Fr.mul(Fr.mul(challenges.u, challenges.xi), Fr.w[vk.power]);
B1 = G1.add(B1, G1.timesFr(proof.Wxiw, s));

@@ -421,3 +400,2 @@ B1 = G1.add(B1, F);

return res;
}

@@ -20,2 +20,3 @@ /*

// ZKEY constants
export {default as setup} from "./plonk_setup.js";

@@ -22,0 +23,0 @@ export {default as fullProve} from "./plonk_fullprove.js";

@@ -598,3 +598,4 @@ /*

for (let i = domainSize; i < domainSize * extensions; i++) {
const upperBound = this.coef.byteLength / this.Fr.n8;
for (let i = domainSize; i < upperBound; i++) {
const i_n8 = i * this.Fr.n8;

@@ -601,0 +602,0 @@

@@ -72,3 +72,3 @@ /*

curContribution.key = utils.keyFromBeacon(curve, lastChallengeHash, beaconHash, numIterationsExp);
curContribution.key = await utils.keyFromBeacon(curve, lastChallengeHash, beaconHash, numIterationsExp);

@@ -75,0 +75,0 @@ const responseHasher = new Blake2b(64);

@@ -362,5 +362,5 @@ /*

export function keyFromBeacon(curve, challengeHash, beaconHash, numIterationsExp) {
export async function keyFromBeacon(curve, challengeHash, beaconHash, numIterationsExp) {
const rng = misc.rngFromBeaconParams(beaconHash, numIterationsExp);
const rng = await misc.rngFromBeaconParams(beaconHash, numIterationsExp);

@@ -367,0 +367,0 @@ const key = keyPair.createPTauKey(curve, challengeHash, rng);

@@ -23,3 +23,2 @@ /*

import * as keyPair from "./keypair.js";
import crypto from "crypto";
import * as binFileUtils from "@iden3/binfileutils";

@@ -33,3 +32,3 @@ import { ChaCha, BigBuffer } from "ffjavascript";

if (cur.type == 1) { // Verify the beacon.
const beaconKey = utils.keyFromBeacon(curve, prev.nextChallenge, cur.beaconHash, cur.numIterationsExp);
const beaconKey = await utils.keyFromBeacon(curve, prev.nextChallenge, cur.beaconHash, cur.numIterationsExp);

@@ -366,9 +365,7 @@ if (!curve.G1.eq(cur.key.tau.g1_s, beaconKey.tau.g1_s)) {

const scalars = new Uint8Array(4*(n-1));
crypto.randomFillSync(scalars);
const scalars = misc.getRandomBytes(4*(n-1));
if (i>0) {
const firstBase = G.fromRprLEM(bases, 0);
const r = crypto.randomBytes(4).readUInt32BE(0, true);
const r = misc.readUInt32BE(misc.getRandomBytes(4), 0);

@@ -414,3 +411,3 @@ R1 = G.add(R1, G.timesScalar(lastBase, r));

for (let i=0; i<8; i++) {
seed[i] = crypto.randomBytes(4).readUInt32BE(0, true);
seed[i] = misc.readUInt32BE(misc.getRandomBytes(4), 0);
}

@@ -417,0 +414,0 @@

@@ -61,11 +61,21 @@ /*

toObjectProof() {
let res = {polynomials: {}, evaluations: {}};
toObjectProof(splitFields = true) {
let res = splitFields ? {polynomials: {}, evaluations: {}} : {};
Object.keys(this.polynomials).forEach(key => {
res.polynomials[key] = this.curve.G1.toObject(this.polynomials[key]);
const value = this.curve.G1.toObject(this.polynomials[key]);
if(splitFields) {
res.polynomials[key] = value;
} else {
res[key] = value;
}
});
Object.keys(this.evaluations).forEach(key => {
res.evaluations[key] = this.curve.Fr.toObject(this.evaluations[key]);
const value = this.curve.Fr.toObject(this.evaluations[key]);
if(splitFields) {
res.evaluations[key] = value;
} else {
res[key] = value;
}
});

@@ -72,0 +82,0 @@

@@ -282,3 +282,3 @@ /*

zkey.nAdditions = await fd.readULE32();
zkey.nConstrains = await fd.readULE32();
zkey.nConstraints = await fd.readULE32();
zkey.k1 = await fd.read(n8r);

@@ -285,0 +285,0 @@ zkey.k2 = await fd.read(n8r);

@@ -27,3 +27,2 @@ /*

const sameRatio = misc.sameRatio;
import crypto from "crypto";
import {hashG1, hashPubKey} from "./zkey_utils.js";

@@ -80,3 +79,3 @@ import { Scalar, ChaCha, BigBuffer } from "ffjavascript";

if (c.type == 1) {
const rng = misc.rngFromBeaconParams(c.beaconHash, c.numIterationsExp);
const rng = await misc.rngFromBeaconParams(c.beaconHash, c.numIterationsExp);
const expected_prvKey = curve.Fr.fromRng(rng);

@@ -257,6 +256,4 @@ const expected_g1_s = curve.G1.toAffine(curve.G1.fromRng(rng));

const scalars = new Uint8Array(4*n);
crypto.randomFillSync(scalars);
const scalars = misc.getRandomBytes(4*n);
const r1 = await G.multiExpAffine(bases1, scalars);

@@ -291,3 +288,3 @@ const r2 = await G.multiExpAffine(bases2, scalars);

for (let i=0; i<8; i++) {
seed[i] = crypto.randomBytes(4).readUInt32BE(0, true);
seed[i] = misc.readUInt32BE(misc.getRandomBytes(4), 0);
}

@@ -294,0 +291,0 @@ const rng = new ChaCha(seed);

@@ -25,3 +25,2 @@ import * as snarkjs from "../main.js";

let vKey;
let vKeyPlonk;
const wtns = {type: "mem"};

@@ -33,3 +32,3 @@ let proof;

curve = await getCurveFromName("bn128");
// curve.Fr.s = 10;
// curve.Fr.s = 10;
});

@@ -36,0 +35,0 @@ after( async () => {

{
"A": [
"15917573233407722732062787698951765050036957325370721125210834646525203076389",
"10234794045268909768723861952713815259678638768538486148638400158927236468234",
"5793065063820843436904916550915654859034020287932129998554119161393759429821",
"16786676070498953269978004876792259709639672042603968998602433263391391134460",
"1"
],
"B": [
"6534033380695361734911825473617889658104101245167934289050248436664841578363",
"14061971131648369041603507755410089728742438126668707374914752588236606702754",
"1950496543538410699101713925686582507181189131769299436066121974021341523887",
"6398017375697817399107120064620930090393734524197331506530258901183836391213",
"1"
],
"C": [
"14505892627896587350473010034286107819685493071925324450974954770526434593332",
"6186416458036711799535608999371759388592544992468951288703737883955685292858",
"15230464306286391636550107373893393844263753443858456494056755797915359962735",
"4295923307603640725029862081489021526166422259641176323643637657103650618753",
"1"
],
"Z": [
"12081441476366171431338238830264497598570062548451685935024863321326757767785",
"9387897371969025065284991899948083393556628309133379383594080265474146141157",
"11004047411656828660428328961973286292047311564838972190990878440058680688901",
"15436256766327825842224680700992331794957429153268020624016727514510742018077",
"1"
],
"T1": [
"11697295649838930633765261378756086756478619706964809367863062927042238692921",
"14968409908681220375122607622180081440264275996476655054223469087507417759789",
"21351603608071808295830607650880557871325148899242110976740167133549418528603",
"2645708186332646685572914154670045342238946773079254998870890373729236802677",
"1"
],
"T2": [
"2953189016956047791736757973461484048315463397915849932374528729412270696527",
"8620891985757406277592771106070049395916563323571640384543833813728271133486",
"18718055159322028716891056460848640315600372124708181482177956090488976138766",
"14545564657670478509737277771736582695733692748073867042597808406303105978491",
"1"
],
"T3": [
"16223333010830689480143912693604648201451508158843567126275050570081980855643",
"14438863974133388343515803834890541076773695198795082356970685950267401738910",
"17300643912187364232525793334678321814907265220556429696382901135492186928813",
"13687463097807270467456771887349938731995528743034200574450167125019408139064",
"1"
],
"eval_a": "14339139182789381237229239915123261853915681686933828385685851702630204504663",
"eval_b": "14868966654115759140239472823375151970328635256589988386102968278787868240414",
"eval_c": "564057494214488102817009147593706678326690684832103817838290432546546599925",
"eval_s1": "19371496695515240161592963759911623294871060124201355865755153108252682382360",
"eval_s2": "2579612056529355211259943592521042166985820548059386261162331074609979969098",
"eval_zw": "19685091872602775677986598924926591283988441651361153034121001539751878867815",
"eval_r": "17019396159933864043409418821108145005876806528173417875530903213264996917828",
"Wxi": [
"4789447887245439838828293816801085734534480786500369542683260813915807895018",
"5743534347322910212791948378800524709212623490686788228035168007519506810508",
"13971416223242651542366715728368906359640038706276531500429531708796073258277",
"10421443948033763642149912846113365572165014601716715331224624947552460520043",
"1"
],
"Wxiw": [
"19379972490037320589254794886333437175961689166573424007077500138714809349682",
"12523908414418029668596495120104904066342410136497532239942511327769729048404",
"17765787784457670830871593390874368837165912572092183824115141625095019062878",
"1923706056001260011656416104295967740181091112784478760912734896662208628583",
"1"
],
"eval_a": "10799560112054680901137226204213873700826592739080369812528079446253216295813",
"eval_b": "7877313129049829225962721657498993624288591252629781090410265210156591091645",
"eval_c": "19262479669546615646866494950794050991978938609429436242634904528122872883540",
"eval_s1": "9943707996031584540773781677363098084929121111061462884057666436801558016467",
"eval_s2": "20442292478151764537886021535271741908528859398849641563695916267470568099112",
"eval_zw": "2514741082646163896220326677313738849736483859214666037715057616704431674465",
"protocol": "plonk",
"curve": "bn128"
}

@@ -9,39 +9,39 @@ {

"Qm": [
"4574976860925876233715815557145957880705707179788243092345689458042383890488",
"4280641572679440220740870768701934042005081764212788702122100316880968332003",
"17953645607507459900286185560951810786731058999325781923205502055353263497291",
"19385486967908870028674938916390954985705306268782601788969000107603897770767",
"1"
],
"Ql": [
"965658296392348546197801330054212493203716810675203464920320569299615906620",
"2656007013467620250344837426700774817845582578535592475523934494973414078961",
"11940858774017579942566450477449012460918017239896733829055270107468309760540",
"947254594125514574342968640034741130676940992205538578216940265903584710169",
"1"
],
"Qr": [
"9466120146806803512081752933000124200435544680867502413168004293837549973279",
"21718061423910769411439185483074527939398926867139106591112998426662463026765",
"16057511199156614460548645536725007313348939819318943470685206502402956172907",
"10506209454111335156976278630909826596572196999531725341452203577193363727183",
"1"
],
"Qo": [
"14232475876760437187555678371073865360567175818750566973123447255794615727867",
"12884948380030714721172201264029036846611910042838904312559968631894569296588",
"17157624048880737579826278328189066542171805404376573481770268188483838847757",
"18514386016535062016800932564037101304017747936838789635283796814642720512673",
"1"
],
"Qc": [
"14611255151810715369553599153356422265550902840832241273629187752840438096443",
"9099095607583972457036848580058361056377035074964862926640921566382822995435",
"9425204922382128984212419080680000340238602060329517997301340801336513664736",
"9167308630107900718125273932943677561306913176994118892249570126249686869364",
"1"
],
"S1": [
"14533465958261944855196820716374074689704505288368818447966063234824080424576",
"12453353674569653145950160230568106433424266373528956571501497772329286407421",
"10782085188530267881189340256496934831907742532399561656521702603135823217637",
"12403008688044971496101927450821599344745023222457894394078671019783662128471",
"1"
],
"S2": [
"19581287390493194877650947725652399954855738146667446650367315521331119724530",
"13292535777423157488265774466403939589622049710743071078999542362804505686482",
"9279525915934333912510150900730589708299616165652915633005823194068751444534",
"17339946533833948904498037980944354287085405669808936769308277491115888828896",
"1"
],
"S3": [
"7628615832235497959754170049702774596960536866278288444040861507702299255530",
"6061093738111279431632848690609155827426019335581022466737969401920480256170",
"10636394165993966883449775646752541022226109588433686577933510456646304718904",
"18335534742276222998450555199564351867006746787413781617417650248398260441193",
"1"

@@ -62,3 +62,4 @@ ],

]
]
],
"w": "19540430494807482326159819597004422086093766032135589407132600596362845576832"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc