Adapted to circom 0.5

This commit is contained in:
Jordi Baylina 2020-03-26 20:16:29 +01:00
parent 762fbe19a4
commit 5adee591bf
No known key found for this signature in database
GPG Key ID: 7480C80C1BE43112
10 changed files with 284 additions and 203 deletions

@ -1,7 +1,7 @@
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 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 Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.

305
cli.js

@ -27,9 +27,14 @@ const path = require("path");
const zkSnark = require("./index.js"); const zkSnark = require("./index.js");
const {stringifyBigInts, unstringifyBigInts} = require("./src/stringifybigint.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 version = require("./package").version;
const loadSyms = require("./src/loadsyms");
const printR1cs = require("./src/printr1cs");
const argv = require("yargs") const argv = require("yargs")
.version(version) .version(version)
.usage(`snarkjs <command> <options> .usage(`snarkjs <command> <options>
@ -41,13 +46,11 @@ setup command
Runs a setup for a circuit generating the proving and the verification key. 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 of the compiled circuit file generated by circom.
Filename could have extension .json or .r1cs Default: circuit.r1cs
Default: circuit.json
--pk or --provingkey <provingKeyFile> --pk or --provingkey <provingKeyFile>
@ -74,11 +77,11 @@ calculate witness command
Calculate the witness of a circuit given an input. 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. Filename of the compiled circuit file generated by circom.
Default: circuit.json Default: circuit.r1cs
-i or --input <inputFile> -i or --input <inputFile>
@ -90,16 +93,12 @@ calculate witness command
{"a": "22", "b": "33"} {"a": "22", "b": "33"}
-w or --witness --wt --witness
Output filename with the generated witness. Output filename with the generated witness.
Default: witness.json Default: witness.json
--lo or --logoutput
Output all the Output signals
--lg or --logget --lg or --logget
Output GET access to the signals Output GET access to the signals
@ -112,13 +111,15 @@ calculate witness command
Output when a subcomponent is triggered and when finished Output when a subcomponent is triggered and when finished
--s or --sanitycheck
generate a proof command generate a proof command
======================== ========================
snarkjs proof <options> snarkjs proof <options>
-w or --witness --wt or --witness
Input filename used to calculate the proof. Input filename used to calculate the proof.
@ -217,11 +218,11 @@ circuit info
Print statistics of a circuit Print statistics of a circuit
-c or --circuit <circuitFile> -r or --r1cs <r1csFile>
Filename of the compiled circuit file generated by circom. Filename of the compiled circuit file generated by circom.
Default: circuit.json Default: circuit.r1cs
print constraints print constraints
================= =================
@ -230,16 +231,24 @@ print constraints
Print all the constraints of a given circuit 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. 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("pk", "provingkey")
.alias("vk", "verificationkey") .alias("vk", "verificationkey")
.alias("w", "witness") .alias("wt", "witness")
.alias("ws", "wasm")
.alias("p", "proof") .alias("p", "proof")
.alias("i", "input") .alias("i", "input")
.alias("pub", "public") .alias("pub", "public")
@ -258,15 +267,21 @@ print constraints
repo directory at https://github.com/iden3/circom `) repo directory at https://github.com/iden3/circom `)
.argv; .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 provingKeyName = (argv.provingkey) ? argv.provingkey : "proving_key.json";
const verificationKeyName = (argv.verificationkey) ? argv.verificationkey : "verification_key.json"; const verificationKeyName = (argv.verificationkey) ? argv.verificationkey : "verification_key.json";
const inputName = (argv.input) ? argv.input : "input.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 witnessName = (argv.witness) ? argv.witness : "witness.json";
const proofName = (argv.proof) ? argv.proof : "proof.json"; const proofName = (argv.proof) ? argv.proof : "proof.json";
const publicName = (argv.public) ? argv.public : "public.json"; const publicName = (argv.public) ? argv.public : "public.json";
const verifierName = (argv.verifier) ? argv.verifier : "verifier.sol"; 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) { function p256(n) {
let nstr = n.toString(16); let nstr = n.toString(16);
@ -275,139 +290,159 @@ function p256(n) {
return nstr; return nstr;
} }
try { async function run() {
if (argv._[0].toUpperCase() == "INFO") { try {
const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8")); if (argv._[0].toUpperCase() == "INFO") {
const cir = new zkSnark.Circuit(cirDef); const cir = await loadR1cs(r1csName);
console.log(`# Wires: ${cir.nVars}`); console.log(`# Wires: ${cir.nVars}`);
console.log(`# Constraints: ${cir.nConstraints}`); console.log(`# Constraints: ${cir.nConstraints}`);
console.log(`# Private Inputs: ${cir.nPrvInputs}`); console.log(`# Private Inputs: ${cir.nPrvInputs}`);
console.log(`# Public Inputs: ${cir.nPubInputs}`); console.log(`# Public Inputs: ${cir.nPubInputs}`);
console.log(`# Outputs: ${cir.nOutputs}`); console.log(`# Outputs: ${cir.nOutputs}`);
} else if (argv._[0].toUpperCase() == "PRINTCONSTRAINTS") { } else if (argv._[0].toUpperCase() == "PRINTCONSTRAINTS") {
const cirDef = JSON.parse(fs.readFileSync(circuitName, "utf8")); const cir = await loadR1cs(r1csName, true, true);
const cir = new zkSnark.Circuit(cirDef);
cir.printConstraints(); const sym = await loadSyms(symName);
} else if (argv._[0].toUpperCase() == "SETUP") { printR1cs(cir, sym);
const cirExtension = circuitName.split(".").pop(); } else if (argv._[0].toUpperCase() == "SETUP") {
const cir = await loadR1cs(r1csName, true);
let cir; if (!zkSnark[protocol]) throw new Error("Invalid protocol");
if (cirExtension == "json"){ const setup = zkSnark[protocol].setup(cir);
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"); fs.writeFileSync(provingKeyName, JSON.stringify(stringifyBigInts(setup.vk_proof), null, 1), "utf-8");
const setup = zkSnark[protocol].setup(cir); fs.writeFileSync(verificationKeyName, JSON.stringify(stringifyBigInts(setup.vk_verifier), null, 1), "utf-8");
process.exit(0);
} else if (argv._[0].toUpperCase() == "CALCULATEWITNESS") {
const wasm = await fs.promises.readFile(wasmName);
const input = unstringifyBigInts(JSON.parse(await fs.promises.readFile(inputName, "utf8")));
fs.writeFileSync(provingKeyName, JSON.stringify(stringifyBigInts(setup.vk_proof), null, 1), "utf-8");
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 witness = cir.calculateWitness(input, { let options;
logOutput: argv.logoutput, let sym;
logSet: argv.logset, if (argv.logset || argv.logget || argv.logtrigger || argv.sanitycheck) {
logGet: argv.logget, options = {
logTrigger: argv.logtrigger 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]);
};
}
}
fs.writeFileSync(witnessName, JSON.stringify(stringifyBigInts(witness), null, 1), "utf-8"); const wc = await WitnessCalculatorBuilder(wasm, options);
process.exit(0);
} else if (argv._[0].toUpperCase() == "PROOF") {
const witness = unstringifyBigInts(JSON.parse(fs.readFileSync(witnessName, "utf8")));
const provingKey = unstringifyBigInts(JSON.parse(fs.readFileSync(provingKeyName, "utf8")));
const protocol = provingKey.protocol; const w = await wc.calculateWitness(input);
if (!zkSnark[protocol]) throw new Error("Invalid protocol");
const {proof, publicSignals} = zkSnark[protocol].genProof(provingKey, witness);
fs.writeFileSync(proofName, JSON.stringify(stringifyBigInts(proof), null, 1), "utf-8"); await fs.promises.writeFile(witnessName, JSON.stringify(stringifyBigInts(w), null, 1));
fs.writeFileSync(publicName, JSON.stringify(stringifyBigInts(publicSignals), null, 1), "utf-8");
process.exit(0);
} else if (argv._[0].toUpperCase() == "VERIFY") {
const public = unstringifyBigInts(JSON.parse(fs.readFileSync(publicName, "utf8")));
const verificationKey = unstringifyBigInts(JSON.parse(fs.readFileSync(verificationKeyName, "utf8")));
const proof = unstringifyBigInts(JSON.parse(fs.readFileSync(proofName, "utf8")));
const protocol = verificationKey.protocol; } else if (argv._[0].toUpperCase() == "PROOF") {
if (!zkSnark[protocol]) throw new Error("Invalid protocol"); const witness = unstringifyBigInts(JSON.parse(fs.readFileSync(witnessName, "utf8")));
const provingKey = unstringifyBigInts(JSON.parse(fs.readFileSync(provingKeyName, "utf8")));
const isValid = zkSnark[protocol].isValid(verificationKey, proof, public); const protocol = provingKey.protocol;
if (!zkSnark[protocol]) throw new Error("Invalid protocol");
const {proof, publicSignals} = zkSnark[protocol].genProof(provingKey, witness);
if (isValid) { fs.writeFileSync(proofName, JSON.stringify(stringifyBigInts(proof), null, 1), "utf-8");
console.log("OK"); fs.writeFileSync(publicName, JSON.stringify(stringifyBigInts(publicSignals), null, 1), "utf-8");
process.exit(0);
} else if (argv._[0].toUpperCase() == "VERIFY") {
const public = unstringifyBigInts(JSON.parse(fs.readFileSync(publicName, "utf8")));
const verificationKey = unstringifyBigInts(JSON.parse(fs.readFileSync(verificationKeyName, "utf8")));
const proof = unstringifyBigInts(JSON.parse(fs.readFileSync(proofName, "utf8")));
const protocol = verificationKey.protocol;
if (!zkSnark[protocol]) throw new Error("Invalid protocol");
const isValid = zkSnark[protocol].isValid(verificationKey, proof, public);
if (isValid) {
console.log("OK");
process.exit(0);
} else {
console.log("INVALID");
process.exit(1);
}
} else if (argv._[0].toUpperCase() == "GENERATEVERIFIER") {
const verificationKey = unstringifyBigInts(JSON.parse(fs.readFileSync(verificationKeyName, "utf8")));
let verifierCode;
if (verificationKey.protocol == "original") {
verifierCode = generateVerifier_original(verificationKey);
} else if (verificationKey.protocol == "groth") {
verifierCode = generateVerifier_groth(verificationKey);
} else if (verificationKey.protocol == "kimleeoh") {
verifierCode = generateVerifier_kimleeoh(verificationKey);
} else {
throw new Error("InvalidProof");
}
fs.writeFileSync(verifierName, verifierCode, "utf-8");
process.exit(0);
} else if (argv._[0].toUpperCase() == "GENERATECALL") {
const public = unstringifyBigInts(JSON.parse(fs.readFileSync(publicName, "utf8")));
const proof = unstringifyBigInts(JSON.parse(fs.readFileSync(proofName, "utf8")));
let inputs = "";
for (let i=0; i<public.length; i++) {
if (inputs != "") inputs = inputs + ",";
inputs = inputs + p256(public[i]);
}
let S;
if ((typeof proof.protocol === "undefined") || (proof.protocol == "original")) {
S=`[${p256(proof.pi_a[0])}, ${p256(proof.pi_a[1])}],` +
`[${p256(proof.pi_ap[0])}, ${p256(proof.pi_ap[1])}],` +
`[[${p256(proof.pi_b[0][1])}, ${p256(proof.pi_b[0][0])}],[${p256(proof.pi_b[1][1])}, ${p256(proof.pi_b[1][0])}]],` +
`[${p256(proof.pi_bp[0])}, ${p256(proof.pi_bp[1])}],` +
`[${p256(proof.pi_c[0])}, ${p256(proof.pi_c[1])}],` +
`[${p256(proof.pi_cp[0])}, ${p256(proof.pi_cp[1])}],` +
`[${p256(proof.pi_h[0])}, ${p256(proof.pi_h[1])}],` +
`[${p256(proof.pi_kp[0])}, ${p256(proof.pi_kp[1])}],` +
`[${inputs}]`;
} else if ((proof.protocol == "groth")||(proof.protocol == "kimleeoh")) {
S=`[${p256(proof.pi_a[0])}, ${p256(proof.pi_a[1])}],` +
`[[${p256(proof.pi_b[0][1])}, ${p256(proof.pi_b[0][0])}],[${p256(proof.pi_b[1][1])}, ${p256(proof.pi_b[1][0])}]],` +
`[${p256(proof.pi_c[0])}, ${p256(proof.pi_c[1])}],` +
`[${inputs}]`;
} else {
throw new Error("InvalidProof");
}
console.log(S);
process.exit(0); process.exit(0);
} else { } else {
console.log("INVALID"); throw new Error("Invalid Command");
process.exit(1);
} }
} else if (argv._[0].toUpperCase() == "GENERATEVERIFIER") { } catch(err) {
console.log(err.stack);
const verificationKey = unstringifyBigInts(JSON.parse(fs.readFileSync(verificationKeyName, "utf8"))); console.log("ERROR: " + err);
process.exit(1);
let verifierCode;
if (verificationKey.protocol == "original") {
verifierCode = generateVerifier_original(verificationKey);
} else if (verificationKey.protocol == "groth") {
verifierCode = generateVerifier_groth(verificationKey);
} else if (verificationKey.protocol == "kimleeoh") {
verifierCode = generateVerifier_kimleeoh(verificationKey);
} else {
throw new Error("InvalidProof");
}
fs.writeFileSync(verifierName, verifierCode, "utf-8");
process.exit(0);
} else if (argv._[0].toUpperCase() == "GENERATECALL") {
const public = unstringifyBigInts(JSON.parse(fs.readFileSync(publicName, "utf8")));
const proof = unstringifyBigInts(JSON.parse(fs.readFileSync(proofName, "utf8")));
let inputs = "";
for (let i=0; i<public.length; i++) {
if (inputs != "") inputs = inputs + ",";
inputs = inputs + p256(public[i]);
}
let S;
if ((typeof proof.protocol === "undefined") || (proof.protocol == "original")) {
S=`[${p256(proof.pi_a[0])}, ${p256(proof.pi_a[1])}],` +
`[${p256(proof.pi_ap[0])}, ${p256(proof.pi_ap[1])}],` +
`[[${p256(proof.pi_b[0][1])}, ${p256(proof.pi_b[0][0])}],[${p256(proof.pi_b[1][1])}, ${p256(proof.pi_b[1][0])}]],` +
`[${p256(proof.pi_bp[0])}, ${p256(proof.pi_bp[1])}],` +
`[${p256(proof.pi_c[0])}, ${p256(proof.pi_c[1])}],` +
`[${p256(proof.pi_cp[0])}, ${p256(proof.pi_cp[1])}],` +
`[${p256(proof.pi_h[0])}, ${p256(proof.pi_h[1])}],` +
`[${p256(proof.pi_kp[0])}, ${p256(proof.pi_kp[1])}],` +
`[${inputs}]`;
} else if ((proof.protocol == "groth")||(proof.protocol == "kimleeoh")) {
S=`[${p256(proof.pi_a[0])}, ${p256(proof.pi_a[1])}],` +
`[[${p256(proof.pi_b[0][1])}, ${p256(proof.pi_b[0][0])}],[${p256(proof.pi_b[1][1])}, ${p256(proof.pi_b[1][0])}]],` +
`[${p256(proof.pi_c[0])}, ${p256(proof.pi_c[1])}],` +
`[${inputs}]`;
} else {
throw new Error("InvalidProof");
}
console.log(S);
process.exit(0);
} else {
throw new Error("Invalid Command");
} }
} catch(err) {
console.log(err.stack);
console.log("ERROR: " + err);
process.exit(1);
} }

@ -42,6 +42,3 @@ exports.unstringifyBigInts = require("./src/stringifybigint.js").unstringifyBigI
const Bn128 = require("./src/bn128.js"); const Bn128 = require("./src/bn128.js");
exports.bn128 = new Bn128(); 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

@ -155,6 +155,22 @@
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" "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": { "cli-cursor": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", "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", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz",
"integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==" "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": { "fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "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", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" "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": { "ramda": {
"version": "0.26.1", "version": "0.26.1",
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz",

@ -30,9 +30,11 @@
"dependencies": { "dependencies": {
"big-integer": "^1.6.43", "big-integer": "^1.6.43",
"chai": "^4.2.0", "chai": "^4.2.0",
"circom_runtime": "0.0.1",
"escape-string-regexp": "^1.0.5", "escape-string-regexp": "^1.0.5",
"eslint": "^5.16.0", "eslint": "^5.16.0",
"keccak": "^2.0.0", "keccak": "^2.0.0",
"r1csfile": "0.0.1",
"yargs": "^12.0.5" "yargs": "^12.0.5"
}, },
"devDependencies": { "devDependencies": {

@ -107,7 +107,7 @@ module.exports = class Circuit {
vs = ""; vs = "";
} }
if (vs!="1") { if (vs!="1") {
vs = vs + v.toString();; vs = vs + v.toString();
} }
} }

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

@ -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 res = {};
const fd = fs.openSync(fileName, "r"); const fd = fs.openSync(fileName, "r");
@ -167,11 +167,9 @@ function loadR1csSync(fileName) {
let pConstraints; let pConstraints;
let headerSize; let headerSize;
let constraintsSize; let constraintsSize;
let pMap;
let mapSize;
for (let i=0; i<nSections; i++) { for (let i=0; i<nSections; i++) {
let ht = readU32(); let ht = readU32();
let hl = readDouble64(); let hl = readU64();
if (ht == 1) { if (ht == 1) {
if (typeof pHeader != "undefined") assert(false, "File has two headder sections"); if (typeof pHeader != "undefined") assert(false, "File has two headder sections");
pHeader = p; pHeader = p;
@ -180,17 +178,26 @@ function loadR1csSync(fileName) {
if (typeof pConstraints != "undefined") assert(false, "File has two constraints sections"); if (typeof pConstraints != "undefined") assert(false, "File has two constraints sections");
pConstraints = p; pConstraints = p;
constraintsSize = hl; constraintsSize = hl;
} else if (ht==3) {
pMap = p;
mapSize = hl;
} }
p += 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 // Read Header
p = pHeader; 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 fieldDefSize = readU32();
const pFieldDef = p; 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);
});
});