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
|
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
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
3
index.js
3
index.js
@ -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
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
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 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);
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in New Issue
Block a user