UNPKG

snarkjs

Version:

zkSNARKs implementation in JavaScript

202 lines (161 loc) 6.52 kB
/* Copyright 2018 0KIMS association. This file is part of snarkJS. snarkJS is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. snarkJS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with snarkJS. If not, see <https://www.gnu.org/licenses/>. */ // Format of the output // Hash of the last contribution 64 Bytes // 2^N*2-1 TauG1 Points (compressed) // 2^N TauG2 Points (compressed) // 2^N AlphaTauG1 Points (compressed) // 2^N BetaTauG1 Points (compressed) // Public Key // BetaG2 (compressed) // G1*s (compressed) // G1*s*tau (compressed) // G1*t (compressed) // G1*t*alpha (compressed) // G1*u (compressed) // G1*u*beta (compressed) // G2*sp*tau (compressed) // G2*tp*alpha (compressed) // G2*up*beta (compressed) import * as fastFile from "fastfile"; import Blake2b from "blake2b-wasm"; import * as utils from "./zkey_utils.js"; import * as misc from "./misc.js"; import { applyKeyToChallengeSection } from "./mpc_applykey.js"; import { hashPubKey } from "./zkey_utils.js"; import { hashToG2 as hashToG2 } from "./keypair.js"; export default async function bellmanContribute(curve, challengeFilename, responseFileName, entropy, logger) { await Blake2b.ready(); const rng = await misc.getRandomRng(entropy); const delta = curve.Fr.fromRng(rng); const invDelta = curve.Fr.inv(delta); const sG1 = curve.G1.F.n8*2; const sG2 = curve.G2.F.n8*2; const fdFrom = await fastFile.readExisting(challengeFilename); const fdTo = await fastFile.createOverride(responseFileName); await copy(sG1); // alpha1 await copy(sG1); // beta1 await copy(sG2); // beta2 await copy(sG2); // gamma2 const oldDelta1 = await readG1(); const delta1 = curve.G1.timesFr(oldDelta1, delta); await writeG1(delta1); const oldDelta2 = await readG2(); const delta2 = curve.G2.timesFr(oldDelta2, delta); await writeG2(delta2); // IC const nIC = await fdFrom.readUBE32(); await fdTo.writeUBE32(nIC); await copy(nIC*sG1); // H const nH = await fdFrom.readUBE32(); await fdTo.writeUBE32(nH); await applyKeyToChallengeSection(fdFrom, fdTo, null, curve, "G1", nH, invDelta, curve.Fr.e(1), "UNCOMPRESSED", "H", logger); // L const nL = await fdFrom.readUBE32(); await fdTo.writeUBE32(nL); await applyKeyToChallengeSection(fdFrom, fdTo, null, curve, "G1", nL, invDelta, curve.Fr.e(1), "UNCOMPRESSED", "L", logger); // A const nA = await fdFrom.readUBE32(); await fdTo.writeUBE32(nA); await copy(nA*sG1); // B1 const nB1 = await fdFrom.readUBE32(); await fdTo.writeUBE32(nB1); await copy(nB1*sG1); // B2 const nB2 = await fdFrom.readUBE32(); await fdTo.writeUBE32(nB2); await copy(nB2*sG2); ////////// /// Read contributions ////////// const transcriptHasher = Blake2b(64); const mpcParams = {}; // csHash mpcParams.csHash = await fdFrom.read(64); transcriptHasher.update(mpcParams.csHash); const nContributions = await fdFrom.readUBE32(); mpcParams.contributions = []; for (let i=0; i<nContributions; i++) { const c = { delta:{} }; c.deltaAfter = await readG1(); c.delta.g1_s = await readG1(); c.delta.g1_sx = await readG1(); c.delta.g2_spx = await readG2(); c.transcript = await fdFrom.read(64); mpcParams.contributions.push(c); hashPubKey(transcriptHasher, curve, c); } const curContribution = {}; curContribution.delta = {}; curContribution.delta.prvKey = delta; curContribution.delta.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); curContribution.delta.g1_sx = curve.G1.toAffine(curve.G1.timesFr(curContribution.delta.g1_s, delta)); utils.hashG1(transcriptHasher, curve, curContribution.delta.g1_s); utils.hashG1(transcriptHasher, curve, curContribution.delta.g1_sx); curContribution.transcript = transcriptHasher.digest(); curContribution.delta.g2_sp = hashToG2(curve, curContribution.transcript); curContribution.delta.g2_spx = curve.G2.toAffine(curve.G2.timesFr(curContribution.delta.g2_sp, delta)); curContribution.deltaAfter = delta1; curContribution.type = 0; mpcParams.contributions.push(curContribution); ////////// /// Write Contribution ////////// await fdTo.write(mpcParams.csHash); await fdTo.writeUBE32(mpcParams.contributions.length); for (let i=0; i<mpcParams.contributions.length; i++) { const c = mpcParams.contributions[i]; await writeG1(c.deltaAfter); await writeG1(c.delta.g1_s); await writeG1(c.delta.g1_sx); await writeG2(c.delta.g2_spx); await fdTo.write(c.transcript); } const contributionHasher = Blake2b(64); hashPubKey(contributionHasher, curve, curContribution); const contributionHash = contributionHasher.digest(); if (logger) logger.info(misc.formatHash(contributionHash, "Contribution Hash: ")); await fdTo.close(); await fdFrom.close(); return contributionHash; async function copy(nBytes) { const CHUNK_SIZE = fdFrom.pageSize*2; for (let i=0; i<nBytes; i+= CHUNK_SIZE) { const n = Math.min(nBytes -i, CHUNK_SIZE); const buff = await fdFrom.read(n); await fdTo.write(buff); } } async function readG1() { const buff = await fdFrom.read(curve.G1.F.n8*2); return curve.G1.fromRprUncompressed(buff, 0); } async function readG2() { const buff = await fdFrom.read(curve.G2.F.n8*2); return curve.G2.fromRprUncompressed(buff, 0); } async function writeG1(P) { const buff = new Uint8Array(sG1); curve.G1.toRprUncompressed(buff, 0, P); await fdTo.write(buff); } async function writeG2(P) { const buff = new Uint8Array(sG2); curve.G2.toRprUncompressed(buff, 0, P); await fdTo.write(buff); } }