Adapted to circom 0.5
This commit is contained in:
parent
762fbe19a4
commit
5adee591bf
2
COPYING
2
COPYING
@ -1,7 +1,7 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Copyright (C) 2020 0Kims Association <https://0kims.org>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
123
cli.js
123
cli.js
@ -27,9 +27,14 @@ const path = require("path");
|
||||
const zkSnark = require("./index.js");
|
||||
const {stringifyBigInts, unstringifyBigInts} = require("./src/stringifybigint.js");
|
||||
|
||||
const loadR1cs = require("r1csfile").load;
|
||||
const WitnessCalculatorBuilder = require("circom_runtime").WitnessCalculatorBuilder;
|
||||
|
||||
const version = require("./package").version;
|
||||
|
||||
const loadSyms = require("./src/loadsyms");
|
||||
const printR1cs = require("./src/printr1cs");
|
||||
|
||||
const argv = require("yargs")
|
||||
.version(version)
|
||||
.usage(`snarkjs <command> <options>
|
||||
@ -41,13 +46,11 @@ setup command
|
||||
|
||||
Runs a setup for a circuit generating the proving and the verification key.
|
||||
|
||||
-c or --circuit <circuitFile>
|
||||
-r or --r1cs <r1csFile>
|
||||
|
||||
Filename of the compiled circuit file generated by circom.
|
||||
|
||||
Filename could have extension .json or .r1cs
|
||||
|
||||
Default: circuit.json
|
||||
Default: circuit.r1cs
|
||||
|
||||
--pk or --provingkey <provingKeyFile>
|
||||
|
||||
@ -74,11 +77,11 @@ calculate witness command
|
||||
|
||||
Calculate the witness of a circuit given an input.
|
||||
|
||||
-c or --circuit <circuitFile>
|
||||
--ws --wasm <wasmFile>
|
||||
|
||||
Filename of the compiled circuit file generated by circom.
|
||||
|
||||
Default: circuit.json
|
||||
Default: circuit.r1cs
|
||||
|
||||
-i or --input <inputFile>
|
||||
|
||||
@ -90,16 +93,12 @@ calculate witness command
|
||||
|
||||
{"a": "22", "b": "33"}
|
||||
|
||||
-w or --witness
|
||||
--wt --witness
|
||||
|
||||
Output filename with the generated witness.
|
||||
|
||||
Default: witness.json
|
||||
|
||||
--lo or --logoutput
|
||||
|
||||
Output all the Output signals
|
||||
|
||||
--lg or --logget
|
||||
|
||||
Output GET access to the signals
|
||||
@ -112,13 +111,15 @@ calculate witness command
|
||||
|
||||
Output when a subcomponent is triggered and when finished
|
||||
|
||||
--s or --sanitycheck
|
||||
|
||||
|
||||
generate a proof command
|
||||
========================
|
||||
|
||||
snarkjs proof <options>
|
||||
|
||||
-w or --witness
|
||||
--wt or --witness
|
||||
|
||||
Input filename used to calculate the proof.
|
||||
|
||||
@ -217,11 +218,11 @@ circuit info
|
||||
|
||||
Print statistics of a circuit
|
||||
|
||||
-c or --circuit <circuitFile>
|
||||
-r or --r1cs <r1csFile>
|
||||
|
||||
Filename of the compiled circuit file generated by circom.
|
||||
|
||||
Default: circuit.json
|
||||
Default: circuit.r1cs
|
||||
|
||||
print constraints
|
||||
=================
|
||||
@ -230,16 +231,24 @@ print constraints
|
||||
|
||||
Print all the constraints of a given circuit
|
||||
|
||||
-c or --circuit <circuitFile>
|
||||
-r or --r1cs <r1csFile>
|
||||
|
||||
Filename of the compiled circuit file generated by circom.
|
||||
|
||||
Default: circuit.json
|
||||
Default: circuit.r1cs
|
||||
|
||||
-s or --sym <symFile>
|
||||
|
||||
Filename of the debuging symbols file generated by circom.
|
||||
|
||||
Default: circuit.sym
|
||||
`)
|
||||
.alias("c", "circuit")
|
||||
.alias("r", "r1cs")
|
||||
.alias("s", "sym")
|
||||
.alias("pk", "provingkey")
|
||||
.alias("vk", "verificationkey")
|
||||
.alias("w", "witness")
|
||||
.alias("wt", "witness")
|
||||
.alias("ws", "wasm")
|
||||
.alias("p", "proof")
|
||||
.alias("i", "input")
|
||||
.alias("pub", "public")
|
||||
@ -258,15 +267,21 @@ print constraints
|
||||
repo directory at https://github.com/iden3/circom `)
|
||||
.argv;
|
||||
|
||||
const circuitName = (argv.circuit) ? argv.circuit : "circuit.json";
|
||||
const r1csName = (argv.r1cs) ? argv.r1cs : "circuit.r1cs";
|
||||
const symName = (argv.sym) ? argv.sym : "circuit.sym";
|
||||
const provingKeyName = (argv.provingkey) ? argv.provingkey : "proving_key.json";
|
||||
const verificationKeyName = (argv.verificationkey) ? argv.verificationkey : "verification_key.json";
|
||||
const inputName = (argv.input) ? argv.input : "input.json";
|
||||
const wasmName = (argv.wasm) ? argv.wasm : "circuit.wasm";
|
||||
const witnessName = (argv.witness) ? argv.witness : "witness.json";
|
||||
const proofName = (argv.proof) ? argv.proof : "proof.json";
|
||||
const publicName = (argv.public) ? argv.public : "public.json";
|
||||
const verifierName = (argv.verifier) ? argv.verifier : "verifier.sol";
|
||||
const protocol = (argv.protocol) ? argv.protocol : "original";
|
||||
const protocol = (argv.protocol) ? argv.protocol : "groth";
|
||||
|
||||
run().then(() => {
|
||||
process.exit();
|
||||
});
|
||||
|
||||
function p256(n) {
|
||||
let nstr = n.toString(16);
|
||||
@ -275,10 +290,10 @@ function p256(n) {
|
||||
return nstr;
|
||||
}
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
if (argv._[0].toUpperCase() == "INFO") {
|
||||
const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8"));
|
||||
const cir = new zkSnark.Circuit(cirDef);
|
||||
const cir = await loadR1cs(r1csName);
|
||||
|
||||
console.log(`# Wires: ${cir.nVars}`);
|
||||
console.log(`# Constraints: ${cir.nConstraints}`);
|
||||
@ -287,20 +302,13 @@ try {
|
||||
console.log(`# Outputs: ${cir.nOutputs}`);
|
||||
|
||||
} else if (argv._[0].toUpperCase() == "PRINTCONSTRAINTS") {
|
||||
const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8"));
|
||||
const cir = new zkSnark.Circuit(cirDef);
|
||||
const cir = await loadR1cs(r1csName, true, true);
|
||||
|
||||
cir.printConstraints();
|
||||
const sym = await loadSyms(symName);
|
||||
|
||||
printR1cs(cir, sym);
|
||||
} else if (argv._[0].toUpperCase() == "SETUP") {
|
||||
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);
|
||||
const cir = await loadR1cs(r1csName, true);
|
||||
|
||||
if (!zkSnark[protocol]) throw new Error("Invalid protocol");
|
||||
const setup = zkSnark[protocol].setup(cir);
|
||||
@ -309,19 +317,45 @@ try {
|
||||
fs.writeFileSync(verificationKeyName, JSON.stringify(stringifyBigInts(setup.vk_verifier), null, 1), "utf-8");
|
||||
process.exit(0);
|
||||
} else if (argv._[0].toUpperCase() == "CALCULATEWITNESS") {
|
||||
const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8"));
|
||||
const cir = new zkSnark.Circuit(cirDef);
|
||||
const input = unstringifyBigInts(JSON.parse(fs.readFileSync(inputName, "utf8")));
|
||||
const wasm = await fs.promises.readFile(wasmName);
|
||||
const input = unstringifyBigInts(JSON.parse(await fs.promises.readFile(inputName, "utf8")));
|
||||
|
||||
const witness = cir.calculateWitness(input, {
|
||||
logOutput: argv.logoutput,
|
||||
logSet: argv.logset,
|
||||
logGet: argv.logget,
|
||||
logTrigger: argv.logtrigger
|
||||
});
|
||||
|
||||
fs.writeFileSync(witnessName, JSON.stringify(stringifyBigInts(witness), null, 1), "utf-8");
|
||||
process.exit(0);
|
||||
let options;
|
||||
let sym;
|
||||
if (argv.logset || argv.logget || argv.logtrigger || argv.sanitycheck) {
|
||||
options = {
|
||||
sanityCheck: true
|
||||
};
|
||||
if (argv.logset) {
|
||||
if (!sym) sym = await loadSyms(symName);
|
||||
options.logSetSignal= function(labelIdx, value) {
|
||||
console.log("SET " + sym.labelIdx2Name[labelIdx] + " <-- " + value.toString());
|
||||
};
|
||||
}
|
||||
if (argv.logget) {
|
||||
if (!sym) sym = await loadSyms(symName);
|
||||
options.logGetSignal= function(varIdx, value) {
|
||||
console.log("GET " + sym.labelIdx2Name[varIdx] + " --> " + value.toString());
|
||||
};
|
||||
}
|
||||
if (argv.logtrigger) {
|
||||
if (!sym) sym = await loadSyms(symName);
|
||||
options.logStartComponent= function(cIdx) {
|
||||
console.log("START: " + sym.componentIdx2Name[cIdx]);
|
||||
};
|
||||
options.logFinishComponent= function(cIdx) {
|
||||
console.log("FINISH: " + sym.componentIdx2Name[cIdx]);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const wc = await WitnessCalculatorBuilder(wasm, options);
|
||||
|
||||
const w = await wc.calculateWitness(input);
|
||||
|
||||
await fs.promises.writeFile(witnessName, JSON.stringify(stringifyBigInts(w), null, 1));
|
||||
|
||||
} else if (argv._[0].toUpperCase() == "PROOF") {
|
||||
const witness = unstringifyBigInts(JSON.parse(fs.readFileSync(witnessName, "utf8")));
|
||||
const provingKey = unstringifyBigInts(JSON.parse(fs.readFileSync(provingKeyName, "utf8")));
|
||||
@ -409,6 +443,7 @@ try {
|
||||
console.log("ERROR: " + err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function generateVerifier_original(verificationKey) {
|
||||
|
3
index.js
3
index.js
@ -42,6 +42,3 @@ 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;
|
26
package-lock.json
generated
26
package-lock.json
generated
@ -155,6 +155,22 @@
|
||||
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
|
||||
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII="
|
||||
},
|
||||
"circom_runtime": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.0.1.tgz",
|
||||
"integrity": "sha512-8j/UBzGHhCyGfAaxKz2kFFEUwmfbp1iC10js382t3hy4RvCyrqQhssFVUXP3GNGKwu7W9ecdHbyODcg5MgffsA==",
|
||||
"requires": {
|
||||
"big-integer": "^1.6.48",
|
||||
"fnv-plus": "^1.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"big-integer": {
|
||||
"version": "1.6.48",
|
||||
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz",
|
||||
"integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli-cursor": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
|
||||
@ -491,6 +507,11 @@
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz",
|
||||
"integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg=="
|
||||
},
|
||||
"fnv-plus": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/fnv-plus/-/fnv-plus-1.3.1.tgz",
|
||||
"integrity": "sha512-Gz1EvfOneuFfk4yG458dJ3TLJ7gV19q3OM/vVvvHf7eT02Hm1DleB4edsia6ahbKgAYxO9gvyQ1ioWZR+a00Yw=="
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
@ -978,6 +999,11 @@
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
},
|
||||
"r1csfile": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.1.tgz",
|
||||
"integrity": "sha512-1mUgD7XXpU/EAf4xWiIt1jaQbQuMBDKAiEJ2eZYsN9rHOJtBWZqLYDkAmC4WJhCwK3O3NZKhvRMaNBM5dBpp1Q=="
|
||||
},
|
||||
"ramda": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz",
|
||||
|
@ -30,9 +30,11 @@
|
||||
"dependencies": {
|
||||
"big-integer": "^1.6.43",
|
||||
"chai": "^4.2.0",
|
||||
"circom_runtime": "0.0.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"eslint": "^5.16.0",
|
||||
"keccak": "^2.0.0",
|
||||
"r1csfile": "0.0.1",
|
||||
"yargs": "^12.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -107,7 +107,7 @@ module.exports = class Circuit {
|
||||
vs = "";
|
||||
}
|
||||
if (vs!="1") {
|
||||
vs = vs + v.toString();;
|
||||
vs = vs + v.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
32
src/loadsyms.js
Normal file
32
src/loadsyms.js
Normal file
@ -0,0 +1,32 @@
|
||||
const fs = require("fs");
|
||||
|
||||
module.exports = async function loadSymbols(symFileName) {
|
||||
const sym = {
|
||||
labelIdx2Name: [ "one" ],
|
||||
varIdx2Name: [ "one" ],
|
||||
componentIdx2Name: []
|
||||
};
|
||||
const symsStr = await fs.promises.readFile(symFileName, "utf8");
|
||||
const lines = symsStr.split("\n");
|
||||
for (let i=0; i<lines.length; i++) {
|
||||
const arr = lines[i].split(",");
|
||||
if (arr.length!=4) continue;
|
||||
if (sym.varIdx2Name[arr[1]]) {
|
||||
sym.varIdx2Name[arr[1]] += "|" + arr[3];
|
||||
} else {
|
||||
sym.varIdx2Name[arr[1]] = arr[3];
|
||||
}
|
||||
sym.labelIdx2Name[arr[0]] = arr[3];
|
||||
if (!sym.componentIdx2Name[arr[2]]) {
|
||||
sym.componentIdx2Name[arr[2]] = extractComponent(arr[3]);
|
||||
}
|
||||
}
|
||||
|
||||
return sym;
|
||||
|
||||
function extractComponent(name) {
|
||||
const arr = name.split(".");
|
||||
arr.pop(); // Remove the lasr element
|
||||
return arr.join(".");
|
||||
}
|
||||
};
|
37
src/printr1cs.js
Normal file
37
src/printr1cs.js
Normal file
@ -0,0 +1,37 @@
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
module.exports = function printR1cs(r1cs, syms) {
|
||||
for (let i=0; i<r1cs.constraints.length; i++) {
|
||||
printCostraint(r1cs.constraints[i]);
|
||||
}
|
||||
function printCostraint(c) {
|
||||
const lc2str = (lc) => {
|
||||
let S = "";
|
||||
for (let k in lc) {
|
||||
let name = syms[k];
|
||||
if (name == "one") name = "";
|
||||
let v = bigInt(lc[k]);
|
||||
let vs;
|
||||
if (!v.lesserOrEquals(r1cs.prime.shiftRight(bigInt(1)))) {
|
||||
v = r1cs.prime.minus(v);
|
||||
vs = "-"+v.toString();
|
||||
} else {
|
||||
if (S!="") {
|
||||
vs = "+"+v.toString();
|
||||
} else {
|
||||
vs = "";
|
||||
}
|
||||
if (vs!="1") {
|
||||
vs = vs + v.toString();
|
||||
}
|
||||
}
|
||||
|
||||
S= S + " " + vs + name;
|
||||
}
|
||||
return S;
|
||||
};
|
||||
const S = `[ ${lc2str(c[0])} ] * [ ${lc2str(c[1])} ] - [ ${lc2str(c[2])} ] = 0`;
|
||||
console.log(S);
|
||||
}
|
||||
|
||||
};
|
@ -147,7 +147,7 @@ async function loadR1cs(fileName) {
|
||||
}
|
||||
}
|
||||
|
||||
function loadR1csSync(fileName) {
|
||||
async function loadR1cs(fileName) {
|
||||
const res = {};
|
||||
const fd = fs.openSync(fileName, "r");
|
||||
|
||||
@ -167,11 +167,9 @@ function loadR1csSync(fileName) {
|
||||
let pConstraints;
|
||||
let headerSize;
|
||||
let constraintsSize;
|
||||
let pMap;
|
||||
let mapSize;
|
||||
for (let i=0; i<nSections; i++) {
|
||||
let ht = readU32();
|
||||
let hl = readDouble64();
|
||||
let hl = readU64();
|
||||
if (ht == 1) {
|
||||
if (typeof pHeader != "undefined") assert(false, "File has two headder sections");
|
||||
pHeader = p;
|
||||
@ -180,17 +178,26 @@ function loadR1csSync(fileName) {
|
||||
if (typeof pConstraints != "undefined") assert(false, "File has two constraints sections");
|
||||
pConstraints = p;
|
||||
constraintsSize = hl;
|
||||
} else if (ht==3) {
|
||||
pMap = p;
|
||||
mapSize = hl;
|
||||
}
|
||||
p += hl;
|
||||
}
|
||||
|
||||
if (typeof pHeader == "undefined") assert(false, "File has two header");
|
||||
if (typeof pHeader == "undefined") assert(false, "File has no header");
|
||||
|
||||
// Read Header
|
||||
p = pHeader;
|
||||
|
||||
const n8 = await readU32();
|
||||
res.prime = await readBigInt();
|
||||
|
||||
res.nWires = await readU32();
|
||||
res.nPubOuts = await readU32();
|
||||
res.nPubIns = await readU32();
|
||||
res.nPrvIns = await readU32();
|
||||
res.nLabels = await readU64();
|
||||
res.nConstraints = await readU32();
|
||||
|
||||
|
||||
const fieldDefSize = readU32();
|
||||
const pFieldDef = p;
|
||||
|
||||
|
@ -1,55 +0,0 @@
|
||||
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);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user