log functions
This commit is contained in:
parent
75a7b6eb18
commit
406ec9fd62
76
cli.js
76
cli.js
@ -59,7 +59,7 @@ setup command
|
|||||||
|
|
||||||
Default: verification_key.json
|
Default: verification_key.json
|
||||||
|
|
||||||
--protocol [original|groth]
|
--protocol [original|groth|kimleeoh]
|
||||||
|
|
||||||
Defines withc variant of snark you want to use
|
Defines withc variant of snark you want to use
|
||||||
|
|
||||||
@ -94,6 +94,23 @@ calculate witness command
|
|||||||
|
|
||||||
Default: witness.json
|
Default: witness.json
|
||||||
|
|
||||||
|
--lo or --logoutput
|
||||||
|
|
||||||
|
Output all the Output signals
|
||||||
|
|
||||||
|
--lg or --logget
|
||||||
|
|
||||||
|
Output GET access to the signals
|
||||||
|
|
||||||
|
--ls or --logset
|
||||||
|
|
||||||
|
Output SET access to the signal
|
||||||
|
|
||||||
|
--lt or --logtrigger
|
||||||
|
|
||||||
|
Output when a subcomponent is triggered and when finished
|
||||||
|
|
||||||
|
|
||||||
generate a proof command
|
generate a proof command
|
||||||
========================
|
========================
|
||||||
|
|
||||||
@ -225,8 +242,13 @@ print constraints
|
|||||||
.alias("i", "input")
|
.alias("i", "input")
|
||||||
.alias("pub", "public")
|
.alias("pub", "public")
|
||||||
.alias("v", "verifier")
|
.alias("v", "verifier")
|
||||||
|
.alias("lo", "logoutput")
|
||||||
|
.alias("lg", "logget")
|
||||||
|
.alias("ls", "logset")
|
||||||
|
.alias("lt", "logtrigger")
|
||||||
.help("h")
|
.help("h")
|
||||||
.alias("h", "help")
|
.alias("h", "help")
|
||||||
|
|
||||||
.epilogue(`Copyright (C) 2018 0kims association
|
.epilogue(`Copyright (C) 2018 0kims association
|
||||||
This program comes with ABSOLUTELY NO WARRANTY;
|
This program comes with ABSOLUTELY NO WARRANTY;
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
@ -283,7 +305,12 @@ try {
|
|||||||
const cir = new zkSnark.Circuit(cirDef);
|
const cir = new zkSnark.Circuit(cirDef);
|
||||||
const input = unstringifyBigInts(JSON.parse(fs.readFileSync(inputName, "utf8")));
|
const input = unstringifyBigInts(JSON.parse(fs.readFileSync(inputName, "utf8")));
|
||||||
|
|
||||||
const witness = cir.calculateWitness(input);
|
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");
|
fs.writeFileSync(witnessName, JSON.stringify(stringifyBigInts(witness), null, 1), "utf-8");
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
@ -324,6 +351,8 @@ try {
|
|||||||
verifierCode = generateVerifier_original(verificationKey);
|
verifierCode = generateVerifier_original(verificationKey);
|
||||||
} else if (verificationKey.protocol == "groth") {
|
} else if (verificationKey.protocol == "groth") {
|
||||||
verifierCode = generateVerifier_groth(verificationKey);
|
verifierCode = generateVerifier_groth(verificationKey);
|
||||||
|
} else if (verificationKey.protocol == "kimleeoh") {
|
||||||
|
verifierCode = generateVerifier_kimleeoh(verificationKey);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("InvalidProof");
|
throw new Error("InvalidProof");
|
||||||
}
|
}
|
||||||
@ -353,7 +382,7 @@ try {
|
|||||||
`[${p256(proof.pi_h[0])}, ${p256(proof.pi_h[1])}],` +
|
`[${p256(proof.pi_h[0])}, ${p256(proof.pi_h[1])}],` +
|
||||||
`[${p256(proof.pi_kp[0])}, ${p256(proof.pi_kp[1])}],` +
|
`[${p256(proof.pi_kp[0])}, ${p256(proof.pi_kp[1])}],` +
|
||||||
`[${inputs}]`;
|
`[${inputs}]`;
|
||||||
} else if (proof.protocol == "groth") {
|
} else if ((proof.protocol == "groth")||(proof.protocol == "kimleeoh")) {
|
||||||
S=`[${p256(proof.pi_a[0])}, ${p256(proof.pi_a[1])}],` +
|
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_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])}],` +
|
`[${p256(proof.pi_c[0])}, ${p256(proof.pi_c[1])}],` +
|
||||||
@ -394,7 +423,7 @@ function generateVerifier_original(verificationKey) {
|
|||||||
template = template.replace("<%vk_c%>", vkc_str);
|
template = template.replace("<%vk_c%>", vkc_str);
|
||||||
|
|
||||||
const vkg_str = `[${verificationKey.vk_g[0][1].toString()},`+
|
const vkg_str = `[${verificationKey.vk_g[0][1].toString()},`+
|
||||||
`${verificationKey.vk_g[0][0].toString()}], `+
|
`${verificationKey.vk_g[0][0].toString()}], `+
|
||||||
`[${verificationKey.vk_g[1][1].toString()},` +
|
`[${verificationKey.vk_g[1][1].toString()},` +
|
||||||
`${verificationKey.vk_g[1][0].toString()}]`;
|
`${verificationKey.vk_g[1][0].toString()}]`;
|
||||||
template = template.replace("<%vk_g%>", vkg_str);
|
template = template.replace("<%vk_g%>", vkg_str);
|
||||||
@ -472,5 +501,44 @@ function generateVerifier_groth(verificationKey) {
|
|||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateVerifier_kimleeoh(verificationKey) {
|
||||||
|
let template = fs.readFileSync(path.join( __dirname, "templates", "verifier_groth.sol"), "utf-8");
|
||||||
|
|
||||||
|
|
||||||
|
const vkalfa1_str = `${verificationKey.vk_alfa_1[0].toString()},`+
|
||||||
|
`${verificationKey.vk_alfa_1[1].toString()}`;
|
||||||
|
template = template.replace("<%vk_alfa1%>", vkalfa1_str);
|
||||||
|
|
||||||
|
const vkbeta2_str = `[${verificationKey.vk_beta_2[0][1].toString()},`+
|
||||||
|
`${verificationKey.vk_beta_2[0][0].toString()}], `+
|
||||||
|
`[${verificationKey.vk_beta_2[1][1].toString()},` +
|
||||||
|
`${verificationKey.vk_beta_2[1][0].toString()}]`;
|
||||||
|
template = template.replace("<%vk_beta2%>", vkbeta2_str);
|
||||||
|
|
||||||
|
const vkgamma2_str = `[${verificationKey.vk_gamma_2[0][1].toString()},`+
|
||||||
|
`${verificationKey.vk_gamma_2[0][0].toString()}], `+
|
||||||
|
`[${verificationKey.vk_gamma_2[1][1].toString()},` +
|
||||||
|
`${verificationKey.vk_gamma_2[1][0].toString()}]`;
|
||||||
|
template = template.replace("<%vk_gamma2%>", vkgamma2_str);
|
||||||
|
|
||||||
|
const vkdelta2_str = `[${verificationKey.vk_delta_2[0][1].toString()},`+
|
||||||
|
`${verificationKey.vk_delta_2[0][0].toString()}], `+
|
||||||
|
`[${verificationKey.vk_delta_2[1][1].toString()},` +
|
||||||
|
`${verificationKey.vk_delta_2[1][0].toString()}]`;
|
||||||
|
template = template.replace("<%vk_delta2%>", vkdelta2_str);
|
||||||
|
|
||||||
|
// The points
|
||||||
|
|
||||||
|
template = template.replace("<%vk_input_length%>", (verificationKey.IC.length-1).toString());
|
||||||
|
template = template.replace("<%vk_ic_length%>", verificationKey.IC.length.toString());
|
||||||
|
let vi = "";
|
||||||
|
for (let i=0; i<verificationKey.IC.length; i++) {
|
||||||
|
if (vi != "") vi = vi + " ";
|
||||||
|
vi = vi + `vk.IC[${i}] = Pairing.G1Point(${verificationKey.IC[i][0].toString()},`+
|
||||||
|
`${verificationKey.IC[i][1].toString()});\n`;
|
||||||
|
}
|
||||||
|
template = template.replace("<%vk_ic_pts%>", vi);
|
||||||
|
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
5
index.js
5
index.js
@ -28,6 +28,11 @@ exports.groth = {
|
|||||||
genProof: require("./src/prover_groth.js"),
|
genProof: require("./src/prover_groth.js"),
|
||||||
isValid: require("./src/verifier_groth.js")
|
isValid: require("./src/verifier_groth.js")
|
||||||
};
|
};
|
||||||
|
exports.kimleeoh = {
|
||||||
|
setup: require("./src/setup_kimleeoh.js"),
|
||||||
|
genProof: require("./src/prover_kimleeoh.js"),
|
||||||
|
isValid: require("./src/verifier_kimleeoh.js")
|
||||||
|
};
|
||||||
exports.bigInt = require("./src/bigint.js");
|
exports.bigInt = require("./src/bigint.js");
|
||||||
exports.ZqField = require("./src/zqfield.js");
|
exports.ZqField = require("./src/zqfield.js");
|
||||||
|
|
||||||
|
34
package-lock.json
generated
34
package-lock.json
generated
@ -89,6 +89,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.43.tgz",
|
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.43.tgz",
|
||||||
"integrity": "sha512-9dULc9jsKmXl0Aeunug8wbF+58n+hQoFjqClN7WeZwGLh0XJUWyJJ9Ee+Ep+Ql/J9fRsTVaeThp8MhiCCrY0Jg=="
|
"integrity": "sha512-9dULc9jsKmXl0Aeunug8wbF+58n+hQoFjqClN7WeZwGLh0XJUWyJJ9Ee+Ep+Ql/J9fRsTVaeThp8MhiCCrY0Jg=="
|
||||||
},
|
},
|
||||||
|
"bindings": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||||
|
"requires": {
|
||||||
|
"file-uri-to-path": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
@ -452,6 +460,11 @@
|
|||||||
"flat-cache": "^2.0.1"
|
"flat-cache": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"file-uri-to-path": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
|
||||||
|
},
|
||||||
"find-up": {
|
"find-up": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
|
||||||
@ -663,6 +676,17 @@
|
|||||||
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
|
||||||
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
|
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
|
||||||
},
|
},
|
||||||
|
"keccak": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/keccak/-/keccak-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-rKe/lRr0KGhjoz97cwg+oeT1Rj/Y4cjae6glArioUC8JBF9ROGZctwIaaruM7d7naovME4Q8WcQSO908A8qcyQ==",
|
||||||
|
"requires": {
|
||||||
|
"bindings": "^1.2.1",
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"nan": "^2.2.1",
|
||||||
|
"safe-buffer": "^5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"lcid": {
|
"lcid": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
|
||||||
@ -786,6 +810,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
|
||||||
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
|
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
|
||||||
},
|
},
|
||||||
|
"nan": {
|
||||||
|
"version": "2.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
|
||||||
|
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
|
||||||
|
},
|
||||||
"natural-compare": {
|
"natural-compare": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||||
@ -1020,6 +1049,11 @@
|
|||||||
"tslib": "^1.9.0"
|
"tslib": "^1.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
},
|
||||||
"safer-buffer": {
|
"safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"escape-string-regexp": "^1.0.5",
|
"escape-string-regexp": "^1.0.5",
|
||||||
"eslint": "^5.16.0",
|
"eslint": "^5.16.0",
|
||||||
|
"keccak": "^2.0.0",
|
||||||
"yargs": "^12.0.5"
|
"yargs": "^12.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -478,5 +478,32 @@ wBigInt.prototype.leInt2Buff = function (len) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
wBigInt.beBuff2int = function(buff) {
|
||||||
|
let res = wBigInt.zero;
|
||||||
|
for (let i=0; i<buff.length; i++) {
|
||||||
|
const n = wBigInt(buff[buff.length - i - 1]);
|
||||||
|
res = res.add(n.shl(i*8));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
wBigInt.beInt2Buff = function(n, len) {
|
||||||
|
let r = n;
|
||||||
|
let o =len-1;
|
||||||
|
const buff = Buffer.alloc(len);
|
||||||
|
while ((r.greater(wBigInt.zero))&&(o>=0)) {
|
||||||
|
let c = Number(r.and(wBigInt("255")));
|
||||||
|
buff[o] = c;
|
||||||
|
o--;
|
||||||
|
r = r.shr(8);
|
||||||
|
}
|
||||||
|
if (r.greater(wBigInt.zero)) throw new Error("Number does not feed in buffer");
|
||||||
|
return buff;
|
||||||
|
};
|
||||||
|
|
||||||
|
wBigInt.prototype.beInt2Buff = function (len) {
|
||||||
|
return wBigInt.beInt2Buff(this,len);
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = wBigInt;
|
module.exports = wBigInt;
|
||||||
|
|
||||||
|
@ -21,9 +21,10 @@ const bigInt = require("./bigint");
|
|||||||
|
|
||||||
module.exports = calculateWitness;
|
module.exports = calculateWitness;
|
||||||
|
|
||||||
function calculateWitness(circuit, inputSignals, log) {
|
function calculateWitness(circuit, inputSignals, options) {
|
||||||
log = log || (() => {});
|
options = options || {};
|
||||||
const ctx = new RTCtx(circuit, log);
|
if (!options.logFunction) options.logFunction = console.log;
|
||||||
|
const ctx = new RTCtx(circuit, options);
|
||||||
|
|
||||||
function iterateSelector(values, sels, cb) {
|
function iterateSelector(values, sels, cb) {
|
||||||
if (!Array.isArray(values)) {
|
if (!Array.isArray(values)) {
|
||||||
@ -62,15 +63,15 @@ function calculateWitness(circuit, inputSignals, log) {
|
|||||||
if (typeof(ctx.witness[i]) == "undefined") {
|
if (typeof(ctx.witness[i]) == "undefined") {
|
||||||
throw new Error("Signal not assigned: " + circuit.signalNames(i));
|
throw new Error("Signal not assigned: " + circuit.signalNames(i));
|
||||||
}
|
}
|
||||||
log(circuit.signalNames(i) + " --> " + ctx.witness[i].toString());
|
if (options.logOutput) options.logFunction(circuit.signalNames(i) + " --> " + ctx.witness[i].toString());
|
||||||
}
|
}
|
||||||
return ctx.witness.slice(0, circuit.nVars);
|
return ctx.witness.slice(0, circuit.nVars);
|
||||||
// return ctx.witness;
|
// return ctx.witness;
|
||||||
}
|
}
|
||||||
|
|
||||||
class RTCtx {
|
class RTCtx {
|
||||||
constructor(circuit, log) {
|
constructor(circuit, options) {
|
||||||
this.log = log || function() {};
|
this.options = options;
|
||||||
this.scopes = [];
|
this.scopes = [];
|
||||||
this.circuit = circuit;
|
this.circuit = circuit;
|
||||||
this.witness = new Array(circuit.nSignals);
|
this.witness = new Array(circuit.nSignals);
|
||||||
@ -104,8 +105,7 @@ class RTCtx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
triggerComponent(c) {
|
triggerComponent(c) {
|
||||||
this.log("Component Treiggered: " + this.circuit.components[c].name);
|
if (this.options.logTrigger) this.options.logFunction("Component Treiggered: " + this.circuit.components[c].name);
|
||||||
// console.log("Start Component Treiggered: " + this.circuit.components[c].name);
|
|
||||||
|
|
||||||
// Set notInitSignals to -1 to not initialize again
|
// Set notInitSignals to -1 to not initialize again
|
||||||
this.notInitSignals[c] --;
|
this.notInitSignals[c] --;
|
||||||
@ -126,7 +126,8 @@ class RTCtx {
|
|||||||
this.circuit.templates[template](this);
|
this.circuit.templates[template](this);
|
||||||
this.scopes = oldScope;
|
this.scopes = oldScope;
|
||||||
this.currentComponent = oldComponent;
|
this.currentComponent = oldComponent;
|
||||||
// console.log("End Component Treiggered: " + this.circuit.components[c].name);
|
|
||||||
|
if (this.options.logTrigger) this.options.logFunction("End Component Treiggered: " + this.circuit.components[c].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
callFunction(functionName, params) {
|
callFunction(functionName, params) {
|
||||||
@ -149,7 +150,7 @@ class RTCtx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSignalFullName(fullName, value) {
|
setSignalFullName(fullName, value) {
|
||||||
this.log("set " + fullName + " <-- " + value.toString());
|
if (this.options.logSet) this.options.logFunction("set " + fullName + " <-- " + value.toString());
|
||||||
const sId = this.circuit.getSignalIdx(fullName);
|
const sId = this.circuit.getSignalIdx(fullName);
|
||||||
let firstInit =false;
|
let firstInit =false;
|
||||||
if (typeof(this.witness[sId]) == "undefined") {
|
if (typeof(this.witness[sId]) == "undefined") {
|
||||||
@ -218,7 +219,7 @@ class RTCtx {
|
|||||||
if (typeof(this.witness[sId]) == "undefined") {
|
if (typeof(this.witness[sId]) == "undefined") {
|
||||||
throw new Error("Signal not initialized: "+fullName);
|
throw new Error("Signal not initialized: "+fullName);
|
||||||
}
|
}
|
||||||
this.log("get --->" + fullName + " = " + this.witness[sId].toString() );
|
if (this.options.logGet) this.options.logFunction("get --->" + fullName + " = " + this.witness[sId].toString() );
|
||||||
return this.witness[sId];
|
return this.witness[sId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,12 @@ module.exports = function genProof(vk_proof, witness) {
|
|||||||
const r = PolF.F.random();
|
const r = PolF.F.random();
|
||||||
const s = PolF.F.random();
|
const s = PolF.F.random();
|
||||||
|
|
||||||
|
/* Uncomment to generate a deterministic proof to debug
|
||||||
|
const r = PolF.F.zero;
|
||||||
|
const s = PolF.F.zero;
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
proof.pi_a = G1.zero;
|
proof.pi_a = G1.zero;
|
||||||
proof.pi_b = G2.zero;
|
proof.pi_b = G2.zero;
|
||||||
proof.pi_c = G1.zero;
|
proof.pi_c = G1.zero;
|
||||||
@ -71,10 +77,16 @@ module.exports = function genProof(vk_proof, witness) {
|
|||||||
|
|
||||||
const h = calculateH(vk_proof, witness);
|
const h = calculateH(vk_proof, witness);
|
||||||
|
|
||||||
|
// proof.pi_c = G1.affine(proof.pi_c);
|
||||||
|
// console.log("pi_onlyc", proof.pi_c);
|
||||||
|
|
||||||
for (let i = 0; i < h.length; i++) {
|
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.mulScalar( vk_proof.hExps[i], h[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// proof.pi_c = G1.affine(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( 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( pib1, r ));
|
||||||
|
177
src/prover_kimleeoh.js
Normal file
177
src/prover_kimleeoh.js
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 0kims association.
|
||||||
|
|
||||||
|
This file is part of snarkjs.
|
||||||
|
|
||||||
|
snarkjs is a free software: you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
snarkjs is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
snarkjs. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Implementation of this paper: https://eprint.iacr.org/2016/260.pdf */
|
||||||
|
|
||||||
|
const BN128 = require("./bn128.js");
|
||||||
|
const PolField = require("./polfield.js");
|
||||||
|
const ZqField = require("./zqfield.js");
|
||||||
|
const createKeccakHash = require("keccak");
|
||||||
|
const bigInt = require("./bigint");
|
||||||
|
|
||||||
|
const bn128 = new BN128();
|
||||||
|
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 = {};
|
||||||
|
|
||||||
|
const r = PolF.F.random();
|
||||||
|
const s = PolF.F.random();
|
||||||
|
|
||||||
|
// const r = PolF.F.zero;
|
||||||
|
// const s = PolF.F.zero;
|
||||||
|
|
||||||
|
/* Uncomment to generate a deterministic proof to debug
|
||||||
|
const r = PolF.F.zero;
|
||||||
|
const s = PolF.F.zero;
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
proof.pi_a = G1.zero;
|
||||||
|
proof.pi_b = G2.zero;
|
||||||
|
proof.pi_c = G1.zero;
|
||||||
|
|
||||||
|
let pib1 = G1.zero;
|
||||||
|
let piadelta = G1.zero;
|
||||||
|
|
||||||
|
|
||||||
|
// Skip public entries and the "1" signal that are forced by the verifier
|
||||||
|
|
||||||
|
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]));
|
||||||
|
|
||||||
|
// pi_b = pi_b + B[s] * witness[s];
|
||||||
|
proof.pi_b = G2.add( proof.pi_b, G2.mulScalar( 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]));
|
||||||
|
}
|
||||||
|
|
||||||
|
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_a = G1.add( proof.pi_a, vk_proof.vk_alfa_1 );
|
||||||
|
proof.pi_a = G1.add( proof.pi_a, G1.mulScalar( G1.g, r ));
|
||||||
|
|
||||||
|
piadelta = G1.add( piadelta, vk_proof.vk_alfadelta_1);
|
||||||
|
piadelta = G1.add( piadelta, G1.mulScalar( 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 ));
|
||||||
|
|
||||||
|
pib1 = G1.add( pib1, vk_proof.vk_beta_1 );
|
||||||
|
pib1 = G1.add( pib1, G1.mulScalar( G1.g, s ));
|
||||||
|
|
||||||
|
proof.pi_a = G1.affine(proof.pi_a);
|
||||||
|
proof.pi_b = G2.affine(proof.pi_b);
|
||||||
|
|
||||||
|
const buff = Buffer.concat([
|
||||||
|
proof.pi_a[0].beInt2Buff(32),
|
||||||
|
proof.pi_a[1].beInt2Buff(32),
|
||||||
|
proof.pi_b[0][0].beInt2Buff(32),
|
||||||
|
proof.pi_b[0][1].beInt2Buff(32),
|
||||||
|
proof.pi_b[1][0].beInt2Buff(32),
|
||||||
|
proof.pi_b[1][1].beInt2Buff(32)
|
||||||
|
]);
|
||||||
|
|
||||||
|
const h1buff = createKeccakHash("keccak256").update(buff).digest();
|
||||||
|
const h2buff = createKeccakHash("keccak256").update(h1buff).digest();
|
||||||
|
|
||||||
|
const h1 = bigInt.beBuff2int(h1buff);
|
||||||
|
const h2 = bigInt.beBuff2int(h2buff);
|
||||||
|
|
||||||
|
|
||||||
|
// const h1 = PolF.F.zero;
|
||||||
|
// const h2 = PolF.F.zero;
|
||||||
|
|
||||||
|
console.log(h1.toString());
|
||||||
|
console.log(h2.toString());
|
||||||
|
|
||||||
|
const h = calculateH(vk_proof, witness);
|
||||||
|
|
||||||
|
// proof.pi_c = G1.affine(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.affine(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.affine(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)));
|
||||||
|
|
||||||
|
const publicSignals = witness.slice(1, vk_proof.nPublic+1);
|
||||||
|
|
||||||
|
proof.pi_c = G1.affine(proof.pi_c);
|
||||||
|
|
||||||
|
proof.protocol = "kimleeoh";
|
||||||
|
|
||||||
|
return {proof, publicSignals};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function calculateH(vk_proof, witness) {
|
||||||
|
|
||||||
|
const F = PolF.F;
|
||||||
|
const m = vk_proof.domainSize;
|
||||||
|
const polA_T = new Array(m).fill(PolF.F.zero);
|
||||||
|
const polB_T = new Array(m).fill(PolF.F.zero);
|
||||||
|
const polC_T = new Array(m).fill(PolF.F.zero);
|
||||||
|
|
||||||
|
for (let s=0; s<vk_proof.nVars; s++) {
|
||||||
|
for (let c in vk_proof.polsA[s]) {
|
||||||
|
polA_T[c] = F.add(polA_T[c], F.mul(witness[s], vk_proof.polsA[s][c]));
|
||||||
|
}
|
||||||
|
for (let c in vk_proof.polsB[s]) {
|
||||||
|
polB_T[c] = F.add(polB_T[c], F.mul(witness[s], vk_proof.polsB[s][c]));
|
||||||
|
}
|
||||||
|
for (let c in vk_proof.polsC[s]) {
|
||||||
|
polC_T[c] = F.add(polC_T[c], F.mul(witness[s], vk_proof.polsC[s][c]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const polA_S = PolF.ifft(polA_T);
|
||||||
|
const polB_S = PolF.ifft(polB_T);
|
||||||
|
|
||||||
|
const polAB_S = PolF.mul(polA_S, polB_S);
|
||||||
|
|
||||||
|
const polC_S = PolF.ifft(polC_T);
|
||||||
|
|
||||||
|
const polABC_S = PolF.sub(polAB_S, polC_S);
|
||||||
|
|
||||||
|
const H_S = polABC_S.slice(m);
|
||||||
|
|
||||||
|
return H_S;
|
||||||
|
}
|
233
src/setup_kimleeoh.js
Normal file
233
src/setup_kimleeoh.js
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 0kims association.
|
||||||
|
|
||||||
|
This file is part of snarkjs.
|
||||||
|
|
||||||
|
snarkjs is a free software: you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
snarkjs is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
snarkjs. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Implementation of this paper: https://eprint.iacr.org/2016/260.pdf */
|
||||||
|
|
||||||
|
const bigInt = require("./bigint.js");
|
||||||
|
|
||||||
|
const BN128 = require("./bn128.js");
|
||||||
|
const PolField = require("./polfield.js");
|
||||||
|
const ZqField = require("./zqfield.js");
|
||||||
|
|
||||||
|
const bn128 = new BN128();
|
||||||
|
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) {
|
||||||
|
const setup = {
|
||||||
|
vk_proof : {
|
||||||
|
protocol: "groth",
|
||||||
|
nVars: circuit.nVars,
|
||||||
|
nPublic: circuit.nPubInputs + circuit.nOutputs
|
||||||
|
},
|
||||||
|
vk_verifier: {
|
||||||
|
protocol: "groth",
|
||||||
|
nPublic: circuit.nPubInputs + circuit.nOutputs
|
||||||
|
},
|
||||||
|
toxic: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
setup.vk_proof.domainBits = PolF.log2(circuit.nConstraints + circuit.nPubInputs + circuit.nOutputs +1 -1) +1;
|
||||||
|
setup.vk_proof.domainSize = 1 << setup.vk_proof.domainBits;
|
||||||
|
|
||||||
|
calculatePolinomials(setup, circuit);
|
||||||
|
setup.toxic.t = F.random();
|
||||||
|
calculateEncriptedValuesAtT(setup, circuit);
|
||||||
|
|
||||||
|
return setup;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function calculatePolinomials(setup, circuit) {
|
||||||
|
|
||||||
|
setup.vk_proof.polsA = new Array(circuit.nVars);
|
||||||
|
setup.vk_proof.polsB = new Array(circuit.nVars);
|
||||||
|
setup.vk_proof.polsC = new Array(circuit.nVars);
|
||||||
|
for (let i=0; i<circuit.nVars; i++) {
|
||||||
|
setup.vk_proof.polsA[i] = {};
|
||||||
|
setup.vk_proof.polsB[i] = {};
|
||||||
|
setup.vk_proof.polsC[i] = {};
|
||||||
|
}
|
||||||
|
for (let c=0; c<circuit.nConstraints; c++) {
|
||||||
|
|
||||||
|
for (let s in circuit.constraints[c][0]) {
|
||||||
|
setup.vk_proof.polsA[s][c] = bigInt(circuit.constraints[c][0][s]);
|
||||||
|
}
|
||||||
|
for (let s in circuit.constraints[c][1]) {
|
||||||
|
setup.vk_proof.polsB[s][c] = bigInt(circuit.constraints[c][1][s]);
|
||||||
|
}
|
||||||
|
for (let s in circuit.constraints[c][2]) {
|
||||||
|
setup.vk_proof.polsC[s][c] = bigInt(circuit.constraints[c][2][s]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add and process the constraints
|
||||||
|
* input_i * 0 = 0
|
||||||
|
* to ensure soundness of input consistency
|
||||||
|
*/
|
||||||
|
for (let i = 0; i < circuit.nPubInputs + circuit.nOutputs + 1; ++i)
|
||||||
|
{
|
||||||
|
setup.vk_proof.polsA[i][circuit.nConstraints + i] = F.one;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateValuesAtT(setup, circuit) {
|
||||||
|
const z_t = PolF.computeVanishingPolinomial(setup.vk_proof.domainBits, setup.toxic.t);
|
||||||
|
const u = PolF.evaluateLagrangePolynomials(setup.vk_proof.domainBits, setup.toxic.t);
|
||||||
|
|
||||||
|
const a_t = new Array(circuit.nVars).fill(F.zero);
|
||||||
|
const b_t = new Array(circuit.nVars).fill(F.zero);
|
||||||
|
const c_t = new Array(circuit.nVars).fill(F.zero);
|
||||||
|
|
||||||
|
// TODO: substitute setup.polsA for coeficients
|
||||||
|
for (let s=0; s<circuit.nVars; s++) {
|
||||||
|
for (let c in setup.vk_proof.polsA[s]) {
|
||||||
|
a_t[s] = F.add(a_t[s], F.mul(u[c], setup.vk_proof.polsA[s][c]));
|
||||||
|
}
|
||||||
|
for (let c in setup.vk_proof.polsB[s]) {
|
||||||
|
b_t[s] = F.add(b_t[s], F.mul(u[c], setup.vk_proof.polsB[s][c]));
|
||||||
|
}
|
||||||
|
for (let c in setup.vk_proof.polsC[s]) {
|
||||||
|
c_t[s] = F.add(c_t[s], F.mul(u[c], setup.vk_proof.polsC[s][c]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {a_t, b_t, c_t, z_t};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function calculateEncriptedValuesAtT(setup, circuit) {
|
||||||
|
|
||||||
|
const v = calculateValuesAtT(setup, circuit);
|
||||||
|
setup.vk_proof.A = new Array(circuit.nVars);
|
||||||
|
setup.vk_proof.Adelta = new Array(circuit.nVars);
|
||||||
|
setup.vk_proof.B1 = new Array(circuit.nVars);
|
||||||
|
setup.vk_proof.B2 = new Array(circuit.nVars);
|
||||||
|
setup.vk_proof.C = new Array(circuit.nVars);
|
||||||
|
setup.vk_verifier.IC = new Array(circuit.nPublic);
|
||||||
|
|
||||||
|
setup.toxic.kalfa = F.random();
|
||||||
|
setup.toxic.kbeta = F.random();
|
||||||
|
setup.toxic.kgamma = F.random();
|
||||||
|
setup.toxic.kdelta = F.random();
|
||||||
|
|
||||||
|
const gammaSquare = F.mul(setup.toxic.kgamma, setup.toxic.kgamma);
|
||||||
|
|
||||||
|
setup.vk_proof.vk_alfa_1 = G1.affine(G1.mulScalar( G1.g, setup.toxic.kalfa));
|
||||||
|
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_alfadelta_1 = G1.affine(G1.mulScalar( G1.g, F.mul(setup.toxic.kalfa, setup.toxic.kdelta)));
|
||||||
|
|
||||||
|
setup.vk_proof.vk_beta_2 = G2.affine(G2.mulScalar( G2.g, setup.toxic.kbeta));
|
||||||
|
|
||||||
|
|
||||||
|
setup.vk_verifier.vk_alfa_1 = G1.affine(G1.mulScalar( G1.g, setup.toxic.kalfa));
|
||||||
|
|
||||||
|
setup.vk_verifier.vk_beta_2 = G2.affine(G2.mulScalar( G2.g, setup.toxic.kbeta));
|
||||||
|
setup.vk_verifier.vk_gamma_2 = G2.affine(G2.mulScalar( G2.g, setup.toxic.kgamma));
|
||||||
|
setup.vk_verifier.vk_delta_2 = G2.affine(G2.mulScalar( G2.g, setup.toxic.kdelta));
|
||||||
|
|
||||||
|
setup.vk_verifier.vk_alfabeta_12 = bn128.F12.affine(bn128.pairing( setup.vk_verifier.vk_alfa_1 , setup.vk_verifier.vk_beta_2 ));
|
||||||
|
|
||||||
|
for (let s=0; s<circuit.nVars; s++) {
|
||||||
|
|
||||||
|
const A = G1.affine(G1.mulScalar(G1.g, F.mul(setup.toxic.kgamma, v.a_t[s])));
|
||||||
|
|
||||||
|
setup.vk_proof.A[s] = A;
|
||||||
|
setup.vk_proof.Adelta[s] = G1.affine(G1.mulScalar(A, setup.toxic.kdelta));
|
||||||
|
|
||||||
|
const B1 = G1.affine(G1.mulScalar(G1.g, F.mul(setup.toxic.kgamma, v.b_t[s])));
|
||||||
|
|
||||||
|
setup.vk_proof.B1[s] = B1;
|
||||||
|
|
||||||
|
const B2 = G2.affine(G2.mulScalar(G2.g, F.mul(setup.toxic.kgamma, v.b_t[s])));
|
||||||
|
|
||||||
|
setup.vk_proof.B2[s] = B2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let s=0; s<=setup.vk_proof.nPublic; s++) {
|
||||||
|
|
||||||
|
let ps =
|
||||||
|
F.add(
|
||||||
|
F.mul(
|
||||||
|
setup.toxic.kgamma,
|
||||||
|
v.c_t[s]
|
||||||
|
),
|
||||||
|
F.add(
|
||||||
|
F.mul(
|
||||||
|
setup.toxic.kbeta,
|
||||||
|
v.a_t[s]
|
||||||
|
),
|
||||||
|
F.mul(
|
||||||
|
setup.toxic.kalfa,
|
||||||
|
v.b_t[s]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const IC = G1.affine(G1.mulScalar(G1.g, ps));
|
||||||
|
setup.vk_verifier.IC[s]=IC;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let s=setup.vk_proof.nPublic+1; s<circuit.nVars; s++) {
|
||||||
|
let ps =
|
||||||
|
F.add(
|
||||||
|
F.mul(
|
||||||
|
gammaSquare,
|
||||||
|
v.c_t[s]
|
||||||
|
),
|
||||||
|
F.add(
|
||||||
|
F.mul(
|
||||||
|
F.mul(setup.toxic.kbeta, setup.toxic.kgamma),
|
||||||
|
v.a_t[s]
|
||||||
|
),
|
||||||
|
F.mul(
|
||||||
|
F.mul(setup.toxic.kalfa, setup.toxic.kgamma),
|
||||||
|
v.b_t[s]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const C = G1.affine(G1.mulScalar(G1.g, ps));
|
||||||
|
setup.vk_proof.C[s]=C;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate HExps
|
||||||
|
|
||||||
|
const maxH = setup.vk_proof.domainSize+1;
|
||||||
|
|
||||||
|
setup.vk_proof.hExps = new Array(maxH);
|
||||||
|
|
||||||
|
const zod = F.mul(gammaSquare, v.z_t);
|
||||||
|
|
||||||
|
setup.vk_proof.hExps[0] = G1.affine(G1.mulScalar(G1.g, zod));
|
||||||
|
let eT = setup.toxic.t;
|
||||||
|
for (let i=1; i<maxH; i++) {
|
||||||
|
setup.vk_proof.hExps[i] = G1.affine(G1.mulScalar(G1.g, F.mul(eT, zod)));
|
||||||
|
eT = F.mul(eT, setup.toxic.t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
75
src/verifier_kimleeoh.js
Normal file
75
src/verifier_kimleeoh.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 0kims association.
|
||||||
|
|
||||||
|
This file is part of snarkjs.
|
||||||
|
|
||||||
|
snarkjs is a free software: you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
snarkjs is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
snarkjs. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Implementation of this paper: https://eprint.iacr.org/2016/260.pdf */
|
||||||
|
|
||||||
|
|
||||||
|
const BN128 = require("./bn128.js");
|
||||||
|
const createKeccakHash = require("keccak");
|
||||||
|
const bigInt = require("./bigint");
|
||||||
|
|
||||||
|
const bn128 = new BN128();
|
||||||
|
const G1 = bn128.G1;
|
||||||
|
const G2 = bn128.G2;
|
||||||
|
|
||||||
|
module.exports = function isValid(vk_verifier, proof, publicSignals) {
|
||||||
|
|
||||||
|
let cpub = vk_verifier.IC[0];
|
||||||
|
for (let s= 0; s< vk_verifier.nPublic; s++) {
|
||||||
|
cpub = G1.add( cpub, G1.mulScalar( vk_verifier.IC[s+1], publicSignals[s]));
|
||||||
|
}
|
||||||
|
|
||||||
|
const buff = Buffer.concat([
|
||||||
|
proof.pi_a[0].beInt2Buff(32),
|
||||||
|
proof.pi_a[1].beInt2Buff(32),
|
||||||
|
proof.pi_b[0][0].beInt2Buff(32),
|
||||||
|
proof.pi_b[0][1].beInt2Buff(32),
|
||||||
|
proof.pi_b[1][0].beInt2Buff(32),
|
||||||
|
proof.pi_b[1][1].beInt2Buff(32)
|
||||||
|
]);
|
||||||
|
|
||||||
|
const h1buff = createKeccakHash("keccak256").update(buff).digest();
|
||||||
|
const h2buff = createKeccakHash("keccak256").update(h1buff).digest();
|
||||||
|
|
||||||
|
const h1 = bigInt.beBuff2int(h1buff);
|
||||||
|
const h2 = bigInt.beBuff2int(h2buff);
|
||||||
|
|
||||||
|
|
||||||
|
// const h1 = bigInt.zero;
|
||||||
|
// const h2 = bigInt.zero;
|
||||||
|
|
||||||
|
console.log(h1.toString());
|
||||||
|
console.log(h2.toString());
|
||||||
|
|
||||||
|
|
||||||
|
if (! bn128.F12.equals(
|
||||||
|
bn128.pairing(
|
||||||
|
G1.add(proof.pi_a, G1.mulScalar(G1.g, h1)),
|
||||||
|
G2.add(proof.pi_b, G2.mulScalar(vk_verifier.vk_delta_2, h2))
|
||||||
|
),
|
||||||
|
bn128.F12.mul(
|
||||||
|
vk_verifier.vk_alfabeta_12,
|
||||||
|
bn128.F12.mul(
|
||||||
|
bn128.pairing( cpub , vk_verifier.vk_gamma_2 ),
|
||||||
|
bn128.pairing( proof.pi_c , G2.g )
|
||||||
|
))))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
211
templates/verifier_kimleeoh.sol
Normal file
211
templates/verifier_kimleeoh.sol
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2017 Christian Reitwiessner
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
pragma solidity ^0.4.17;
|
||||||
|
library Pairing {
|
||||||
|
struct G1Point {
|
||||||
|
uint X;
|
||||||
|
uint Y;
|
||||||
|
}
|
||||||
|
// Encoding of field elements is: X[0] * z + X[1]
|
||||||
|
struct G2Point {
|
||||||
|
uint[2] X;
|
||||||
|
uint[2] Y;
|
||||||
|
}
|
||||||
|
/// @return the generator of G1
|
||||||
|
function P1() pure internal returns (G1Point) {
|
||||||
|
return G1Point(1, 2);
|
||||||
|
}
|
||||||
|
/// @return the generator of G2
|
||||||
|
function P2() pure internal returns (G2Point) {
|
||||||
|
// Original code point
|
||||||
|
return G2Point(
|
||||||
|
[11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||||
|
10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||||
|
[4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||||
|
8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Changed by Jordi point
|
||||||
|
return G2Point(
|
||||||
|
[10857046999023057135944570762232829481370756359578518086990519993285655852781,
|
||||||
|
11559732032986387107991004021392285783925812861821192530917403151452391805634],
|
||||||
|
[8495653923123431417604973247489272438418190587263600148770280649306958101930,
|
||||||
|
4082367875863433681332203403145435568316851327593401208105741076214120093531]
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
/// @return the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||||
|
function negate(G1Point p) pure internal returns (G1Point) {
|
||||||
|
// The prime q in the base field F_q for G1
|
||||||
|
uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||||
|
if (p.X == 0 && p.Y == 0)
|
||||||
|
return G1Point(0, 0);
|
||||||
|
return G1Point(p.X, q - (p.Y % q));
|
||||||
|
}
|
||||||
|
/// @return the sum of two points of G1
|
||||||
|
function addition(G1Point p1, G1Point p2) view internal returns (G1Point r) {
|
||||||
|
uint[4] memory input;
|
||||||
|
input[0] = p1.X;
|
||||||
|
input[1] = p1.Y;
|
||||||
|
input[2] = p2.X;
|
||||||
|
input[3] = p2.Y;
|
||||||
|
bool success;
|
||||||
|
assembly {
|
||||||
|
success := staticcall(sub(gas, 2000), 6, input, 0xc0, r, 0x60)
|
||||||
|
// Use "invalid" to make gas estimation work
|
||||||
|
switch success case 0 { invalid() }
|
||||||
|
}
|
||||||
|
require(success);
|
||||||
|
}
|
||||||
|
/// @return the product of a point on G1 and a scalar, i.e.
|
||||||
|
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
|
||||||
|
function scalar_mul(G1Point p, uint s) view internal returns (G1Point r) {
|
||||||
|
uint[3] memory input;
|
||||||
|
input[0] = p.X;
|
||||||
|
input[1] = p.Y;
|
||||||
|
input[2] = s;
|
||||||
|
bool success;
|
||||||
|
assembly {
|
||||||
|
success := staticcall(sub(gas, 2000), 7, input, 0x80, r, 0x60)
|
||||||
|
// Use "invalid" to make gas estimation work
|
||||||
|
switch success case 0 { invalid() }
|
||||||
|
}
|
||||||
|
require (success);
|
||||||
|
}
|
||||||
|
/// @return the result of computing the pairing check
|
||||||
|
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||||
|
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should
|
||||||
|
/// return true.
|
||||||
|
function pairing(G1Point[] p1, G2Point[] p2) view internal returns (bool) {
|
||||||
|
require(p1.length == p2.length);
|
||||||
|
uint elements = p1.length;
|
||||||
|
uint inputSize = elements * 6;
|
||||||
|
uint[] memory input = new uint[](inputSize);
|
||||||
|
for (uint i = 0; i < elements; i++)
|
||||||
|
{
|
||||||
|
input[i * 6 + 0] = p1[i].X;
|
||||||
|
input[i * 6 + 1] = p1[i].Y;
|
||||||
|
input[i * 6 + 2] = p2[i].X[0];
|
||||||
|
input[i * 6 + 3] = p2[i].X[1];
|
||||||
|
input[i * 6 + 4] = p2[i].Y[0];
|
||||||
|
input[i * 6 + 5] = p2[i].Y[1];
|
||||||
|
}
|
||||||
|
uint[1] memory out;
|
||||||
|
bool success;
|
||||||
|
assembly {
|
||||||
|
success := staticcall(sub(gas, 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||||
|
// Use "invalid" to make gas estimation work
|
||||||
|
switch success case 0 { invalid() }
|
||||||
|
}
|
||||||
|
require(success);
|
||||||
|
return out[0] != 0;
|
||||||
|
}
|
||||||
|
/// Convenience method for a pairing check for two pairs.
|
||||||
|
function pairingProd2(G1Point a1, G2Point a2, G1Point b1, G2Point b2) view internal returns (bool) {
|
||||||
|
G1Point[] memory p1 = new G1Point[](2);
|
||||||
|
G2Point[] memory p2 = new G2Point[](2);
|
||||||
|
p1[0] = a1;
|
||||||
|
p1[1] = b1;
|
||||||
|
p2[0] = a2;
|
||||||
|
p2[1] = b2;
|
||||||
|
return pairing(p1, p2);
|
||||||
|
}
|
||||||
|
/// Convenience method for a pairing check for three pairs.
|
||||||
|
function pairingProd3(
|
||||||
|
G1Point a1, G2Point a2,
|
||||||
|
G1Point b1, G2Point b2,
|
||||||
|
G1Point c1, G2Point c2
|
||||||
|
) view internal returns (bool) {
|
||||||
|
G1Point[] memory p1 = new G1Point[](3);
|
||||||
|
G2Point[] memory p2 = new G2Point[](3);
|
||||||
|
p1[0] = a1;
|
||||||
|
p1[1] = b1;
|
||||||
|
p1[2] = c1;
|
||||||
|
p2[0] = a2;
|
||||||
|
p2[1] = b2;
|
||||||
|
p2[2] = c2;
|
||||||
|
return pairing(p1, p2);
|
||||||
|
}
|
||||||
|
/// Convenience method for a pairing check for four pairs.
|
||||||
|
function pairingProd4(
|
||||||
|
G1Point a1, G2Point a2,
|
||||||
|
G1Point b1, G2Point b2,
|
||||||
|
G1Point c1, G2Point c2,
|
||||||
|
G1Point d1, G2Point d2
|
||||||
|
) view internal returns (bool) {
|
||||||
|
G1Point[] memory p1 = new G1Point[](4);
|
||||||
|
G2Point[] memory p2 = new G2Point[](4);
|
||||||
|
p1[0] = a1;
|
||||||
|
p1[1] = b1;
|
||||||
|
p1[2] = c1;
|
||||||
|
p1[3] = d1;
|
||||||
|
p2[0] = a2;
|
||||||
|
p2[1] = b2;
|
||||||
|
p2[2] = c2;
|
||||||
|
p2[3] = d2;
|
||||||
|
return pairing(p1, p2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contract Verifier {
|
||||||
|
using Pairing for *;
|
||||||
|
struct VerifyingKey {
|
||||||
|
Pairing.G1Point alfa1;
|
||||||
|
Pairing.G2Point beta2;
|
||||||
|
Pairing.G2Point gamma2;
|
||||||
|
Pairing.G2Point delta2;
|
||||||
|
Pairing.G1Point[] IC;
|
||||||
|
}
|
||||||
|
struct Proof {
|
||||||
|
Pairing.G1Point A;
|
||||||
|
Pairing.G2Point B;
|
||||||
|
Pairing.G1Point C;
|
||||||
|
}
|
||||||
|
function verifyingKey() pure internal returns (VerifyingKey vk) {
|
||||||
|
vk.alfa1 = Pairing.G1Point(<%vk_alfa1%>);
|
||||||
|
vk.beta2 = Pairing.G2Point(<%vk_beta2%>);
|
||||||
|
vk.gamma2 = Pairing.G2Point(<%vk_gamma2%>);
|
||||||
|
vk.delta2 = Pairing.G2Point(<%vk_delta2%>);
|
||||||
|
vk.IC = new Pairing.G1Point[](<%vk_ic_length%>);
|
||||||
|
<%vk_ic_pts%>
|
||||||
|
}
|
||||||
|
function verify(uint[] input, Proof proof) view internal returns (uint) {
|
||||||
|
VerifyingKey memory vk = verifyingKey();
|
||||||
|
require(input.length + 1 == vk.IC.length);
|
||||||
|
// Compute the linear combination vk_x
|
||||||
|
Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
|
||||||
|
for (uint i = 0; i < input.length; i++)
|
||||||
|
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i]));
|
||||||
|
vk_x = Pairing.addition(vk_x, vk.IC[0]);
|
||||||
|
if (!Pairing.pairingProd4(
|
||||||
|
Pairing.negate(proof.A), proof.B,
|
||||||
|
vk.alfa1, vk.beta2,
|
||||||
|
vk_x, vk.gamma2,
|
||||||
|
proof.C, vk.delta2
|
||||||
|
)) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
function verifyProof(
|
||||||
|
uint[2] a,
|
||||||
|
uint[2][2] b,
|
||||||
|
uint[2] c,
|
||||||
|
uint[<%vk_input_length%>] input
|
||||||
|
) view public returns (bool r) {
|
||||||
|
Proof memory proof;
|
||||||
|
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||||
|
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||||
|
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||||
|
uint[] memory inputValues = new uint[](input.length);
|
||||||
|
for(uint i = 0; i < input.length; i++){
|
||||||
|
inputValues[i] = input[i];
|
||||||
|
}
|
||||||
|
if (verify(inputValues, proof) == 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
test/zksnark_kimleeoh.js
Normal file
44
test/zksnark_kimleeoh.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 0kims association.
|
||||||
|
|
||||||
|
This file is part of zksnark JavaScript library.
|
||||||
|
|
||||||
|
zksnark JavaScript library is a free software: you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
zksnark JavaScript library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
zksnark JavaScript library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const chai = require("chai");
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const Circuit = require("../src/circuit.js");
|
||||||
|
const zkSnark = require("../index.js").kimleeoh;
|
||||||
|
|
||||||
|
const assert = chai.assert;
|
||||||
|
|
||||||
|
describe("zkSnark KimLeeOh", () => {
|
||||||
|
it("Load a circuit, create trusted setup, create a proof and validate it", () => {
|
||||||
|
|
||||||
|
|
||||||
|
const cirDef = JSON.parse(fs.readFileSync(path.join(__dirname, "circuit", "sum.json"), "utf8"));
|
||||||
|
const cir = new Circuit(cirDef);
|
||||||
|
|
||||||
|
const setup = zkSnark.setup(cir);
|
||||||
|
|
||||||
|
const witness = cir.calculateWitness({"a": "33", "b": "34"});
|
||||||
|
|
||||||
|
const {proof, publicSignals} = zkSnark.genProof(setup.vk_proof, witness);
|
||||||
|
|
||||||
|
assert( zkSnark.isValid(setup.vk_verifier, proof, publicSignals));
|
||||||
|
}).timeout(10000000);
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user