From 6b08298526c0eeef2a614f2b99ccb9b8fbc72908 Mon Sep 17 00:00:00 2001 From: Jordi Baylina Date: Tue, 30 Jun 2020 15:45:21 +0200 Subject: [PATCH] bls12-381 working --- cli.js | 118 ++++++++++++++++------------ src/curves.js | 37 +++++++-- src/keypair.js | 40 +++++----- src/mpc_applykey.js | 4 +- src/powersoftau_beacon.js | 2 +- src/powersoftau_contribute.js | 2 +- src/powersoftau_new.js | 6 +- src/powersoftau_utils.js | 27 +++---- src/powersoftau_verify.js | 12 +-- src/prover_groth16.js | 34 ++++---- src/prover_kimleeoh.js | 46 +++++------ src/prover_original.js | 54 ++++++------- src/r1cs.js | 3 + src/r1cs_export_json.js | 14 ++++ src/r1cs_info.js | 25 ++++++ src/{printr1cs.js => r1cs_print.js} | 7 +- src/setup_groth16.js | 30 +++---- src/setup_kimleeoh.js | 38 ++++----- src/setup_original.js | 68 ++++++++-------- src/verifier_groth16.js | 6 +- src/verifier_kimleeoh.js | 9 ++- src/verifier_original.js | 6 +- src/zkey.js | 2 +- src/zkey_beacon.js | 12 +-- src/zkey_challangecontribute.js | 12 +-- src/zkey_contribute.js | 13 +-- src/zkey_export_verificationkey.js | 43 ++++++++++ src/zkey_new.js | 16 ++-- src/zkey_utils.js | 2 +- src/zkey_verify.js | 6 +- src/zksnark_groth16_prover.js | 41 +++++----- src/zksnark_groth16_verifier.js | 43 +++++++--- 32 files changed, 458 insertions(+), 320 deletions(-) create mode 100644 src/r1cs.js create mode 100644 src/r1cs_export_json.js create mode 100644 src/r1cs_info.js rename src/{printr1cs.js => r1cs_print.js} (84%) create mode 100644 src/zkey_export_verificationkey.js diff --git a/cli.js b/cli.js index 226c5d8..9244259 100755 --- a/cli.js +++ b/cli.js @@ -33,13 +33,12 @@ const WitnessCalculatorBuilder = require("circom_runtime").WitnessCalculatorBuil const wtnsFile = require("./src/wtnsfile"); const loadSyms = require("./src/loadsyms"); -const printR1cs = require("./src/printr1cs"); +const r1cs = require("./src/r1cs"); const clProcessor = require("./src/clprocessor"); const powersOfTaw = require("./src/powersoftau"); -const bn128 = require("ffjavascript").bn128; const solidityGenerator = require("./src/soliditygenerator.js"); const Scalar = require("ffjavascript").Scalar; @@ -64,18 +63,32 @@ const commands = [ action: r1csPrint }, { - cmd: "witness calculate [circuit.wasm] [input.json] [witness.wtns]", - description: "Caclculate specific witness of a circuit given an input", - alias: ["wc", "calculatewitness -ws|wasm:circuit.wasm -i|input:input.json -wt|witness:witness.wtns"], - action: witnessCalculate + cmd: "r1cs export json [circuit.r1cs] [circuit.json]", + description: "Export r1cs to JSON file", + alias: ["rej"], + action: r1csExportJSON }, { - cmd: "witness debug [circuit.wasm] [input.json] [witness.wtns] [circuit.sym]", + cmd: "wtns calculate [circuit.wasm] [input.json] [witness.wtns]", + description: "Caclculate specific witness of a circuit given an input", + alias: ["wc", "calculatewitness -ws|wasm:circuit.wasm -i|input:input.json -wt|witness:witness.wtns"], + action: wtnsCalculate + }, + { + cmd: "wtns debug [circuit.wasm] [input.json] [witness.wtns] [circuit.sym]", description: "Calculate the witness with debug info.", longDescription: "Calculate the witness with debug info. \nOptions:\n-g or --g : Log signal gets\n-s or --s : Log signal sets\n-t or --trigger : Log triggers ", options: "-get|g -set|s -trigger|t", alias: ["wd"], - action: witnessDebug + action: wtnsDebug + }, + { + cmd: "wtns export json [witness.wtns] [witnes.json]", + description: "Calculate the witness with debug info.", + longDescription: "Calculate the witness with debug info. \nOptions:\n-g or --g : Log signal gets\n-s or --s : Log signal sets\n-t or --trigger : Log triggers ", + options: "-get|g -set|s -trigger|t", + alias: ["wej"], + action: wtnsExportJson }, { cmd: "zksnark setup [circuit.r1cs] [circuit.zkey] [verification_key.json]", @@ -110,7 +123,7 @@ const commands = [ action: solidityGenCall }, { - cmd: "powersoftau new [powersoftau_0000.ptau]", + cmd: "powersoftau new [powersoftau_0000.ptau]", description: "Starts a powers of tau ceremony", alias: ["ptn"], options: "-verbose|v", @@ -314,13 +327,8 @@ function changeExt(fileName, newExt) { async function r1csInfo(params, options) { const r1csName = params[0] || "circuit.r1cs"; - const cir = await loadR1cs(r1csName); + await r1cs.info(r1csName); - console.log(`# Wires: ${cir.nVars}`); - console.log(`# Constraints: ${cir.nConstraints}`); - console.log(`# Private Inputs: ${cir.nPrvInputs}`); - console.log(`# Public Inputs: ${cir.nPubInputs}`); - console.log(`# Outputs: ${cir.nOutputs}`); return 0; } @@ -328,18 +336,29 @@ async function r1csInfo(params, options) { // r1cs print [circuit.r1cs] [circuit.sym] async function r1csPrint(params, options) { const r1csName = params[0] || "circuit.r1cs"; - const symName = params[2] || changeExt(r1csName, "sym"); + const symName = params[1] || changeExt(r1csName, "sym"); const cir = await loadR1cs(r1csName, true, true); const sym = await loadSyms(symName); - printR1cs(cir, sym); + await r1cs.print(cir, sym); return 0; } -// witness calculate -async function witnessCalculate(params, options) { + +// r1cs export json [circuit.r1cs] [circuit.json] +async function r1csExportJSON(params, options) { + const r1csName = params[0] || "circuit.r1cs"; + const jsonName = params[1] || changeExt(r1csName, "json"); + + await r1cs.exportJson(r1csName, jsonName); + + return 0; +} + +// wtns calculate +async function wtnsCalculate(params, options) { const wasmName = params[0] || "circuit.wasm"; const inputName = params[1] || "input.json"; const witnessName = params[2] || "witness.wtns"; @@ -361,9 +380,9 @@ async function witnessCalculate(params, options) { } -// witness debug +// wtns debug // -get|g -set|s -trigger|t -async function witnessDebug(params, options) { +async function wtnsDebug(params, options) { const wasmName = params[0] || "circuit.wasm"; const inputName = params[1] || "input.json"; const witnessName = params[2] || "witness.wtns"; @@ -410,6 +429,21 @@ async function witnessDebug(params, options) { } +// wtns export json [witness.wtns] [witness.json] +// -get|g -set|s -trigger|t +async function wtnsExportJson(params, options) { + const wtnsName = params[0] || "witness.wtns"; + const jsonName = params[1] || "witness.json"; + + const w = await wtnsFile.read(wtnsName); + + await fs.promises.writeFile(jsonName, JSON.stringify(stringifyBigInts(w), null, 1)); + + return 0; +} + + + // zksnark setup [circuit.r1cs] [circuit.zkey] [verification_key.json] async function zksnarkSetup(params, options) { @@ -511,31 +545,7 @@ async function zkeyExportVKey(params) { const zkeyName = params[0] || "circuit.zkey"; const verificationKeyName = params[2] || "verification_key.json"; - const zKey = await zkey.utils.read(zkeyName); - - let curve; - if (Scalar.eq(zKey.q, bn128.q)) { - curve = bn128; - } else { - assert(false, " Curve not supported"); - } - const vKey = { - protocol: zKey.protocol, - nPublic: zKey.nPublic, - IC: zKey.IC, - - - vk_alpha_1: zKey.vk_alpha_1, - - vk_beta_2: zKey.vk_beta_2, - vk_gamma_2: zKey.vk_gamma_2, - vk_delta_2: zKey.vk_delta_2, - - vk_alphabeta_12: await curve.pairing( zKey.vk_alpha_1 , zKey.vk_beta_2 ) - }; - - await fs.promises.writeFile(verificationKeyName, JSON.stringify(stringifyBigInts(vKey), null, 1), "utf-8"); - + return await zkey.exportVerificationKey(zkeyName, verificationKeyName); } // zkey export json [circuit.zkey] [circuit.zkey.json]", @@ -634,22 +644,28 @@ async function solidityGenCall(params, options) { return 0; } +// powersoftau new [powersoftau_0000.ptau]", async function powersOfTawNew(params, options) { + let curveName; let power; let ptauName; - power = parseInt(params[0]); + curveName = params[0]; + + power = parseInt(params[1]); if ((power<1) || (power>28)) { throw new Error("Power must be between 1 and 28"); } - if (params.length < 2) { + if (params.length < 3) { ptauName = "powersOfTaw" + power + "_0000.ptau"; } else { - ptauName = params[1]; + ptauName = params[2]; } - return await powersOfTaw.newAccumulator(bn128, power, ptauName, options.verbose); + const curve = await curves.getCurveFromName(curveName); + + return await powersOfTaw.newAccumulator(curve, power, ptauName, options.verbose); } async function powersOfTawExportChallange(params, options) { @@ -672,7 +688,7 @@ async function powersOfTawChallangeContribute(params, options) { let challangeName; let responseName; - const curve = curves.getCurveFromName(params[0]); + const curve = await curves.getCurveFromName(params[0]); challangeName = params[1]; diff --git a/src/curves.js b/src/curves.js index d03c936..68ddff5 100644 --- a/src/curves.js +++ b/src/curves.js @@ -1,21 +1,44 @@ const Scalar = require("ffjavascript").Scalar; -const bn128 = require("ffjavascript").bn128; +const buildBn128 = require("ffjavascript").buildBn128; +const buildBls12381 = require("ffjavascript").buildBls12381; -module.exports.getCurveFromQ = function getCurveFromQ(q) { +const bls12381r = Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); +const bn128r = Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); + +const bls12381q = Scalar.e("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16); +const bn128q = Scalar.e("21888242871839275222246405745257275088696311157297823662689037894645226208583"); + +module.exports.getCurveFromR = async function getCurveFromR(r) { let curve; - if (Scalar.eq(q, bn128.q)) { - curve = bn128; + if (Scalar.eq(r, bn128r)) { + curve = await buildBn128(); + } else if (Scalar.eq(r, bls12381r)) { + curve = await buildBls12381(); } else { - throw new Error(`Curve not supported: ${q.toString()}`); + throw new Error(`Curve not supported: ${Scalar.toString(r)}`); } return curve; }; -module.exports.getCurveFromName = function getCurveFromName(name) { +module.exports.getCurveFromQ = async function getCurveFromQ(q) { + let curve; + if (Scalar.eq(q, bn128q)) { + curve = await buildBn128(); + } else if (Scalar.eq(q, bls12381q)) { + curve = await buildBls12381(); + } else { + throw new Error(`Curve not supported: ${Scalar.toString(q)}`); + } + return curve; +}; + +module.exports.getCurveFromName = async function getCurveFromName(name) { let curve; const normName = normalizeName(name); if (["BN128", "BN254", "ALTBN128"].indexOf(normName) >= 0) { - curve = bn128; + curve = await buildBn128(); + } else if (["BLS12381"].indexOf(normName) >= 0) { + curve = await buildBls12381(); } else { throw new Error(`Curve not supported: ${name}`); } diff --git a/src/keypair.js b/src/keypair.js index d33b5eb..1f8c8fb 100644 --- a/src/keypair.js +++ b/src/keypair.js @@ -1,12 +1,9 @@ -const bn128 = require("ffjavascript").bn128; -const utils = require("ffjavascript").utils; - const blake2b = require("blake2b-wasm"); const ChaCha = require("ffjavascript").ChaCha; -function hashToG2(hash) { +function hashToG2(curve, hash) { const hashV = new DataView(hash.buffer, hash.byteOffset, hash.byteLength); const seed = []; for (let i=0; i<8; i++) { @@ -15,30 +12,31 @@ function hashToG2(hash) { const rng = new ChaCha(seed); - const g2_sp = bn128.G2.fromRng(rng); + const g2_sp = curve.G2.fromRng(rng); return g2_sp; } -function getG2sp(persinalization, challange, g1s, g1sx) { +function getG2sp(curve, persinalization, challange, g1s, g1sx) { const h = blake2b(64); - h.update(Buffer.from([persinalization])); + const b1 = new Uint8Array([persinalization]); + h.update(b1); h.update(challange); - h.update( utils.beInt2Buff(g1s[0],32)); - h.update( utils.beInt2Buff(g1s[1],32)); - h.update( utils.beInt2Buff(g1sx[0],32)); - h.update( utils.beInt2Buff(g1sx[1],32)); - const hash = Buffer.from(h.digest()); + const b3 = curve.G1.toUncompressed(g1s); + h.update( b3); + const b4 = curve.G1.toUncompressed(g1sx); + h.update( b4); + const hash =h.digest(); - return hashToG2(hash); + return hashToG2(curve, hash); } function calculatePubKey(k, curve, personalization, challangeHash, rng ) { - k.g1_s = curve.G1.affine(curve.G1.fromRng(rng)); - k.g1_sx = curve.G1.affine(curve.G1.mulScalar(k.g1_s, k.prvKey)); - k.g2_sp = curve.G2.affine(getG2sp(personalization, challangeHash, k.g1_s, k.g1_sx)); - k.g2_spx = curve.G2.affine(curve.G2.mulScalar(k.g2_sp, k.prvKey)); + k.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); + k.g1_sx = curve.G1.toAffine(curve.G1.timesFr(k.g1_s, k.prvKey)); + k.g2_sp = curve.G2.toAffine(getG2sp(curve, personalization, challangeHash, k.g1_s, k.g1_sx)); + k.g2_spx = curve.G2.toAffine(curve.G2.timesFr(k.g2_sp, k.prvKey)); return k; } @@ -60,10 +58,10 @@ function createPTauKey(curve, challangeHash, rng) { function createDeltaKey(curve, transcript, rng) { const delta = {}; delta.prvKey = curve.Fr.fromRng(rng); - delta.g1_s = curve.G1.affine(curve.G1.fromRng(rng)); - delta.g1_sx = curve.G1.affine(curve.G1.mulScalar(delta.g1_s, delta.prvKey)); - delta.g2_sp = hashToG2(transcript); - delta.g2_spx = curve.G2.affine(curve.G2.mulScalar(delta.g2_sp, delta.prvKey)); + delta.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); + delta.g1_sx = curve.G1.toAffine(curve.G1.timesScalar(delta.g1_s, delta.prvKey)); + delta.g2_sp = hashToG2(curve, transcript); + delta.g2_spx = curve.G2.toAffine(curve.G2.timesScalar(delta.g2_sp, delta.prvKey)); return delta; } diff --git a/src/mpc_applykey.js b/src/mpc_applykey.js index ef3f72a..2be6094 100644 --- a/src/mpc_applykey.js +++ b/src/mpc_applykey.js @@ -53,9 +53,9 @@ async function applyKeyToChallangeSection(fdOld, fdNew, responseHasher, curve, g buffOut = await G.batchLEMtoU(buffOutLEM); } - if (responseHasher) responseHasher.update(buffOutC); + if (responseHasher) responseHasher.update(buffOut); await fdNew.write(buffOut); - t = curve.Fr.mul(t, curve.Fr.pow(inc, n)); + t = curve.Fr.mul(t, curve.Fr.exp(inc, n)); } } diff --git a/src/powersoftau_beacon.js b/src/powersoftau_beacon.js index 4eaae80..5e371c3 100644 --- a/src/powersoftau_beacon.js +++ b/src/powersoftau_beacon.js @@ -141,7 +141,7 @@ async function beacon(oldPtauFilename, newPTauFilename, name, numIterationsExp, if (i==0) // Return the 2 first points. for (let j=0; j" + h[i].toString()); - proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( vk_proof.hExps[i], h[i])); + proof.pi_c = G1.add( proof.pi_c, G1.timesScalar( vk_proof.hExps[i], h[i])); if ((verbose)&&(i%1000 == 1)) console.log("H: ", i); } - // proof.pi_c = G1.affine(proof.pi_c); + // proof.pi_c = G1.toAffine(proof.pi_c); // console.log("pi_candh", proof.pi_c); - proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( proof.pi_a, s )); - proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( pib1, r )); - proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( vk_proof.vk_delta_1, PolF.F.neg(PolF.F.mul(r,s) ))); + proof.pi_c = G1.add( proof.pi_c, G1.timesScalar( proof.pi_a, s )); + proof.pi_c = G1.add( proof.pi_c, G1.timesScalar( pib1, r )); + proof.pi_c = G1.add( proof.pi_c, G1.timesScalar( vk_proof.vk_delta_1, PolF.F.neg(PolF.F.mul(r,s) ))); const publicSignals = witness.slice(1, vk_proof.nPublic+1); - proof.pi_a = G1.affine(proof.pi_a); - proof.pi_b = G2.affine(proof.pi_b); - proof.pi_c = G1.affine(proof.pi_c); + proof.pi_a = G1.toAffine(proof.pi_a); + proof.pi_b = G2.toAffine(proof.pi_b); + proof.pi_c = G1.toAffine(proof.pi_c); proof.protocol = "groth"; diff --git a/src/prover_kimleeoh.js b/src/prover_kimleeoh.js index bbb29a7..98201f5 100644 --- a/src/prover_kimleeoh.js +++ b/src/prover_kimleeoh.js @@ -25,11 +25,11 @@ const ZqField = require("ffjavascript").ZqField; const createKeccakHash = require("keccak"); const utils = require("ffjavascript").utils; - +/* const PolF = new PolField(new ZqField(bn128.r)); const G1 = bn128.G1; const G2 = bn128.G2; - +*/ module.exports = function genProof(vk_proof, witness) { const proof = {}; @@ -58,35 +58,35 @@ module.exports = function genProof(vk_proof, witness) { for (let s= 0; s< vk_proof.nVars; s++) { // pi_a = pi_a + A[s] * witness[s]; - proof.pi_a = G1.add( proof.pi_a, G1.mulScalar( vk_proof.A[s], witness[s])); + proof.pi_a = G1.add( proof.pi_a, G1.timesScalar( vk_proof.A[s], witness[s])); // pi_b = pi_b + B[s] * witness[s]; - proof.pi_b = G2.add( proof.pi_b, G2.mulScalar( vk_proof.B2[s], witness[s])); + proof.pi_b = G2.add( proof.pi_b, G2.timesScalar( vk_proof.B2[s], witness[s])); - piadelta = G1.add( piadelta, G1.mulScalar( vk_proof.Adelta[s], witness[s])); - pib1 = G1.add( pib1, G1.mulScalar( vk_proof.B1[s], witness[s])); + piadelta = G1.add( piadelta, G1.timesScalar( vk_proof.Adelta[s], witness[s])); + pib1 = G1.add( pib1, G1.timesScalar( vk_proof.B1[s], witness[s])); } for (let s= vk_proof.nPublic+1; s< vk_proof.nVars; s++) { // pi_a = pi_a + A[s] * witness[s]; - proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( vk_proof.C[s], witness[s])); + proof.pi_c = G1.add( proof.pi_c, G1.timesScalar( vk_proof.C[s], witness[s])); } proof.pi_a = G1.add( proof.pi_a, vk_proof.vk_alpha_1 ); - proof.pi_a = G1.add( proof.pi_a, G1.mulScalar( G1.g, r )); + proof.pi_a = G1.add( proof.pi_a, G1.timesScalar( G1.g, r )); piadelta = G1.add( piadelta, vk_proof.vk_alphadelta_1); - piadelta = G1.add( piadelta, G1.mulScalar( vk_proof.vk_delta_1, r )); + piadelta = G1.add( piadelta, G1.timesScalar( vk_proof.vk_delta_1, r )); proof.pi_b = G2.add( proof.pi_b, vk_proof.vk_beta_2 ); - proof.pi_b = G2.add( proof.pi_b, G2.mulScalar( G2.g, s )); + proof.pi_b = G2.add( proof.pi_b, G2.timesScalar( G2.g, s )); pib1 = G1.add( pib1, vk_proof.vk_beta_1 ); - pib1 = G1.add( pib1, G1.mulScalar( G1.g, s )); + pib1 = G1.add( pib1, G1.timesScalar( G1.g, s )); - proof.pi_a = G1.affine(proof.pi_a); - proof.pi_b = G2.affine(proof.pi_b); + proof.pi_a = G1.toAffine(proof.pi_a); + proof.pi_b = G2.toAffine(proof.pi_b); const buff = Buffer.concat([ utils.beInt2Buff(proof.pi_a[0],32), @@ -111,28 +111,28 @@ module.exports = function genProof(vk_proof, witness) { const h = calculateH(vk_proof, witness); - // proof.pi_c = G1.affine(proof.pi_c); + // proof.pi_c = G1.toAffine(proof.pi_c); // console.log("pi_onlyc", proof.pi_c); for (let i = 0; i < h.length; i++) { // console.log(i + "->" + h[i].toString()); - proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( vk_proof.hExps[i], h[i])); + proof.pi_c = G1.add( proof.pi_c, G1.timesScalar( vk_proof.hExps[i], h[i])); } - // proof.pi_c = G1.affine(proof.pi_c); + // proof.pi_c = G1.toAffine(proof.pi_c); // console.log("pi_candh", proof.pi_c); - proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( proof.pi_a, s )); - proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( pib1, r )); - proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( G1.g, PolF.F.neg(PolF.F.mul(r,s) ))); + proof.pi_c = G1.add( proof.pi_c, G1.timesScalar( proof.pi_a, s )); + proof.pi_c = G1.add( proof.pi_c, G1.timesScalar( pib1, r )); + proof.pi_c = G1.add( proof.pi_c, G1.timesScalar( G1.g, PolF.F.neg(PolF.F.mul(r,s) ))); - proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( piadelta, h2 )); - proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( pib1, h1 )); - proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( vk_proof.vk_delta_1, PolF.F.mul(h1,h2))); + proof.pi_c = G1.add( proof.pi_c, G1.timesScalar( piadelta, h2 )); + proof.pi_c = G1.add( proof.pi_c, G1.timesScalar( pib1, h1 )); + proof.pi_c = G1.add( proof.pi_c, G1.timesScalar( vk_proof.vk_delta_1, PolF.F.mul(h1,h2))); const publicSignals = witness.slice(1, vk_proof.nPublic+1); - proof.pi_c = G1.affine(proof.pi_c); + proof.pi_c = G1.toAffine(proof.pi_c); proof.protocol = "kimleeoh"; diff --git a/src/prover_original.js b/src/prover_original.js index b1d28f4..aa584f7 100644 --- a/src/prover_original.js +++ b/src/prover_original.js @@ -20,11 +20,11 @@ const bn128 = require("ffjavascript").bn128; const PolField = require("ffjavascript").PolField; const ZqField = require("ffjavascript").ZqField; - +/* const PolF = new PolField(new ZqField(bn128.r)); const G1 = bn128.G1; const G2 = bn128.G2; - +*/ module.exports = function genProof(vk_proof, witness) { const proof = {}; @@ -48,41 +48,41 @@ module.exports = function genProof(vk_proof, witness) { for (let s= vk_proof.nPublic+1; s< vk_proof.nVars; s++) { // pi_a = pi_a + A[s] * witness[s]; - proof.pi_a = G1.add( proof.pi_a, G1.mulScalar( vk_proof.A[s], witness[s])); + proof.pi_a = G1.add( proof.pi_a, G1.timesScalar( vk_proof.A[s], witness[s])); // pi_ap = pi_ap + Ap[s] * witness[s]; - proof.pi_ap = G1.add( proof.pi_ap, G1.mulScalar( vk_proof.Ap[s], witness[s])); + proof.pi_ap = G1.add( proof.pi_ap, G1.timesScalar( vk_proof.Ap[s], witness[s])); } for (let s= 0; s< vk_proof.nVars; s++) { // pi_a = pi_a + A[s] * witness[s]; - proof.pi_b = G2.add( proof.pi_b, G2.mulScalar( vk_proof.B[s], witness[s])); + proof.pi_b = G2.add( proof.pi_b, G2.timesScalar( vk_proof.B[s], witness[s])); // pi_ap = pi_ap + Ap[s] * witness[s]; - proof.pi_bp = G1.add( proof.pi_bp, G1.mulScalar( vk_proof.Bp[s], witness[s])); + proof.pi_bp = G1.add( proof.pi_bp, G1.timesScalar( vk_proof.Bp[s], witness[s])); // pi_a = pi_a + A[s] * witness[s]; - proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( vk_proof.C[s], witness[s])); + proof.pi_c = G1.add( proof.pi_c, G1.timesScalar( vk_proof.C[s], witness[s])); // pi_ap = pi_ap + Ap[s] * witness[s]; - proof.pi_cp = G1.add( proof.pi_cp, G1.mulScalar( vk_proof.Cp[s], witness[s])); + proof.pi_cp = G1.add( proof.pi_cp, G1.timesScalar( vk_proof.Cp[s], witness[s])); // pi_ap = pi_ap + Ap[s] * witness[s]; - proof.pi_kp = G1.add( proof.pi_kp, G1.mulScalar( vk_proof.Kp[s], witness[s])); + proof.pi_kp = G1.add( proof.pi_kp, G1.timesScalar( vk_proof.Kp[s], witness[s])); } - proof.pi_a = G1.add( proof.pi_a, G1.mulScalar( vk_proof.A[vk_proof.nVars], d1)); - proof.pi_ap = G1.add( proof.pi_ap, G1.mulScalar( vk_proof.Ap[vk_proof.nVars], d1)); + proof.pi_a = G1.add( proof.pi_a, G1.timesScalar( vk_proof.A[vk_proof.nVars], d1)); + proof.pi_ap = G1.add( proof.pi_ap, G1.timesScalar( vk_proof.Ap[vk_proof.nVars], d1)); - proof.pi_b = G2.add( proof.pi_b, G2.mulScalar( vk_proof.B[vk_proof.nVars], d2)); - proof.pi_bp = G1.add( proof.pi_bp, G1.mulScalar( vk_proof.Bp[vk_proof.nVars], d2)); + proof.pi_b = G2.add( proof.pi_b, G2.timesScalar( vk_proof.B[vk_proof.nVars], d2)); + proof.pi_bp = G1.add( proof.pi_bp, G1.timesScalar( vk_proof.Bp[vk_proof.nVars], d2)); - proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( vk_proof.C[vk_proof.nVars], d3)); - proof.pi_cp = G1.add( proof.pi_cp, G1.mulScalar( vk_proof.Cp[vk_proof.nVars], d3)); + proof.pi_c = G1.add( proof.pi_c, G1.timesScalar( vk_proof.C[vk_proof.nVars], d3)); + proof.pi_cp = G1.add( proof.pi_cp, G1.timesScalar( vk_proof.Cp[vk_proof.nVars], d3)); - proof.pi_kp = G1.add( proof.pi_kp, G1.mulScalar( vk_proof.Kp[vk_proof.nVars ], d1)); - proof.pi_kp = G1.add( proof.pi_kp, G1.mulScalar( vk_proof.Kp[vk_proof.nVars+1], d2)); - proof.pi_kp = G1.add( proof.pi_kp, G1.mulScalar( vk_proof.Kp[vk_proof.nVars+2], d3)); + proof.pi_kp = G1.add( proof.pi_kp, G1.timesScalar( vk_proof.Kp[vk_proof.nVars ], d1)); + proof.pi_kp = G1.add( proof.pi_kp, G1.timesScalar( vk_proof.Kp[vk_proof.nVars+1], d2)); + proof.pi_kp = G1.add( proof.pi_kp, G1.timesScalar( vk_proof.Kp[vk_proof.nVars+2], d3)); /* let polA = []; @@ -120,17 +120,17 @@ module.exports = function genProof(vk_proof, witness) { // console.log(h.length + "/" + vk_proof.hExps.length); for (let i = 0; i < h.length; i++) { - proof.pi_h = G1.add( proof.pi_h, G1.mulScalar( vk_proof.hExps[i], h[i])); + proof.pi_h = G1.add( proof.pi_h, G1.timesScalar( vk_proof.hExps[i], h[i])); } - proof.pi_a = G1.affine(proof.pi_a); - proof.pi_b = G2.affine(proof.pi_b); - proof.pi_c = G1.affine(proof.pi_c); - proof.pi_ap = G1.affine(proof.pi_ap); - proof.pi_bp = G1.affine(proof.pi_bp); - proof.pi_cp = G1.affine(proof.pi_cp); - proof.pi_kp = G1.affine(proof.pi_kp); - proof.pi_h = G1.affine(proof.pi_h); + proof.pi_a = G1.toAffine(proof.pi_a); + proof.pi_b = G2.toAffine(proof.pi_b); + proof.pi_c = G1.toAffine(proof.pi_c); + proof.pi_ap = G1.toAffine(proof.pi_ap); + proof.pi_bp = G1.toAffine(proof.pi_bp); + proof.pi_cp = G1.toAffine(proof.pi_cp); + proof.pi_kp = G1.toAffine(proof.pi_kp); + proof.pi_h = G1.toAffine(proof.pi_h); // proof.h=h; diff --git a/src/r1cs.js b/src/r1cs.js new file mode 100644 index 0000000..22a3ca7 --- /dev/null +++ b/src/r1cs.js @@ -0,0 +1,3 @@ +module.exports.print = require("./r1cs_print"); +module.exports.info = require("./r1cs_info"); +module.exports.exportJson = require("./r1cs_export_json"); diff --git a/src/r1cs_export_json.js b/src/r1cs_export_json.js new file mode 100644 index 0000000..7c7f1d5 --- /dev/null +++ b/src/r1cs_export_json.js @@ -0,0 +1,14 @@ +const {stringifyBigInts} = require("ffjavascript").utils; +const fs = require("fs"); +const readZKey = require("./zkey_utils").read; +const loadR1cs = require("r1csfile").load; + +module.exports = r1csExportJson; + +async function r1csExportJson(r1csFileName, jsonFileName, verbose) { + + const cir = await loadR1cs(r1csFileName, true, true); + + const S = JSON.stringify(stringifyBigInts(cir), null, 1); + await fs.promises.writeFile(jsonFileName, S); +} diff --git a/src/r1cs_info.js b/src/r1cs_info.js new file mode 100644 index 0000000..475eb2b --- /dev/null +++ b/src/r1cs_info.js @@ -0,0 +1,25 @@ +const Scalar = require("ffjavascript").Scalar; +const loadR1cs = require("r1csfile").load; +module.exports = r1csInfo; + + +const bls12381r = Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); +const bn128r = Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617", 16); + +async function r1csInfo(r1csName) { + const cir = await loadR1cs(r1csName); + + if (Scalar.eq(cir.prime, bn128r)) { + console.log("# Curve: bn-128"); + } else if (Scalar.eq(cir.prime, bls12381r)) { + console.log("# Curve: bls12-381"); + } else { + console.log(`# Unknown Curve. Prime: ${Scalar.toString(cir.r)}`); + } + console.log(`# Wires: ${cir.nVars}`); + console.log(`# Constraints: ${cir.nConstraints}`); + console.log(`# Private Inputs: ${cir.nPrvInputs}`); + console.log(`# Public Inputs: ${cir.nPubInputs}`); + console.log(`# Outputs: ${cir.nOutputs}`); + +} diff --git a/src/printr1cs.js b/src/r1cs_print.js similarity index 84% rename from src/printr1cs.js rename to src/r1cs_print.js index 72087ec..b813eb0 100644 --- a/src/printr1cs.js +++ b/src/r1cs_print.js @@ -1,12 +1,13 @@ -module.exports = function printR1cs(r1cs, syms) { +module.exports = function r1csPrint(r1cs, syms) { for (let i=0; i { let S = ""; - for (let k in lc) { + const keys = Object.keys(lc); + keys.forEach( (k) => { let name = syms.varIdx2Name[k]; if (name == "one") name = ""; @@ -16,7 +17,7 @@ module.exports = function printR1cs(r1cs, syms) { if ((S!="")&&(vs[0]!="-")) vs = "+"+vs; if (S!="") vs = " "+vs; S= S + vs + name; - } + }); return S; }; const S = `[ ${lc2str(c[0])} ] * [ ${lc2str(c[1])} ] - [ ${lc2str(c[2])} ] = 0`; diff --git a/src/setup_groth16.js b/src/setup_groth16.js index 7c39d3c..0b12d10 100644 --- a/src/setup_groth16.js +++ b/src/setup_groth16.js @@ -22,12 +22,12 @@ const bn128 = require("ffjavascript").bn128; const PolField = require("ffjavascript").PolField; const ZqField = require("ffjavascript").ZqField; - +/* const G1 = bn128.G1; const G2 = bn128.G2; const PolF = new PolField(new ZqField(bn128.r)); const F = new ZqField(bn128.r); - +*/ module.exports = function setup(circuit, verbose) { const setup = { vk_proof : { @@ -165,26 +165,26 @@ function calculateEncriptedValuesAtT(setup, circuit, verbose) { let invDelta = F.inv(setup.toxic.kdelta); let invGamma = F.inv(setup.toxic.kgamma); - setup.vk_proof.vk_alpha_1 = G1.affine(G1.mulScalar( G1.g, setup.toxic.kalpha)); - setup.vk_proof.vk_beta_1 = G1.affine(G1.mulScalar( G1.g, setup.toxic.kbeta)); - setup.vk_proof.vk_delta_1 = G1.affine(G1.mulScalar( G1.g, setup.toxic.kdelta)); + setup.vk_proof.vk_alpha_1 = G1.toAffine(G1.timesScalar( G1.g, setup.toxic.kalpha)); + setup.vk_proof.vk_beta_1 = G1.toAffine(G1.timesScalar( G1.g, setup.toxic.kbeta)); + setup.vk_proof.vk_delta_1 = G1.toAffine(G1.timesScalar( G1.g, setup.toxic.kdelta)); - setup.vk_proof.vk_beta_2 = G2.affine(G2.mulScalar( G2.g, setup.toxic.kbeta)); - setup.vk_proof.vk_delta_2 = G2.affine(G2.mulScalar( G2.g, setup.toxic.kdelta)); - setup.vk_proof.vk_gamma_2 = G2.affine(G2.mulScalar( G2.g, setup.toxic.kgamma)); + setup.vk_proof.vk_beta_2 = G2.toAffine(G2.timesScalar( G2.g, setup.toxic.kbeta)); + setup.vk_proof.vk_delta_2 = G2.toAffine(G2.timesScalar( G2.g, setup.toxic.kdelta)); + setup.vk_proof.vk_gamma_2 = G2.toAffine(G2.timesScalar( G2.g, setup.toxic.kgamma)); for (let s=0; s setup.vk_proof.nPublic) { - setup.vk_proof.Ap[s] = G1.affine(G1.mulScalar(A, setup.toxic.ka)); + setup.vk_proof.Ap[s] = G1.toAffine(G1.timesScalar(A, setup.toxic.ka)); } - setup.vk_proof.Bp[s] = G1.affine(G1.mulScalar(B1, setup.toxic.kb)); - setup.vk_proof.Cp[s] = G1.affine(G1.mulScalar(C, setup.toxic.kc)); - setup.vk_proof.Kp[s] = G1.affine(G1.mulScalar(K, setup.toxic.kbeta)); + setup.vk_proof.Bp[s] = G1.toAffine(G1.timesScalar(B1, setup.toxic.kb)); + setup.vk_proof.Cp[s] = G1.toAffine(G1.timesScalar(C, setup.toxic.kc)); + setup.vk_proof.Kp[s] = G1.toAffine(G1.timesScalar(K, setup.toxic.kbeta)); } // Extra coeficients - const A = G1.mulScalar( G1.g, F.mul(setup.toxic.ra, v.z_t)); - setup.vk_proof.A[circuit.nVars] = G1.affine(A); - setup.vk_proof.Ap[circuit.nVars] = G1.affine(G1.mulScalar(A, setup.toxic.ka)); + const A = G1.timesScalar( G1.g, F.mul(setup.toxic.ra, v.z_t)); + setup.vk_proof.A[circuit.nVars] = G1.toAffine(A); + setup.vk_proof.Ap[circuit.nVars] = G1.toAffine(G1.timesScalar(A, setup.toxic.ka)); - const B1 = G1.mulScalar( G1.g, F.mul(setup.toxic.rb, v.z_t)); - const B2 = G2.mulScalar( G2.g, F.mul(setup.toxic.rb, v.z_t)); - setup.vk_proof.B[circuit.nVars] = G2.affine(B2); - setup.vk_proof.Bp[circuit.nVars] = G1.affine(G1.mulScalar(B1, setup.toxic.kb)); + const B1 = G1.timesScalar( G1.g, F.mul(setup.toxic.rb, v.z_t)); + const B2 = G2.timesScalar( G2.g, F.mul(setup.toxic.rb, v.z_t)); + setup.vk_proof.B[circuit.nVars] = G2.toAffine(B2); + setup.vk_proof.Bp[circuit.nVars] = G1.toAffine(G1.timesScalar(B1, setup.toxic.kb)); - const C = G1.mulScalar( G1.g, F.mul(setup.toxic.rc, v.z_t)); - setup.vk_proof.C[circuit.nVars] = G1.affine(C); - setup.vk_proof.Cp[circuit.nVars] = G1.affine(G1.mulScalar(C, setup.toxic.kc)); + const C = G1.timesScalar( G1.g, F.mul(setup.toxic.rc, v.z_t)); + setup.vk_proof.C[circuit.nVars] = G1.toAffine(C); + setup.vk_proof.Cp[circuit.nVars] = G1.toAffine(G1.timesScalar(C, setup.toxic.kc)); - setup.vk_proof.Kp[circuit.nVars ] = G1.affine(G1.mulScalar(A, setup.toxic.kbeta)); - setup.vk_proof.Kp[circuit.nVars+1] = G1.affine(G1.mulScalar(B1, setup.toxic.kbeta)); - setup.vk_proof.Kp[circuit.nVars+2] = G1.affine(G1.mulScalar(C, setup.toxic.kbeta)); + setup.vk_proof.Kp[circuit.nVars ] = G1.toAffine(G1.timesScalar(A, setup.toxic.kbeta)); + setup.vk_proof.Kp[circuit.nVars+1] = G1.toAffine(G1.timesScalar(B1, setup.toxic.kbeta)); + setup.vk_proof.Kp[circuit.nVars+2] = G1.toAffine(G1.timesScalar(C, setup.toxic.kbeta)); -// setup.vk_verifier.A[0] = G1.affine(G1.add(setup.vk_verifier.A[0], setup.vk_proof.A[circuit.nVars])); +// setup.vk_verifier.A[0] = G1.toAffine(G1.add(setup.vk_verifier.A[0], setup.vk_proof.A[circuit.nVars])); // vk_z - setup.vk_verifier.vk_z = G2.affine(G2.mulScalar( + setup.vk_verifier.vk_z = G2.toAffine(G2.timesScalar( G2.g, F.mul(setup.toxic.rc, v.z_t))); } @@ -229,7 +229,7 @@ function calculateHexps(setup) { setup.vk_proof.hExps[0] = G1.g; let eT = setup.toxic.t; for (let i=1; i