First try phase2

This commit is contained in:
Jordi Baylina 2020-05-31 00:46:49 +02:00
parent 2d07b2c806
commit b948a0d0d1
No known key found for this signature in database
GPG Key ID: 7480C80C1BE43112
7 changed files with 376 additions and 121 deletions

72
cli.js
View File

@ -38,11 +38,13 @@ const printR1cs = require("./src/printr1cs");
const clProcessor = require("./src/clprocessor");
const powersOfTaw = require("./src/powersoftaw");
const powersOfTaw = require("./src/powersoftau");
const bn128 = require("ffjavascript").bn128;
const solidityGenerator = require("./src/soliditygenerator.js");
const phase2 = require("./src/phase2");
const commands = [
{
cmd: "r1cs info [circuit.r1cs]",
@ -103,62 +105,69 @@ const commands = [
action: solidityGenCall
},
{
cmd: "powersoftaw new <power> [powersoftaw_0000.ptaw]",
description: "Starts a powers of taw ceremony",
cmd: "powersoftau new <power> [powersoftau_0000.ptau]",
description: "Starts a powers of tau ceremony",
alias: ["ptn"],
options: "-verbose|v",
action: powersOfTawNew
},
{
cmd: "powersoftaw export challange <powersoftaw_0000.ptaw> [challange]",
cmd: "powersoftau export challange <powersoftau_0000.ptau> [challange]",
description: "Creates a challange",
alias: ["pte"],
options: "-verbose|v",
action: powersOfTawExportChallange
},
{
cmd: "powersoftaw challange contribute <challange> [response]",
cmd: "powersoftau challange contribute <challange> [response]",
description: "Contribute to a challange",
alias: ["ptcc"],
options: "-verbose|v -entropy|e",
action: powersOfTawChallangeContribute
},
{
cmd: "powersoftaw import <powersoftaw_old.ptaw> <response> <<powersoftaw_new.ptaw>",
description: "import a response to a ptaw file",
cmd: "powersoftau import <powersoftau_old.ptau> <response> <<powersoftau_new.ptau>",
description: "import a response to a ptau file",
alias: ["pti"],
options: "-verbose|v -nopoints -nocheck -description|d -name|n",
action: powersOfTawImport
},
{
cmd: "powersoftaw verify <powersoftaw.ptaw>",
cmd: "powersoftau verify <powersoftau.ptau>",
description: "verifies a powers of tau file",
alias: ["ptv"],
options: "-verbose|v",
action: powersOfTawVerify
},
{
cmd: "powersoftaw beacon <old_powersoftaw.ptaw> <new_powersoftaw.ptaw> <beaconHash(Hex)> <numIterationsExp>",
cmd: "powersoftau beacon <old_powersoftau.ptau> <new_powersoftau.ptau> <beaconHash(Hex)> <numIterationsExp>",
description: "adds a beacon",
alias: ["ptb"],
options: "-verbose|v -name|n",
action: powersOfTawBeacon
},
{
cmd: "powersoftaw contribute <powersoftaw.ptaw> <new_powersoftaw.ptaw>",
cmd: "powersoftau contribute <powersoftau.ptau> <new_powersoftau.ptau>",
description: "verifies a powers of tau file",
alias: ["ptc"],
options: "-verbose|v -name|n -entropy|e",
action: powersOfTawContribute
},
{
cmd: "powersoftaw prepare phase2 <powersoftaw.ptaw> <new_powersoftaw.ptaw>",
cmd: "powersoftau prepare phase2 <powersoftau.ptau> <new_powersoftau.ptau>",
description: "Prepares phase 2. ",
longDescription: " This process calculates the evaluation of the Lagrange polinomials at tau for alpha*tau and beta tau",
alias: ["pt2"],
options: "-verbose|v",
action: powersOfTawPreparePhase2
},
{
cmd: "phase2 new [circuit.r1cs] [powersoftau.ptau] [circuit.zkey]",
description: "Creates an initial pkey file with zero contributions ",
alias: ["p2n"],
options: "-verbose|v",
action: phase2new
},
];
@ -504,7 +513,7 @@ async function solidityGenCall(params, options) {
async function powersOfTawNew(params, options) {
let power;
let ptawName;
let ptauName;
power = parseInt(params[0]);
if ((power<1) || (power>28)) {
@ -512,19 +521,19 @@ async function powersOfTawNew(params, options) {
}
if (params.length < 2) {
ptawName = "powersOfTaw" + power + "_0000.ptaw";
ptauName = "powersOfTaw" + power + "_0000.ptau";
} else {
ptawName = params[1];
ptauName = params[1];
}
return await powersOfTaw.newAccumulator(bn128, power, ptawName, options.verbose);
return await powersOfTaw.newAccumulator(bn128, power, ptauName, options.verbose);
}
async function powersOfTawExportChallange(params, options) {
let ptawName;
let ptauName;
let challangeName;
ptawName = params[0];
ptauName = params[0];
if (params.length < 2) {
challangeName = "challange";
@ -532,7 +541,7 @@ async function powersOfTawExportChallange(params, options) {
challangeName = params[1];
}
return await powersOfTaw.exportChallange(ptawName, challangeName, options.verbose);
return await powersOfTaw.exportChallange(ptauName, challangeName, options.verbose);
}
@ -623,3 +632,30 @@ async function powersOfTawPreparePhase2(params, options) {
return await powersOfTaw.preparePhase2(oldPtauName, newPtauName, options.verbose);
}
// phase2 new <circuit.r1cs> <powersoftau.ptau> <circuit.zkey>
async function phase2new(params, options) {
let r1csName;
let ptauName;
let zkeyName;
if (params.length < 1) {
r1csName = "circuit.r1cs";
} else {
r1csName = params[0];
}
if (params.length < 2) {
ptauName = "powersoftau.ptau";
} else {
ptauName = params[1];
}
if (params.length < 2) {
zkeyName = "circuit.zkey";
} else {
zkeyName = params[2];
}
return phase2.new(r1csName, ptauName, zkeyName, options.verbose);
}

View File

@ -88,7 +88,7 @@ async function endReadSection(fd, noCheck) {
async function writeBigInt(fd, n, n8) {
const buff = new Uint8Array(n8);
Scalar.toRprLE(buff, 0, n);
Scalar.toRprLE(buff, 0, n, n8);
await fd.write(buff);
}

3
src/phase2.js Normal file
View File

@ -0,0 +1,3 @@
module.exports.new = require("./phase2_new.js");

191
src/phase2_new.js Normal file
View File

@ -0,0 +1,191 @@
const loadR1cs = require("r1csfile").load;
const utils = require("./powersoftau_utils");
const binFileUtils = require("./binfileutils");
const writeZKey = require("./zkeyfile").write;
const assert = require("assert");
function log2( V )
{
return( ( ( V & 0xFFFF0000 ) !== 0 ? ( V &= 0xFFFF0000, 16 ) : 0 ) | ( ( V & 0xFF00FF00 ) !== 0 ? ( V &= 0xFF00FF00, 8 ) : 0 ) | ( ( V & 0xF0F0F0F0 ) !== 0 ? ( V &= 0xF0F0F0F0, 4 ) : 0 ) | ( ( V & 0xCCCCCCCC ) !== 0 ? ( V &= 0xCCCCCCCC, 2 ) : 0 ) | ( ( V & 0xAAAAAAAA ) !== 0 ) );
}
module.exports = async function phase2new(r1csName, ptauName, zkeyName) {
const r1cs = await loadR1cs(r1csName, true);
const {fd: ptauFd, sections} = await binFileUtils.readBinFile(ptauName, "ptau", 1);
const {curve, power} = await utils.readPTauHeader(ptauFd, sections);
if (r1cs.prime != curve.r) {
console.log("r1cs curve does not match powers of tau ceremony curve");
return -1;
}
const cirPower = log2(r1cs.nConstraints + r1cs.nPubInputs + r1cs.nOutputs +1 -1) +1;
if (cirPower > power) {
console.log(`circuit too big for this power of tau ceremony. ${r1cs.nConstraints} > 2**${power}`);
return -1;
}
if (!sections[12]) {
console.log("Powers of tau is not prepared.");
return -1;
}
const zKey = {
nPublic: r1cs.nOutputs + r1cs.nPubInputs,
nVars: r1cs.nVars,
q: curve.q,
r: curve.r,
domainBits: cirPower,
domainSize: 1 << cirPower
};
const linc = 1 << (power - cirPower);
calculatePolinomials(curve, zKey,r1cs);
zKey.A = new Array(r1cs.nVars);
zKey.B1 = new Array(r1cs.nVars);
zKey.B2 = new Array(r1cs.nVars);
zKey.C = new Array(r1cs.nVars);
zKey.IC = new Array(zKey.nPublic+1);
for (let i=0; i<r1cs.nVars; i++) {
zKey.A[i] = curve.G1.zero;
zKey.B1[i] = curve.G1.zero;
zKey.B2[i] = curve.G2.zero;
if (i>zKey.nPublic) {
zKey.C[i] = curve.G1.zero;
} else {
zKey.IC[i] = curve.G1.zero;
}
}
for (let i=0; i<zKey.ccoefs.length; i++) {
const c = zKey.ccoefs[i];
let CIC;
if (c.matrix == 0) {
const l1 = await readEvaluation("lTauG1", c.constraint);
const l2 = await readEvaluation("lBetaTauG1", c.constraint);
zKey.A[c.signal] =
curve.G1.add(
zKey.A[c.signal],
curve.G1.mulScalar(l1, c.value)
);
CIC = curve.G1.mulScalar(l2, c.value);
} else if (c.matrix == 1) {
const l1 = await readEvaluation("lTauG1", c.constraint);
const l2 = await readEvaluation("lTauG2", c.constraint);
const l3 = await readEvaluation("lAlphaTauG1", c.constraint);
zKey.B1[c.signal] =
curve.G1.add(
zKey.B1[c.signal],
curve.G1.mulScalar(l1, c.value)
);
zKey.B2[c.signal] =
curve.G2.add(
zKey.B2[c.signal],
curve.G2.mulScalar(l2, c.value)
);
CIC = curve.G1.mulScalar(l3, c.value);
} else if (c.matrix == 2) {
const l1 = await readEvaluation("lTauG1", c.constraint);
CIC = curve.G1.mulScalar(l1, c.value);
} else {
assert(false);
}
if (c.signal <= zKey.nPublic) {
zKey.IC[c.signal] =
curve.G1.add(
zKey.IC[c.signal],
CIC
);
} else {
zKey.C[c.signal] =
curve.G1.add(
zKey.C[c.signal],
CIC
);
}
}
zKey.hExps = new Array(zKey.domainSize-1);
for (let i=0; i< zKey.domainSize; i++) {
const t1 = await readEvaluation("tauG1", i);
const t2 = await readEvaluation("tauG1", i+zKey.domainSize);
zKey.hExps[i] = curve.G1.add(t1, t2);
}
zKey.vk_alfa_1 = await readEvaluation("alphaTauG1", 0);
zKey.vk_beta_1 = await readEvaluation("betaTauG1", 0);
zKey.vk_delta_1 = curve.G1.g;
zKey.vk_beta_2 = await readEvaluation("betaG2", 0);
zKey.vk_gamma_2 = curve.G2.g;
zKey.vk_delta_2 = curve.G2.g;
await writeZKey(zkeyName, zKey);
return 0;
async function readEvaluation(sectionName, idx) {
let o;
let G;
switch (sectionName) {
case "tauG1": o = sections[2][0].p; G = curve.G1; break;
case "tauG2": o = sections[3][0].p; G = curve.G2; break;
case "alphaTauG1": o = sections[4][0].p; G = curve.G1; break;
case "betaTauG1": o = sections[5][0].p; G = curve.G1; break;
case "betaG2": o = sections[6][0].p; G = curve.G2; break;
case "lTauG1": o = sections[12][0].p; G = curve.G1; break;
case "lTauG2": o = sections[13][0].p; G = curve.G2; break;
case "lAlphaTauG1": o = sections[14][0].p; G = curve.G1; break;
case "lBetaTauG1": o = sections[15][0].p; G = curve.G1; break;
}
const sG = G.F.n8*2;
ptauFd.pos = o + sG*idx*linc;
const buff = await ptauFd.read(sG);
return G.fromRprLEM(buff, 0);
}
};
function calculatePolinomials(curve, zKey, r1cs) {
zKey.ccoefs = [];
for (let m=0; m<2; m++) {
for (let c=0; c<r1cs.nConstraints; c++) {
const signals = Object.keys(r1cs.constraints[c][m]);
signals.forEach( (s) => {
zKey.ccoefs.push({
matrix: m,
constraint: c,
signal: s,
value: r1cs.constraints[c][m][s]
});
});
}
}
/**
* add and process the constraints
* input_i * 0 = 0
* to ensure soundness of input consistency
*/
for (let i = 0; i < r1cs.nPubInputs + r1cs.nOutputs + 1; ++i)
{
zKey.ccoefs.push({
matrix: 0,
constraint: r1cs.nConstraints + i,
signal: i,
value: curve.Fr.one
});
}
}

View File

@ -3,20 +3,21 @@ const utils = require("./powersoftau_utils");
const keyPair = require("./keypair");
const assert = require("assert");
const crypto = require("crypto");
const buildTaskManager = require("./taskmanager");
const binFileUtils = require("./binfileutils");
const ChaCha = require("ffjavascript").ChaCha;
function sameRatio(curve, g1s, g1sx, g2s, g2sx) {
async function sameRatio(curve, g1s, g1sx, g2s, g2sx) {
if (curve.G1.isZero(g1s)) return false;
if (curve.G1.isZero(g1sx)) return false;
if (curve.G2.isZero(g2s)) return false;
if (curve.G2.isZero(g2sx)) return false;
return curve.F12.eq(curve.pairing(g1s, g2sx), curve.pairing(g1sx, g2s));
// return curve.F12.eq(curve.pairing(g1s, g2sx), curve.pairing(g1sx, g2s));
const res = await curve.pairingEq(g1s, g2sx, curve.G1.neg(g1sx), g2s);
return res;
}
function verifyContribution(curve, cur, prev) {
async function verifyContribution(curve, cur, prev) {
let sr;
if (cur.type == 1) { // Verify the beacon.
const beaconKey = utils.keyFromBeacon(curve, prev.nextChallange, cur.beaconHash, cur.numIterationsExp);
@ -64,42 +65,50 @@ function verifyContribution(curve, cur, prev) {
cur.key.alpha.g2_sp = keyPair.getG2sp(1, prev.nextChallange, cur.key.alpha.g1_s, cur.key.alpha.g1_sx);
cur.key.beta.g2_sp = keyPair.getG2sp(2, prev.nextChallange, cur.key.beta.g1_s, cur.key.beta.g1_sx);
if (!sameRatio(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, cur.key.tau.g2_sp, cur.key.tau.g2_spx)) {
sr = await sameRatio(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, cur.key.tau.g2_sp, cur.key.tau.g2_spx);
if (sr !== true) {
console.log("INVALID key (tau) in challange #"+cur.id);
return false;
}
if (!sameRatio(curve, cur.key.alpha.g1_s, cur.key.alpha.g1_sx, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx)) {
sr = await sameRatio(curve, cur.key.alpha.g1_s, cur.key.alpha.g1_sx, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx);
if (sr !== true) {
console.log("INVALID key (alpha) in challange #"+cur.id);
return false;
}
if (!sameRatio(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, cur.key.beta.g2_sp, cur.key.beta.g2_spx)) {
sr = await sameRatio(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, cur.key.beta.g2_sp, cur.key.beta.g2_spx);
if (sr !== true) {
console.log("INVALID key (beta) in challange #"+cur.id);
return false;
}
if (!sameRatio(curve, prev.tauG1, cur.tauG1, cur.key.tau.g2_sp, cur.key.tau.g2_spx)) {
sr = await sameRatio(curve, prev.tauG1, cur.tauG1, cur.key.tau.g2_sp, cur.key.tau.g2_spx);
if (sr !== true) {
console.log("INVALID tau*G1. challange #"+cur.id+" It does not follow the previous contribution");
return false;
}
if (!sameRatio(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, prev.tauG2, cur.tauG2,)) {
sr = await sameRatio(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, prev.tauG2, cur.tauG2);
if (sr !== true) {
console.log("INVALID tau*G2. challange #"+cur.id+" It does not follow the previous contribution");
return false;
}
if (!sameRatio(curve, prev.alphaG1, cur.alphaG1, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx)) {
sr = await sameRatio(curve, prev.alphaG1, cur.alphaG1, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx);
if (sr !== true) {
console.log("INVALID alpha*G1. challange #"+cur.id+" It does not follow the previous contribution");
return false;
}
if (!sameRatio(curve, prev.betaG1, cur.betaG1, cur.key.beta.g2_sp, cur.key.beta.g2_spx)) {
sr = await sameRatio(curve, prev.betaG1, cur.betaG1, cur.key.beta.g2_sp, cur.key.beta.g2_spx);
if (sr !== true) {
console.log("INVALID beta*G1. challange #"+cur.id+" It does not follow the previous contribution");
return false;
}
if (!sameRatio(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, prev.betaG2, cur.betaG2,)) {
sr = await sameRatio(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, prev.betaG2, cur.betaG2);
if (sr !== true) {
console.log("INVALID beta*G2. challange #"+cur.id+"It does not follow the previous contribution");
return false;
}
@ -108,6 +117,7 @@ function verifyContribution(curve, cur, prev) {
}
async function verify(tauFilename, verbose) {
let sr;
await Blake2b.ready();
const {fd, sections} = await binFileUtils.readBinFile(tauFilename, "ptau", 1);
@ -141,7 +151,7 @@ async function verify(tauFilename, verbose) {
}
const curContr = contrs[contrs.length-1];
if (verbose) console.log("Validating contribution #"+contrs[contrs.length-1].id);
const res = verifyContribution(curve, curContr,prevContr, verbose);
const res = await verifyContribution(curve, curContr,prevContr, verbose);
if (!res) return false;
@ -156,7 +166,8 @@ async function verify(tauFilename, verbose) {
// Verify Section tau*G1
if (verbose) console.log("Verifying powers in tau*G1 section");
const rTau1 = await processSection(2, "G1", "tauG1", (1 << power)*2-1, [0, 1]);
if (!sameRatio(curve, rTau1.R1, rTau1.R2, curve.G2.g, curContr.tauG2)) {
sr = await sameRatio(curve, rTau1.R1, rTau1.R2, curve.G2.g, curContr.tauG2);
if (sr !== true) {
console.log("tauG1 section. Powers do not match");
return false;
}
@ -174,7 +185,8 @@ async function verify(tauFilename, verbose) {
// Verify Section tau*G2
if (verbose) console.log("Verifying powers in tau*G2 section");
const rTau2 = await processSection(3, "G2", "tauG2", 1 << power, [0, 1]);
if (!sameRatio(curve, curve.G1.g, curContr.tauG1, rTau2.R1, rTau2.R2)) {
sr = await sameRatio(curve, curve.G1.g, curContr.tauG1, rTau2.R1, rTau2.R2);
if (sr !== true) {
console.log("tauG2 section. Powers do not match");
return false;
}
@ -190,7 +202,8 @@ async function verify(tauFilename, verbose) {
// Verify Section alpha*tau*G1
if (verbose) console.log("Verifying powers in alpha*tau*G1 section");
const rAlphaTauG1 = await processSection(4, "G1", "alphatauG1", 1 << power, [0]);
if (!sameRatio(curve, rAlphaTauG1.R1, rAlphaTauG1.R2, curve.G2.g, curContr.tauG2)) {
sr = await sameRatio(curve, rAlphaTauG1.R1, rAlphaTauG1.R2, curve.G2.g, curContr.tauG2);
if (sr !== true) {
console.log("alphaTauG1 section. Powers do not match");
return false;
}
@ -202,7 +215,8 @@ async function verify(tauFilename, verbose) {
// Verify Section beta*tau*G1
if (verbose) console.log("Verifying powers in beta*tau*G1 section");
const rBetaTauG1 = await processSection(5, "G1", "betatauG1", 1 << power, [0]);
if (!sameRatio(curve, rBetaTauG1.R1, rBetaTauG1.R2, curve.G2.g, curContr.tauG2)) {
sr = await sameRatio(curve, rBetaTauG1.R1, rBetaTauG1.R2, curve.G2.g, curContr.tauG2);
if (sr !== true) {
console.log("betaTauG1 section. Powers do not match");
return false;
}
@ -238,7 +252,7 @@ async function verify(tauFilename, verbose) {
for (let i = contrs.length-2; i>=0; i--) {
const curContr = contrs[i];
const prevContr = (curContr>0) ? contrs[i-1] : initialContribution;
verifyContribution(curve, curContr, prevContr);
await verifyContribution(curve, curContr, prevContr);
printContribution(curContr, prevContr);
}
console.log("-----------------------------------------------------");

View File

@ -32,10 +32,18 @@ const Scalar = require("ffjavascript").Scalar;
const F1Field = require("ffjavascript").F1Field;
const assert = require("assert");
const binFileUtils = require("./binfileutils");
const bn128 = require("ffjavascript").bn128;
module.exports.write = async function writeZKey(fileName, zkey) {
const fd = await binFileUtils.createOverride(fileName,"zkey", 6, 1);
let curve;
if (Scalar.eq(zkey.q, bn128.q)) {
curve = bn128;
} else {
assert(false, fd.fileName +": Curve not supported");
}
const fd = await binFileUtils.createBinFile(fileName,"zkey", 1, 9);
// Write the header
///////////
@ -48,20 +56,17 @@ module.exports.write = async function writeZKey(fileName, zkey) {
await binFileUtils.startWriteSection(fd, 2);
const primeQ = zkey.q;
const Fq = new F1Field(zkey.q);
const n8q = (Math.floor( (Scalar.bitLength(primeQ) - 1) / 64) +1)*8;
const Rq = Scalar.mod(Scalar.shl(1, n8q*8), primeQ);
const primeR = zkey.r;
const Fr = new F1Field(zkey.r);
const n8r = (Math.floor( (Scalar.bitLength(primeR) - 1) / 64) +1)*8;
const Rr = Scalar.mod(Scalar.shl(1, n8r*8), primeR);
const R2r = Scalar.mod(Scalar.mul(Rr,Rr), primeR);
await fd.writeULE32(n8q);
await binFileUtils.writeBigInt(primeQ, n8q);
await binFileUtils.writeBigInt(fd, primeQ, n8q);
await fd.writeULE32(n8r);
await binFileUtils.writeBigInt(primeR, n8r);
await binFileUtils.writeBigInt(fd, primeR, n8r);
await fd.writeULE32(zkey.nVars); // Total number of bars
await fd.writeULE32(zkey.nPublic); // Total number of public vars (not including ONE)
await fd.writeULE32(zkey.domainSize); // domainSize
@ -98,24 +103,43 @@ module.exports.write = async function writeZKey(fileName, zkey) {
await binFileUtils.endWriteSection(fd);
// Write A B1 B2 C points
// Write A
///////////
await binFileUtils.startWriteSection(fd, 5);
for (let i=0; i<zkey.nVars; i++) {
await writePointG1(zkey.A[i]);
await writePointG1(zkey.B1[i]);
await writePointG2(zkey.B2[i]);
if (i<=zkey.nPublic) {
await writePointG1_zero();
} else {
await writePointG1(zkey.C[i]);
}
}
await binFileUtils.endWriteSection(fd);
// Write H points
// Write B1
///////////
await binFileUtils.startWriteSection(fd, 6);
for (let i=0; i<zkey.nVars; i++) {
await writePointG1(zkey.B1[i]);
}
await binFileUtils.endWriteSection(fd);
// Write B2
///////////
await binFileUtils.startWriteSection(fd, 7);
for (let i=0; i<zkey.nVars; i++) {
await writePointG2(zkey.B2[i]);
}
await binFileUtils.endWriteSection(fd);
// Write C
///////////
await binFileUtils.startWriteSection(fd, 8);
for (let i=zkey.nPublic+1; i<zkey.nVars; i++) {
await writePointG1(zkey.C[i]);
}
await binFileUtils.endWriteSection(fd);
// Write H points
///////////
await binFileUtils.startWriteSection(fd, 9);
for (let i=0; i<zkey.domainSize; i++) {
await writePointG1(zkey.hExps[i]);
}
@ -130,41 +154,16 @@ module.exports.write = async function writeZKey(fileName, zkey) {
await binFileUtils.writeBigInt(fd, n, n8r);
}
async function writeFq(n) {
// Convert to montgomery
n = Scalar.mod( Scalar.mul(n, Rq), primeQ);
await binFileUtils.writeBigInt(fd, n, n8q);
}
async function writePointG1(p) {
if (Fq.isZero(p[2])) {
await writeFq(0);
await writeFq(0);
} else {
await writeFq(p[0]);
await writeFq(p[1]);
}
}
async function writePointG1_zero() {
await writeFq(0);
await writeFq(0);
const buff = new Uint8Array(curve.G1.F.n8*2);
curve.G1.toRprLEM(buff, 0, p);
await fd.write(buff);
}
async function writePointG2(p) {
if (Fq.isZero(p[2][0]) && Fq.isZero(p[2][1])) {
await writeFq(Fq.e(0));
await writeFq(Fq.e(0));
await writeFq(Fq.e(0));
await writeFq(Fq.e(0));
} else {
await writeFq(p[0][0]);
await writeFq(p[0][1]);
await writeFq(p[1][0]);
await writeFq(p[1][1]);
}
const buff = new Uint8Array(curve.G2.F.n8*2);
curve.G2.toRprLEM(buff, 0, p);
await fd.write(buff);
}
};
@ -197,6 +196,12 @@ module.exports.read = async function readZKey(fileName) {
const Rri = Fr.inv(Rr);
const Rri2 = Fr.mul(Rri, Rri);
let curve;
if (Scalar.eq(zkey.q, bn128.q)) {
curve = bn128;
} else {
assert(false, fd.fileName +": Curve not supported");
}
zkey.nVars = await fd.readULE32();
zkey.nPublic = await fd.readULE32();
@ -240,32 +245,55 @@ module.exports.read = async function readZKey(fileName) {
}
await binFileUtils.endReadSection(fd);
// Read A B1 B2 C points
// Read A points
///////////
await binFileUtils.startReadUniqueSection(fd, sections, 5);
zkey.A = [];
zkey.B1 = [];
zkey.B2 = [];
zkey.C = [];
for (let i=0; i<zkey.nVars; i++) {
const A = await readG1();
const B1 = await readG1();
const B2 = await readG2();
const C = await readG1();
zkey.A.push(A);
zkey.B1.push(B1);
zkey.B2.push(B2);
zkey.C.push(C);
if (i<= zkey.nPublic) {
assert(Fr.isZero(C[2]), "C value for public is not zero");
}
zkey.A[i] = A;
}
await binFileUtils.endReadSection(fd);
// Read H points
// Read B1
///////////
await binFileUtils.startReadUniqueSection(fd, sections, 6);
zkey.B1 = [];
for (let i=0; i<zkey.nVars; i++) {
const B1 = await readG1();
zkey.B1[i] = B1;
}
await binFileUtils.endReadSection(fd);
// Read B2 points
///////////
await binFileUtils.startReadUniqueSection(fd, sections, 7);
zkey.B2 = [];
for (let i=0; i<zkey.nVars; i++) {
const B2 = await readG2();
zkey.B2[i] = B2;
}
await binFileUtils.endReadSection(fd);
// Read C points
///////////
await binFileUtils.startReadUniqueSection(fd, sections, 8);
zkey.C = [];
for (let i=zkey.nPublic+1; i<zkey.nVars; i++) {
const C = await readG1();
zkey.C[i] = C;
}
await binFileUtils.endReadSection(fd);
// Read H points
///////////
await binFileUtils.startReadUniqueSection(fd, sections, 9);
zkey.hExps = [];
for (let i=0; i<zkey.domainSize; i++) {
const H = await readG1();
@ -277,36 +305,19 @@ module.exports.read = async function readZKey(fileName) {
return zkey;
async function readFq() {
const n = await binFileUtils.readBigInt(fd, n8q);
return Fq.mul(n, Rqi);
}
async function readFr2() {
const n = await binFileUtils.readBigInt(fd, n8r);
return Fr.mul(n, Rri2);
}
async function readG1() {
const x = await readFq();
const y = await readFq();
if (Fq.isZero(x) && Fq.isZero(y)) {
return [Fq.e(0), Fq.e(1), Fq.e(0)];
} else {
return [x , y, Fq.e(1)];
}
const buff = await fd.read(curve.G1.F.n8*2);
return curve.G1.fromRprLEM(buff, 0);
}
async function readG2() {
const xa = await readFq();
const xb = await readFq();
const ya = await readFq();
const yb = await readFq();
if (Fq.isZero(xa) && Fq.isZero(xb) && Fq.isZero(ya) && Fq.isZero(yb)) {
return [[Fq.e(0),Fq.e(0)],[Fq.e(1),Fq.e(0)], [Fq.e(0),Fq.e(0)]];
} else {
return [[xa, xb],[ya, yb], [Fq.e(1),Fq.e(0)]];
}
const buff = await fd.read(curve.G2.F.n8*2);
return curve.G2.fromRprLEM(buff, 0);
}