From 762fbe19a4f7544b46e300a575b5bc1da2bd6ba3 Mon Sep 17 00:00:00 2001 From: krlosMata Date: Mon, 24 Feb 2020 12:45:44 +0100 Subject: [PATCH] add setup for .r1cs files --- cli.js | 12 +- index.js | 3 + package.json | 1 + src/r1cs_parser.js | 289 +++++++++++++++++++++++++++++++++++++++++ test/r1cs/circuit.json | 126 ++++++++++++++++++ test/r1cs/circuit.r1cs | Bin 0 -> 443 bytes test/setup_r1cs.js | 55 ++++++++ 7 files changed, 484 insertions(+), 2 deletions(-) create mode 100644 src/r1cs_parser.js create mode 100644 test/r1cs/circuit.json create mode 100644 test/r1cs/circuit.r1cs create mode 100644 test/setup_r1cs.js diff --git a/cli.js b/cli.js index 9e40502..2beb0a2 100755 --- a/cli.js +++ b/cli.js @@ -45,6 +45,8 @@ setup command Filename of the compiled circuit file generated by circom. + Filename could have extension .json or .r1cs + Default: circuit.json --pk or --provingkey @@ -291,8 +293,14 @@ try { cir.printConstraints(); } else if (argv._[0].toUpperCase() == "SETUP") { - const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8")); - const cir = new zkSnark.Circuit(cirDef); + const cirExtension = circuitName.split(".").pop(); + + let cir; + if (cirExtension == "json"){ + const cirDefJSON = JSON.parse(fs.readFileSync(circuitName, "utf8")); + cir = new zkSnark.Circuit(cirDefJSON); + } else if (cirExtension == "r1cs") + cir = zkSnark.parseR1csSync(circuitName); if (!zkSnark[protocol]) throw new Error("Invalid protocol"); const setup = zkSnark[protocol].setup(cir); diff --git a/index.js b/index.js index dc13df0..131057a 100644 --- a/index.js +++ b/index.js @@ -42,3 +42,6 @@ exports.unstringifyBigInts = require("./src/stringifybigint.js").unstringifyBigI const Bn128 = require("./src/bn128.js"); exports.bn128 = new Bn128(); + +exports.parseR1cs = require("./src/r1cs_parser.js").loadR1cs; +exports.parseR1csSync = require("./src/r1cs_parser.js").loadR1csSynch; \ No newline at end of file diff --git a/package.json b/package.json index f40193a..f4916e8 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ }, "devDependencies": { "eslint-plugin-mocha": "^5.3.0", + "lodash": "^4.17.15", "mocha": "^5.2.0" } } diff --git a/src/r1cs_parser.js b/src/r1cs_parser.js new file mode 100644 index 0000000..719bb2b --- /dev/null +++ b/src/r1cs_parser.js @@ -0,0 +1,289 @@ +const fs = require("fs"); +const assert = require("assert"); +const bigInt = require("big-integer"); + +module.exports.loadR1cs = loadR1cs; +module.exports.loadR1csSynch = loadR1csSync; + +async function loadR1cs(fileName) { + const res = {}; + const fd = await fs.promises.open(fileName, "r"); + + const b = Buffer.allocUnsafe(4); + await fd.read(b, 0, 4, 0); + if (b.toString() != "r1cs") assert(false, "Invalid File format"); + + let p=4; + + let v = await readU32(); + + if (v>1) assert(false, "Version not supported"); + + const nSections = await readU32(); + + let pHeader; + let pConstraints; + let headerSize; + let constraintsSize; + let pMap; + let mapSize; + for (let i=0; i1) assert(false, "Version not supported"); + + const nSections = readU32(); + + let pHeader; + let pConstraints; + let headerSize; + let constraintsSize; + let pMap; + let mapSize; + for (let i=0; iK=L5x0szpJX&(Rp literal 0 HcmV?d00001 diff --git a/test/setup_r1cs.js b/test/setup_r1cs.js new file mode 100644 index 0000000..a08243b --- /dev/null +++ b/test/setup_r1cs.js @@ -0,0 +1,55 @@ +const chai = require("chai"); +const fs = require("fs"); +const path = require("path"); +const lodash = require("lodash"); + +const zkSnark = require("../index.js"); + +const assert = chai.assert; + +describe("R1CS", () => { + + it("parser", () => { + // Load circuit with .json file + const cirDefJSON = JSON.parse(fs.readFileSync(path.join(__dirname, "r1cs", "circuit.json"), "utf8")); + const cirJSON = new zkSnark.Circuit(cirDefJSON); + // Load circuit with .r1cs file (async) + zkSnark.parseR1cs(path.join(__dirname, "r1cs", "circuit.r1cs")) + .then( cirDefR1cs => { + assert(cirJSON.nVars == cirDefR1cs.nVars); + assert(cirJSON.nPubInputs == cirDefR1cs.nPubInputs); + assert(cirJSON.nOutputs == cirDefR1cs.nOutputs); + assert(cirJSON.constraints.length == cirDefR1cs.nConstraints); + + for (let i = 0; i < cirDefR1cs.nConstraints; i++){ + const constraintJSON = cirJSON.constraints[i]; + const constraintR1CS = cirDefR1cs.constraints[i]; + assert(constraintJSON.length, constraintR1CS.length); + for (let j = 0; j < constraintJSON.length; j++) + assert(lodash.isEqual(constraintJSON[j], constraintR1CS[j])); + } + }); + }); + + it("check setup", () => { + // load JSON circuit + const cirDef = JSON.parse(fs.readFileSync(path.join(__dirname, "r1cs", "circuit.json"), "utf8")); + const cir = new zkSnark.Circuit(cirDef); + + // load .r1cs circuit (sync) + const cirDefR1cs = zkSnark.parseR1csSync(path.join(__dirname, "r1cs", "circuit.r1cs")); + + // calculate prover and verifier from R1CS circuit + const setupR1cs = zkSnark["groth"].setup(cirDefR1cs); + + // calculate witness from regular circuit + const witness = cir.calculateWitness({"a": "1", "b": "1", "c": "5", "d": "5", "e": "1", "f": "25"}); + + // generate proof + const { proof, publicSignals } = zkSnark["groth"].genProof(setupR1cs.vk_proof, witness); + + // check proof + const isValid = zkSnark["groth"].isValid(setupR1cs.vk_verifier, proof, publicSignals); + assert(isValid); + }); +}); \ No newline at end of file