zkSnarks working
This commit is contained in:
parent
0270ceada6
commit
2910b7cf7d
15
README.md
15
README.md
@ -39,7 +39,7 @@ const circuit = new zkSnark.Circuit(circuitDef);
|
|||||||
circuit.nPublic; // number of public signals (nOutputs + nPublicInputs)
|
circuit.nPublic; // number of public signals (nOutputs + nPublicInputs)
|
||||||
|
|
||||||
// The array of signals is always sorted in this order:
|
// The array of signals is always sorted in this order:
|
||||||
// [ outputs, publicInputs, 1, privedInputs, internalSignals, constants]
|
// [ 1, outputs, publicInputs, privedInputs, internalSignals, constants]
|
||||||
|
|
||||||
// returns a,b and c coeficients of the `signalId` on a given `constrain`
|
// returns a,b and c coeficients of the `signalId` on a given `constrain`
|
||||||
circuit.a(constrain, signalId)
|
circuit.a(constrain, signalId)
|
||||||
@ -47,14 +47,19 @@ const circuit = new zkSnark.Circuit(circuitDef);
|
|||||||
circuit.c(constrain, signalId)
|
circuit.c(constrain, signalId)
|
||||||
|
|
||||||
circuit.nOutputs // number of public outputs
|
circuit.nOutputs // number of public outputs
|
||||||
circuit.nPublicInputs // number of public inputs
|
circuit.pubInputs // number of public inputs
|
||||||
circuit.nPrivateInputs // number of private inputs
|
circuit.nPrvInputs // number of private inputs
|
||||||
circuit.nInputs // number of inputs ( nPublicInputs + nPrivateInputs)
|
circuit.nInputs // number of inputs ( nPublicInputs + nPrivateInputs)
|
||||||
|
circuit.nVars // number of variables ( not including constants (one is a variable) )
|
||||||
|
circuit.nSignals // number of signals ( including constants )
|
||||||
|
|
||||||
circuit.outputIdx(i) // returns the index of the i'th output
|
circuit.outputIdx(i) // returns the index of the i'th output
|
||||||
circuit.inputIdx(i) // returns the index of the i'th input
|
circuit.inputIdx(i) // returns the index of the i'th input
|
||||||
circuit.inputPublicIdx(i) // returns the index of the i'th public input
|
circuit.pubInputIdx(i) // returns the index of the i'th public input
|
||||||
circuit.inputPrivateIdx(i) // returns the index of the i'th private input
|
circuit.prvInputIdx(i) // returns the index of the i'th private input
|
||||||
|
circuit.varIdx(i) // returns the index of the i'th variable
|
||||||
|
circuit.constantIdx(i) // returns the index of the i'th constant
|
||||||
|
circuit.signalIdx(i) // returns the index of the i'th signal
|
||||||
|
|
||||||
// returns signal Idx given a signalId
|
// returns signal Idx given a signalId
|
||||||
// if the idx >= n , it is a constant
|
// if the idx >= n , it is a constant
|
||||||
|
@ -55,7 +55,7 @@ class PolFieldZq {
|
|||||||
return this.reduce(res);
|
return this.reduce(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
mulEscalar(a, b) {
|
mulScalar(a, b) {
|
||||||
if (this.F.isZero(b)) return [];
|
if (this.F.isZero(b)) return [];
|
||||||
const res = new Array(a.length);
|
const res = new Array(a.length);
|
||||||
for (let i=0; i<a.length; i++) {
|
for (let i=0; i<a.length; i++) {
|
||||||
@ -67,8 +67,8 @@ class PolFieldZq {
|
|||||||
mul(a, b) {
|
mul(a, b) {
|
||||||
if (a.length == 0) return [];
|
if (a.length == 0) return [];
|
||||||
if (b.length == 0) return [];
|
if (b.length == 0) return [];
|
||||||
if (a.length == 1) return this.mulEscalar(b, a[0]);
|
if (a.length == 1) return this.mulScalar(b, a[0]);
|
||||||
if (b.length == 1) return this.mulEscalar(a, b[0]);
|
if (b.length == 1) return this.mulScalar(a, b[0]);
|
||||||
|
|
||||||
const longestN = Math.max(a.length, b.length);
|
const longestN = Math.max(a.length, b.length);
|
||||||
const bitsResult = log2(longestN-1)+2;
|
const bitsResult = log2(longestN-1)+2;
|
||||||
|
8
index.js
8
index.js
@ -1,4 +1,4 @@
|
|||||||
exports.Circuit = require "./src/circuit.js";
|
exports.Circuit = require("./src/circuit.js");
|
||||||
exports.setup = require "./src/setup.js";
|
exports.setup = require("./src/setup.js");
|
||||||
exports.genProof = require "./src/prover.js";
|
exports.genProof = require("./src/prover.js");
|
||||||
exports.isValid = require "./src/verifier.js";
|
exports.isValid = require("./src/verifier.js");
|
||||||
|
@ -85,6 +85,20 @@ if (typeof(BigInt) != "undefined") {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Shr
|
||||||
|
wBigInt.genShr = () => {
|
||||||
|
return (a,b) => a >> wBigInt(b);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Shl
|
||||||
|
wBigInt.genShl = (q) => {
|
||||||
|
if (q) {
|
||||||
|
return (a,b) => (a << wBigInt(b)) % q;
|
||||||
|
} else {
|
||||||
|
return (a,b) => a << wBigInt(b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Equals
|
// Equals
|
||||||
wBigInt.genEquals = (q) => {
|
wBigInt.genEquals = (q) => {
|
||||||
if (q) {
|
if (q) {
|
||||||
@ -132,18 +146,40 @@ if (typeof(BigInt) != "undefined") {
|
|||||||
return this < wBigInt.zero;
|
return this < wBigInt.zero;
|
||||||
};
|
};
|
||||||
|
|
||||||
wBigInt.prototype.shiftRight = function(f) {
|
wBigInt.prototype.and = function(m) {
|
||||||
return this >> wBigInt(f);
|
return this & m;
|
||||||
|
};
|
||||||
|
|
||||||
|
wBigInt.prototype.mod = function(c) {
|
||||||
|
return this % c;
|
||||||
|
};
|
||||||
|
|
||||||
|
wBigInt.prototype.modPow = function(e, m) {
|
||||||
|
return this ** e % m;
|
||||||
};
|
};
|
||||||
|
|
||||||
wBigInt.prototype.greaterOrEquals = function(b) {
|
wBigInt.prototype.greaterOrEquals = function(b) {
|
||||||
return this >= b;
|
return this >= b;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
wBigInt.prototype.greater = function(b) {
|
||||||
|
return this > b;
|
||||||
|
};
|
||||||
|
wBigInt.prototype.gt = wBigInt.prototype.greater;
|
||||||
|
|
||||||
wBigInt.prototype.lesserOrEquals = function(b) {
|
wBigInt.prototype.lesserOrEquals = function(b) {
|
||||||
return this <= b;
|
return this <= b;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
wBigInt.prototype.lesser = function(b) {
|
||||||
|
return this < b;
|
||||||
|
};
|
||||||
|
wBigInt.prototype.lt = wBigInt.prototype.lesser;
|
||||||
|
|
||||||
|
wBigInt.prototype.equals = function(b) {
|
||||||
|
return this.valueOf == b.valueOf;
|
||||||
|
};
|
||||||
|
wBigInt.prototype.eq = wBigInt.prototype.equals;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -214,6 +250,20 @@ if (typeof(BigInt) != "undefined") {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Shr
|
||||||
|
wBigInt.genShr = () => {
|
||||||
|
return (a,b) => a.shiftRight(wBigInt(b).value);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Shr
|
||||||
|
wBigInt.genShl = (q) => {
|
||||||
|
if (q) {
|
||||||
|
return (a,b) => a.shiftLeft(wBigInt(b).value).mod(q);
|
||||||
|
} else {
|
||||||
|
return (a,b) => a.shiftLeft(wBigInt(b).value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Square
|
// Square
|
||||||
wBigInt.genSquare = (q) => {
|
wBigInt.genSquare = (q) => {
|
||||||
if (q) {
|
if (q) {
|
||||||
@ -301,6 +351,22 @@ wBigInt.prototype.mul = function (a, q) {
|
|||||||
return wBigInt.genMul(q)(this, a);
|
return wBigInt.genMul(q)(this, a);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
wBigInt.shr = function(a, b, q) {
|
||||||
|
return wBigInt.genShr(q)(a,b);
|
||||||
|
};
|
||||||
|
|
||||||
|
wBigInt.prototype.shr = function (a, q) {
|
||||||
|
return wBigInt.genShr(q)(this, a);
|
||||||
|
};
|
||||||
|
|
||||||
|
wBigInt.shl = function(a, b, q) {
|
||||||
|
return wBigInt.genShl(q)(a,b);
|
||||||
|
};
|
||||||
|
|
||||||
|
wBigInt.prototype.shl = function (a, q) {
|
||||||
|
return wBigInt.genShl(q)(this, a);
|
||||||
|
};
|
||||||
|
|
||||||
wBigInt.equals = function(a, b, q) {
|
wBigInt.equals = function(a, b, q) {
|
||||||
return wBigInt.genEquals(q)(a,b);
|
return wBigInt.genEquals(q)(a,b);
|
||||||
};
|
};
|
||||||
|
24
src/bn128.js
24
src/bn128.js
@ -58,14 +58,14 @@ class BN128 {
|
|||||||
this.loop_count_bits = []; // Constant
|
this.loop_count_bits = []; // Constant
|
||||||
while (!lc.isZero()) {
|
while (!lc.isZero()) {
|
||||||
this.loop_count_bits.push( lc.isOdd() );
|
this.loop_count_bits.push( lc.isOdd() );
|
||||||
lc = lc.shiftRight(1);
|
lc = lc.shr(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.two_inv = this.F1.inverse(bigInt(2));
|
this.two_inv = this.F1.inverse(bigInt(2));
|
||||||
|
|
||||||
this.coef_b = bigInt(3);
|
this.coef_b = bigInt(3);
|
||||||
this.twist = [bigInt(9) , bigInt(1)];
|
this.twist = [bigInt(9) , bigInt(1)];
|
||||||
this.twist_coeff_b = this.F2.mulEscalar( this.F2.inverse(this.twist), this.coef_b );
|
this.twist_coeff_b = this.F2.mulScalar( this.F2.inverse(this.twist), this.coef_b );
|
||||||
|
|
||||||
this.frobenius_coeffs_c1_1 = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208582");
|
this.frobenius_coeffs_c1_1 = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208582");
|
||||||
this.twist_mul_by_q_X =
|
this.twist_mul_by_q_X =
|
||||||
@ -179,8 +179,8 @@ class BN128 {
|
|||||||
f = this._mul_by_024(
|
f = this._mul_by_024(
|
||||||
f,
|
f,
|
||||||
c.ell_0,
|
c.ell_0,
|
||||||
this.F2.mulEscalar(c.ell_VW , pre1.PY),
|
this.F2.mulScalar(c.ell_VW , pre1.PY),
|
||||||
this.F2.mulEscalar(c.ell_VV , pre1.PX, ));
|
this.F2.mulScalar(c.ell_VV , pre1.PX, ));
|
||||||
|
|
||||||
if (bit)
|
if (bit)
|
||||||
{
|
{
|
||||||
@ -188,8 +188,8 @@ class BN128 {
|
|||||||
f = this._mul_by_024(
|
f = this._mul_by_024(
|
||||||
f,
|
f,
|
||||||
c.ell_0,
|
c.ell_0,
|
||||||
this.F2.mulEscalar(c.ell_VW, pre1.PY, ),
|
this.F2.mulScalar(c.ell_VW, pre1.PY, ),
|
||||||
this.F2.mulEscalar(c.ell_VV, pre1.PX, ));
|
this.F2.mulScalar(c.ell_VV, pre1.PX, ));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -203,15 +203,15 @@ class BN128 {
|
|||||||
f = this._mul_by_024(
|
f = this._mul_by_024(
|
||||||
f,
|
f,
|
||||||
c.ell_0,
|
c.ell_0,
|
||||||
this.F2.mulEscalar(c.ell_VW, pre1.PY),
|
this.F2.mulScalar(c.ell_VW, pre1.PY),
|
||||||
this.F2.mulEscalar(c.ell_VV, pre1.PX));
|
this.F2.mulScalar(c.ell_VV, pre1.PX));
|
||||||
|
|
||||||
c = pre2.coeffs[idx++];
|
c = pre2.coeffs[idx++];
|
||||||
f = this._mul_by_024(
|
f = this._mul_by_024(
|
||||||
f,
|
f,
|
||||||
c.ell_0,
|
c.ell_0,
|
||||||
this.F2.mulEscalar(c.ell_VW, pre1.PY, ),
|
this.F2.mulScalar(c.ell_VW, pre1.PY, ),
|
||||||
this.F2.mulEscalar(c.ell_VV, pre1.PX));
|
this.F2.mulScalar(c.ell_VV, pre1.PX));
|
||||||
|
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
@ -229,14 +229,14 @@ class BN128 {
|
|||||||
const Y = current.Y;
|
const Y = current.Y;
|
||||||
const Z = current.Z;
|
const Z = current.Z;
|
||||||
|
|
||||||
const A = this.F2.mulEscalar(this.F2.mul(X,Y), this.two_inv); // A = X1 * Y1 / 2
|
const A = this.F2.mulScalar(this.F2.mul(X,Y), this.two_inv); // A = X1 * Y1 / 2
|
||||||
const B = this.F2.square(Y); // B = Y1^2
|
const B = this.F2.square(Y); // B = Y1^2
|
||||||
const C = this.F2.square(Z); // C = Z1^2
|
const C = this.F2.square(Z); // C = Z1^2
|
||||||
const D = this.F2.add(C, this.F2.add(C,C)); // D = 3 * C
|
const D = this.F2.add(C, this.F2.add(C,C)); // D = 3 * C
|
||||||
const E = this.F2.mul(this.twist_coeff_b, D); // E = twist_b * D
|
const E = this.F2.mul(this.twist_coeff_b, D); // E = twist_b * D
|
||||||
const F = this.F2.add(E, this.F2.add(E,E)); // F = 3 * E
|
const F = this.F2.add(E, this.F2.add(E,E)); // F = 3 * E
|
||||||
const G =
|
const G =
|
||||||
this.F2.mulEscalar(
|
this.F2.mulScalar(
|
||||||
this.F2.add( B , F ),
|
this.F2.add( B , F ),
|
||||||
this.two_inv); // G = (B+F)/2
|
this.two_inv); // G = (B+F)/2
|
||||||
const H =
|
const H =
|
||||||
|
209
src/calculateWitness.js
Normal file
209
src/calculateWitness.js
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
const bigInt = require("./bigInt");
|
||||||
|
|
||||||
|
module.exports = calculateWitness;
|
||||||
|
|
||||||
|
function calculateWitness(circuit, inputSignals, log) {
|
||||||
|
log = log || (() => {});
|
||||||
|
const ctx = new RTCtx(circuit, log);
|
||||||
|
|
||||||
|
function iterateSelector(values, sels, cb) {
|
||||||
|
if (!Array.isArray(values)) {
|
||||||
|
return cb(sels, values);
|
||||||
|
}
|
||||||
|
for (let i=0; i<values.length; i++) {
|
||||||
|
sels.push(i);
|
||||||
|
iterateSelector(values[i], sels, cb);
|
||||||
|
sels.pop(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.setSignal("one", [], bigInt(1));
|
||||||
|
|
||||||
|
for (let c in ctx.notInitSignals) {
|
||||||
|
if (ctx.notInitSignals[c] == 0) ctx.triggerComponent(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let s in inputSignals) {
|
||||||
|
ctx.currentComponent = "main";
|
||||||
|
iterateSelector(inputSignals[s], [], function(selector, value) {
|
||||||
|
ctx.setSignal(s, selector, bigInt(value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i=0; i<circuit.nInputs; i++) {
|
||||||
|
const idx = circuit.inputIdx(i);
|
||||||
|
if (typeof(ctx.witness[idx]) == "undefined") {
|
||||||
|
throw new Error("Input Signal not assigned: " + circuit.signalNames(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (let i=0; i<ctx.witness.length; i++) {
|
||||||
|
if (typeof(ctx.witness[i]) == "undefined") {
|
||||||
|
throw new Error("Signal not assigned: " + circuit.signalNames(i));
|
||||||
|
}
|
||||||
|
log(circuit.signalNames(i) + " --> " + ctx.witness[i].toString());
|
||||||
|
}
|
||||||
|
return ctx.witness.slice(0, circuit.nVars);
|
||||||
|
}
|
||||||
|
|
||||||
|
class RTCtx {
|
||||||
|
constructor(circuit, log) {
|
||||||
|
this.log = log || function() {};
|
||||||
|
this.scopes = [];
|
||||||
|
this.circuit = circuit;
|
||||||
|
this.witness = new Array(circuit.nSignals);
|
||||||
|
this.notInitSignals = {};
|
||||||
|
for (let c in this.circuit.components) {
|
||||||
|
this.notInitSignals[c] = this.circuit.components[c].inputSignals;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_sels2str(sels) {
|
||||||
|
let res = "";
|
||||||
|
for (let i=0; i<sels.length; i++) {
|
||||||
|
res += `[${sels[i]}]`;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPin(componentName, componentSels, signalName, signalSels, value) {
|
||||||
|
let fullName = componentName=="one" ? "one" : this.currentComponent + "." + componentName;
|
||||||
|
fullName += this._sels2str(componentSels) +
|
||||||
|
"."+
|
||||||
|
signalName+
|
||||||
|
this._sels2str(signalSels);
|
||||||
|
this.setSignalFullName(fullName, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSignal(name, sels, value) {
|
||||||
|
let fullName = this.currentComponent ? this.currentComponent + "." + name : name;
|
||||||
|
fullName += this._sels2str(sels);
|
||||||
|
this.setSignalFullName(fullName, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerComponent(c) {
|
||||||
|
this.log("Component Treiggered: " + c);
|
||||||
|
|
||||||
|
// Set notInitSignals to -1 to not initialize again
|
||||||
|
this.notInitSignals[c] --;
|
||||||
|
const oldComponent = this.currentComponent;
|
||||||
|
this.currentComponent = this.circuit.components[c].name;
|
||||||
|
const template = this.circuit.components[c].template;
|
||||||
|
|
||||||
|
const newScope = {};
|
||||||
|
for (let p in this.circuit.components[c].params) {
|
||||||
|
newScope[p] = this.circuit.components[c].params[p];
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldScope = this.scopes;
|
||||||
|
this.scopes = [ this.scopes[0], newScope ];
|
||||||
|
|
||||||
|
// TODO set params.
|
||||||
|
|
||||||
|
this.circuit.templates[template](this);
|
||||||
|
this.scopes = oldScope;
|
||||||
|
this.currentComponent = oldComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
callFunction(functionName, params) {
|
||||||
|
|
||||||
|
const newScope = {};
|
||||||
|
for (let p=0; p<this.circuit.functions[functionName].params.length; p++) {
|
||||||
|
const paramName = this.circuit.functions[functionName].params[p];
|
||||||
|
newScope[paramName] = params[p];
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldScope = this.scopes;
|
||||||
|
this.scopes = [ this.scopes[0], newScope ];
|
||||||
|
|
||||||
|
// TODO set params.
|
||||||
|
|
||||||
|
const res = this.circuit.functions[functionName].func(this);
|
||||||
|
this.scopes = oldScope;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSignalFullName(fullName, value) {
|
||||||
|
this.log("set " + fullName + " <-- " + value.toString());
|
||||||
|
const sId = this.circuit.getSignalIdx(fullName);
|
||||||
|
let firstInit =false;
|
||||||
|
if (typeof(this.witness[sId]) == "undefined") {
|
||||||
|
firstInit = true;
|
||||||
|
}
|
||||||
|
this.witness[sId] = value;
|
||||||
|
const callComponents = [];
|
||||||
|
for (let i=0; i<this.circuit.signals[sId].triggerComponents.length; i++) {
|
||||||
|
var idCmp = this.circuit.signals[sId].triggerComponents[i];
|
||||||
|
if (firstInit) this.notInitSignals[idCmp] --;
|
||||||
|
callComponents.push(idCmp);
|
||||||
|
}
|
||||||
|
callComponents.map( (c) => {
|
||||||
|
if (this.notInitSignals[c] == 0) this.triggerComponent(c);
|
||||||
|
});
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
setVar(name, sels, value) {
|
||||||
|
function setVarArray(a, sels2, value) {
|
||||||
|
if (sels2.length == 1) {
|
||||||
|
a[sels2[0]] = value;
|
||||||
|
} else {
|
||||||
|
if (typeof(a[sels2[0]]) == "undefined") a[sels2[0]] = [];
|
||||||
|
setVarArray(a[sels2[0]], sels2.slice(1), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const scope = this.scopes[this.scopes.length-1];
|
||||||
|
if (sels.length == 0) {
|
||||||
|
scope[name] = value;
|
||||||
|
} else {
|
||||||
|
if (typeof(scope[name]) == "undefined") scope[name] = [];
|
||||||
|
setVarArray(scope[name], sels, value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
getVar(name, sels) {
|
||||||
|
function select(a, sels2) {
|
||||||
|
return (sels2.length == 0) ? a : select(a[sels2[0]], sels2.slice(1));
|
||||||
|
}
|
||||||
|
for (let i=this.scopes.length-1; i>=0; i--) {
|
||||||
|
if (typeof(this.scopes[i][name]) != "undefined") return select(this.scopes[i][name], sels);
|
||||||
|
}
|
||||||
|
throw new Error("Variable not defined: " + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSignal(name, sels) {
|
||||||
|
let fullName = name=="one" ? "one" : this.currentComponent + "." + name;
|
||||||
|
fullName += this._sels2str(sels);
|
||||||
|
return this.getSignalFullName(fullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getPin(componentName, componentSels, signalName, signalSels) {
|
||||||
|
let fullName = componentName=="one" ? "one" : this.currentComponent + "." + componentName;
|
||||||
|
fullName += this._sels2str(componentSels) +
|
||||||
|
"."+
|
||||||
|
signalName+
|
||||||
|
this._sels2str(signalSels);
|
||||||
|
return this.getSignalFullName(fullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSignalFullName(fullName) {
|
||||||
|
const sId = this.circuit.getSignalIdx(fullName);
|
||||||
|
if (typeof(this.witness[sId]) == "undefined") {
|
||||||
|
throw new Error("Signal not initialized: "+fullName);
|
||||||
|
}
|
||||||
|
this.log("get --->" + fullName + " = " + this.witness[sId].toString() );
|
||||||
|
return this.witness[sId];
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(a,b) {
|
||||||
|
const ba = bigInt(a);
|
||||||
|
const bb = bigInt(b);
|
||||||
|
if (!ba.equals(bb)) {
|
||||||
|
throw new Error("Constrain doesn't match: " + ba.toString() + " != " + bb.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
100
src/circuit.js
100
src/circuit.js
@ -1,6 +1,106 @@
|
|||||||
|
const bigInt = require("./bigint.js");
|
||||||
|
|
||||||
|
const __P__ = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||||
|
const __MASK__ = bigInt("28948022309329048855892746252171976963317496166410141009864396001978282409983"); // 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||||
|
const calculateWitness = require("./calculateWitness.js");
|
||||||
|
|
||||||
module.exports = class Circuit {
|
module.exports = class Circuit {
|
||||||
constructor(circuitDef) {
|
constructor(circuitDef) {
|
||||||
|
this.nPubInputs = circuitDef.nPubInputs;
|
||||||
|
this.nPrvInputs = circuitDef.nPrvInputs;
|
||||||
|
this.nInputs = circuitDef.nInputs;
|
||||||
|
this.nOutputs = circuitDef.nOutputs;
|
||||||
|
this.nVars = circuitDef.nVars;
|
||||||
|
this.nSignals = circuitDef.nSignals;
|
||||||
|
this.nConstants = circuitDef.nConstants;
|
||||||
|
|
||||||
|
this.nConstrains = circuitDef.constrains.length;
|
||||||
|
|
||||||
|
this.signalName2Idx = circuitDef.signalName2Idx;
|
||||||
|
this.components = circuitDef.components;
|
||||||
|
this.componentName2Idx = circuitDef.componentName2Idx;
|
||||||
|
this.signals = circuitDef.signals;
|
||||||
|
this.constrains = circuitDef.constrains;
|
||||||
|
|
||||||
|
this.templates = {};
|
||||||
|
for (let t in circuitDef.templates) {
|
||||||
|
this.templates[t] = eval(" const __f= " +circuitDef.templates[t] + "\n__f");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.functions = {};
|
||||||
|
for (let f in circuitDef.functions) {
|
||||||
|
this.functions[f] = {
|
||||||
|
params: circuitDef.functions[f].params,
|
||||||
|
func: eval(" const __f= " +circuitDef.functions[f].func + "\n__f;")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateWitness(input) {
|
||||||
|
return calculateWitness(this, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSignalIdx(name) {
|
||||||
|
if (typeof(this.signalName2Idx[name]) != "undefined") return this.signalName2Idx[name];
|
||||||
|
if (!isNaN(name)) return Number(name);
|
||||||
|
throw new Error("Invalid signal identifier: ", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the index of the i'th output
|
||||||
|
outputIdx(i) {
|
||||||
|
if (i>=this.nOutputs) throw new Error("Accessing an invalid output: "+i);
|
||||||
|
return i+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the index of the i'th input
|
||||||
|
inputIdx(i) {
|
||||||
|
if (i>=this.nInputs) throw new Error("Accessing an invalid input: "+i);
|
||||||
|
return this.nOutputs + 1 + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the index of the i'th public input
|
||||||
|
pubInputIdx(i) {
|
||||||
|
if (i>=this.nPubInputs) throw new Error("Accessing an invalid pubInput: "+i);
|
||||||
|
return this.inputIdx(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the index of the i'th private input
|
||||||
|
prvInputIdx(i) {
|
||||||
|
if (i>=this.nPrvInputs) throw new Error("Accessing an invalid prvInput: "+i);
|
||||||
|
return this.inputIdx(this.nPubInputs + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the index of the i'th variable
|
||||||
|
varIdx(i) {
|
||||||
|
if (i>=this.nVars) throw new Error("Accessing an invalid variable: "+i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the index of the i'th constant
|
||||||
|
constantIdx(i) {
|
||||||
|
if (i>=this.nConstants) throw new Error("Accessing an invalid constant: "+i);
|
||||||
|
return this.nVars + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the index of the i'th signal
|
||||||
|
signalIdx(i) {
|
||||||
|
if (i>=this.nSignls) throw new Error("Accessing an invalid signal: "+i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
signalNames(i) {
|
||||||
|
return this.signals[ this.getSignalIdx(i) ].names.join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
a(constrain, signalIdx) {
|
||||||
|
return bigInt(this.constrains[constrain][0][signalIdx] || 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
b(constrain, signalIdx) {
|
||||||
|
return bigInt(this.constrains[constrain][1][signalIdx] || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
c(constrain, signalIdx) {
|
||||||
|
return bigInt(this.constrains[constrain][2][signalIdx] || 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -37,7 +37,7 @@ C.two_inv= F1.inverse(bigInt(2));
|
|||||||
|
|
||||||
C.coef_b = bigInt(3);
|
C.coef_b = bigInt(3);
|
||||||
C.twist = [bigInt(9) , bigInt(1)];
|
C.twist = [bigInt(9) , bigInt(1)];
|
||||||
C.twist_coeff_b = F2.mulEscalar( F2.inverse(C.twist), C.coef_b );
|
C.twist_coeff_b = F2.mulScalar( F2.inverse(C.twist), C.coef_b );
|
||||||
|
|
||||||
|
|
||||||
module.exports = C;
|
module.exports = C;
|
||||||
|
@ -101,8 +101,8 @@ class F2Field {
|
|||||||
return [this.F.affine(a[0]), this.F.affine(a[1])];
|
return [this.F.affine(a[0]), this.F.affine(a[1])];
|
||||||
}
|
}
|
||||||
|
|
||||||
mulEscalar(base, e) {
|
mulScalar(base, e) {
|
||||||
return fUtils.mulEscalar(this, base, e);
|
return fUtils.mulScalar(this, base, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
exp(base, e) {
|
exp(base, e) {
|
||||||
|
@ -141,8 +141,8 @@ class F3Field {
|
|||||||
return [this.F.affine(a[0]), this.F.affine(a[1]), this.F.affine(a[2])];
|
return [this.F.affine(a[0]), this.F.affine(a[1]), this.F.affine(a[2])];
|
||||||
}
|
}
|
||||||
|
|
||||||
mulEscalar(base, e) {
|
mulScalar(base, e) {
|
||||||
return fUtils.mulEscalar(this, base, e);
|
return fUtils.mulScalar(this, base, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
exp(base, e) {
|
exp(base, e) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const bigInt = require("big-integer");
|
const bigInt = require("./bigint.js");
|
||||||
|
|
||||||
exports.mulEscalar = (F, base, e) =>{
|
exports.mulScalar = (F, base, e) =>{
|
||||||
let res = F.zero;
|
let res = F.zero;
|
||||||
let rem = bigInt(e);
|
let rem = bigInt(e);
|
||||||
let exp = base;
|
let exp = base;
|
||||||
@ -10,7 +10,7 @@ exports.mulEscalar = (F, base, e) =>{
|
|||||||
res = F.add(res, exp);
|
res = F.add(res, exp);
|
||||||
}
|
}
|
||||||
exp = F.double(exp);
|
exp = F.double(exp);
|
||||||
rem = rem.shiftRight(1);
|
rem = rem.shr(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -27,7 +27,7 @@ exports.exp = (F, base, e) =>{
|
|||||||
res = F.mul(res, exp);
|
res = F.mul(res, exp);
|
||||||
}
|
}
|
||||||
exp = F.square(exp);
|
exp = F.square(exp);
|
||||||
rem = rem.shiftRight(1);
|
rem = rem.shr(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -68,6 +68,14 @@ class GCurve {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
neg(p) {
|
||||||
|
return [p[0], this.F.neg(p[1]), p[2]];
|
||||||
|
}
|
||||||
|
|
||||||
|
sub(a, b) {
|
||||||
|
return this.add(a, this.neg(b));
|
||||||
|
}
|
||||||
|
|
||||||
double(p) {
|
double(p) {
|
||||||
const res = new Array(3);
|
const res = new Array(3);
|
||||||
|
|
||||||
@ -105,8 +113,8 @@ class GCurve {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
mulEscalar(base, e) {
|
mulScalar(base, e) {
|
||||||
return fUtils.mulEscalar(this, base, e);
|
return fUtils.mulScalar(this, base, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
affine(p) {
|
affine(p) {
|
||||||
|
@ -6,22 +6,24 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const bigInt = require("./bigInt");
|
const bigInt = require("./bigInt");
|
||||||
const ZqField = require("./zqfield");
|
|
||||||
|
|
||||||
class PolFieldZq {
|
class PolFieldZq {
|
||||||
constructor (q) {
|
constructor (F) {
|
||||||
this.F = new ZqField(q);
|
this.F = F;
|
||||||
|
|
||||||
let rem = q.sub(bigInt(1));
|
const q = this.F.q;
|
||||||
|
let rem = q.sub(this.F.one);
|
||||||
let s = 0;
|
let s = 0;
|
||||||
while (!rem.isOdd()) {
|
while (!rem.isOdd()) {
|
||||||
s ++;
|
s ++;
|
||||||
rem = rem.shiftRight(1);
|
rem = rem.shr(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const five = this.F.add(this.F.add(this.F.two, this.F.two), this.F.one);
|
||||||
|
|
||||||
this.w = new Array(s+1);
|
this.w = new Array(s+1);
|
||||||
this.wi = new Array(s+1);
|
this.wi = new Array(s+1);
|
||||||
this.w[s] = this.F.exp(bigInt(5), rem);
|
this.w[s] = this.F.exp(five, rem);
|
||||||
this.wi[s] = this.F.inverse(this.w[s]);
|
this.wi[s] = this.F.inverse(this.w[s]);
|
||||||
|
|
||||||
let n=s-1;
|
let n=s-1;
|
||||||
@ -55,8 +57,9 @@ class PolFieldZq {
|
|||||||
return this.reduce(res);
|
return this.reduce(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
mulEscalar(a, b) {
|
mulScalar(a, b) {
|
||||||
if (this.F.isZero(b)) return [];
|
if (this.F.isZero(b)) return [];
|
||||||
|
if (this.F.equals(b, this.F.one)) return a;
|
||||||
const res = new Array(a.length);
|
const res = new Array(a.length);
|
||||||
for (let i=0; i<a.length; i++) {
|
for (let i=0; i<a.length; i++) {
|
||||||
res[i] = this.F.mul(a[i], b);
|
res[i] = this.F.mul(a[i], b);
|
||||||
@ -64,12 +67,35 @@ class PolFieldZq {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
mul(a, b) {
|
mul(a, b) {
|
||||||
if (a.length == 0) return [];
|
if (a.length == 0) return [];
|
||||||
if (b.length == 0) return [];
|
if (b.length == 0) return [];
|
||||||
if (a.length == 1) return this.mulEscalar(b, a[0]);
|
if (a.length == 1) return this.mulScalar(b, a[0]);
|
||||||
if (b.length == 1) return this.mulEscalar(a, b[0]);
|
if (b.length == 1) return this.mulScalar(a, b[0]);
|
||||||
|
|
||||||
|
if (b.length > a.length) {
|
||||||
|
[b, a] = [a, b];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.length < log2(a.length)) {
|
||||||
|
return this.mulNormal(a,b);
|
||||||
|
} else {
|
||||||
|
return this.mulFFT(a,b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mulNormal(a, b) {
|
||||||
|
let res = [];
|
||||||
|
b = this.affine(b);
|
||||||
|
for (let i=0; i<b.length; i++) {
|
||||||
|
res = this.add(res, this.scaleX(this.mulScalar(a, b[i]), i) );
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
mulFFT(a,b) {
|
||||||
const longestN = Math.max(a.length, b.length);
|
const longestN = Math.max(a.length, b.length);
|
||||||
const bitsResult = log2(longestN-1)+2;
|
const bitsResult = log2(longestN-1)+2;
|
||||||
const m = 1 << bitsResult;
|
const m = 1 << bitsResult;
|
||||||
@ -87,7 +113,7 @@ class PolFieldZq {
|
|||||||
|
|
||||||
const res = this._fft(tres, bitsResult, 0, 1, true);
|
const res = this._fft(tres, bitsResult, 0, 1, true);
|
||||||
|
|
||||||
const twoinvm = this.F.inverse(bigInt(m));
|
const twoinvm = this.F.inverse( this.F.mulScalar(this.F.one, m) );
|
||||||
const resn = new Array(m);
|
const resn = new Array(m);
|
||||||
for (let i=0; i<m; i++) {
|
for (let i=0; i<m; i++) {
|
||||||
resn[i] = this.F.mul(res[(m-i)%m], twoinvm);
|
resn[i] = this.F.mul(res[(m-i)%m], twoinvm);
|
||||||
@ -125,7 +151,22 @@ class PolFieldZq {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lagrange(points) {
|
lagrange(points) {
|
||||||
throw new Error("Not Implementted");
|
let sum = [];
|
||||||
|
for (let i=0; i<points.length; i++) {
|
||||||
|
let mpol = [this.F.one];
|
||||||
|
for (let j=0;j<points.length;j++) {
|
||||||
|
if (i!=j) {
|
||||||
|
mpol = this.mul(mpol, [this.F.neg(points[j][0]), this.F.one]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const factor =
|
||||||
|
this.F.mul(
|
||||||
|
this.F.inverse(this.eval(mpol, points[i][0])),
|
||||||
|
points[i][1]);
|
||||||
|
mpol = this.mulScalar(mpol, factor);
|
||||||
|
sum = this.add(sum, mpol);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
_fft(pall, bits, offset, step) {
|
_fft(pall, bits, offset, step) {
|
||||||
@ -141,7 +182,7 @@ class PolFieldZq {
|
|||||||
|
|
||||||
const out = new Array(n);
|
const out = new Array(n);
|
||||||
|
|
||||||
let m= bigInt(1);
|
let m= this.F.one;
|
||||||
for (let i=0; i<ndiv2; i++) {
|
for (let i=0; i<ndiv2; i++) {
|
||||||
out[i] = this.F.add(p1[i], this.F.mul(m, p2[i]));
|
out[i] = this.F.add(p1[i], this.F.mul(m, p2[i]));
|
||||||
out[i+ndiv2] = this.F.sub(p1[i], this.F.mul(m, p2[i]));
|
out[i+ndiv2] = this.F.sub(p1[i], this.F.mul(m, p2[i]));
|
||||||
@ -262,7 +303,7 @@ class PolFieldZq {
|
|||||||
const s = this._reciprocal(v, kbits);
|
const s = this._reciprocal(v, kbits);
|
||||||
let t;
|
let t;
|
||||||
if (m>2*n) {
|
if (m>2*n) {
|
||||||
t = this.sub(this.scaleX([bigInt(1)], 2*n), this.mul(s, v));
|
t = this.sub(this.scaleX([this.F.one], 2*n), this.mul(s, v));
|
||||||
}
|
}
|
||||||
|
|
||||||
let q = [];
|
let q = [];
|
||||||
|
@ -1,62 +1,58 @@
|
|||||||
const bigInt = require("big-integer");
|
const BN128 = require("./BN128.js");
|
||||||
|
|
||||||
const ZnField = require("./znfield.js");
|
|
||||||
const G1Curve = require("./g1curve");
|
|
||||||
const G2Curve = require("./g2curve");
|
|
||||||
const PolField = require("./polfield.js");
|
const PolField = require("./polfield.js");
|
||||||
|
const ZqField = require("./zqfield.js");
|
||||||
|
|
||||||
const F = new ZnField(bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
|
const bn128 = new BN128();
|
||||||
const G1 = new G1Curve();
|
const PolF = new PolField(new ZqField(bn128.r));
|
||||||
const G2 = new G2Curve();
|
const G1 = bn128.G1;
|
||||||
const PolF = new PolField(F);
|
const G2 = bn128.G2;
|
||||||
|
|
||||||
|
|
||||||
module.exports = function genProof(vk_proof, witness) {
|
module.exports = function genProof(vk_proof, witness) {
|
||||||
|
|
||||||
const proof = {};
|
const proof = {};
|
||||||
|
|
||||||
proof.pi_a = G1.zero();
|
proof.pi_a = G1.zero;
|
||||||
proof.pi_ap = G1.zero();
|
proof.pi_ap = G1.zero;
|
||||||
proof.pi_b = G2.zero();
|
proof.pi_b = G2.zero;
|
||||||
proof.pi_bp = G2.zero();
|
proof.pi_bp = G1.zero;
|
||||||
proof.pi_c = G1.zero();
|
proof.pi_c = G1.zero;
|
||||||
proof.pi_cp = G1.zero();
|
proof.pi_cp = G1.zero;
|
||||||
proof.pi_kp = G1.zero();
|
proof.pi_kp = G1.zero;
|
||||||
proof.pi_h = G1.zero();
|
proof.pi_h = G1.zero;
|
||||||
|
|
||||||
|
|
||||||
// Skip public entries and the "1" signal that are forced by the verifier
|
// Skip public entries and the "1" signal that are forced by the verifier
|
||||||
for (let s= vk_proof.nPublic+1; s< vk_proof.nSignals; s++) {
|
for (let s= vk_proof.nPublic+1; s< vk_proof.nVars; s++) {
|
||||||
|
|
||||||
// pi_a = pi_a + A[s] * witness[s];
|
// pi_a = pi_a + A[s] * witness[s];
|
||||||
proof.pi_a = G1.add( proof.pi_a, G1.mulEscalar( vk_proof.A[s], witness[s]));
|
proof.pi_a = G1.add( proof.pi_a, G1.mulScalar( vk_proof.A[s], witness[s]));
|
||||||
|
|
||||||
// pi_ap = pi_ap + Ap[s] * witness[s];
|
// pi_ap = pi_ap + Ap[s] * witness[s];
|
||||||
proof.pi_ap = G1.add( proof.pi_ap, G1.mulEscalar( vk_proof.Ap[s], witness[s]));
|
proof.pi_ap = G1.add( proof.pi_ap, G1.mulScalar( vk_proof.Ap[s], witness[s]));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let s= 0; s< vk_proof.nSignals; s++) {
|
for (let s= 0; s< vk_proof.nVars; s++) {
|
||||||
// pi_a = pi_a + A[s] * witness[s];
|
// pi_a = pi_a + A[s] * witness[s];
|
||||||
proof.pi_b = G2.add( proof.pi_b, G1.mulEscalar( vk_proof.B[s], witness[s]));
|
proof.pi_b = G2.add( proof.pi_b, G2.mulScalar( vk_proof.B[s], witness[s]));
|
||||||
|
|
||||||
// pi_ap = pi_ap + Ap[s] * witness[s];
|
// pi_ap = pi_ap + Ap[s] * witness[s];
|
||||||
proof.pi_bp = G1.add( proof.pi_bp, G1.mulEscalar( vk_proof.Bp[s], witness[s]));
|
proof.pi_bp = G1.add( proof.pi_bp, G1.mulScalar( vk_proof.Bp[s], witness[s]));
|
||||||
|
|
||||||
// pi_a = pi_a + A[s] * witness[s];
|
// pi_a = pi_a + A[s] * witness[s];
|
||||||
proof.pi_c = G1.add( proof.pi_c, G1.mulEscalar( vk_proof.C[s], witness[s]));
|
proof.pi_c = G1.add( proof.pi_c, G1.mulScalar( vk_proof.C[s], witness[s]));
|
||||||
|
|
||||||
// pi_ap = pi_ap + Ap[s] * witness[s];
|
// pi_ap = pi_ap + Ap[s] * witness[s];
|
||||||
proof.pi_cp = G1.add( proof.pi_cp, G1.mulEscalar( vk_proof.Cp[s], witness[s]));
|
proof.pi_cp = G1.add( proof.pi_cp, G1.mulScalar( vk_proof.Cp[s], witness[s]));
|
||||||
|
|
||||||
// pi_ap = pi_ap + Ap[s] * witness[s];
|
// pi_ap = pi_ap + Ap[s] * witness[s];
|
||||||
proof.pi_kp = G1.add( proof.pi_kp, G1.mulEscalar( vk_proof.Kp[s], witness[s]));
|
proof.pi_kp = G1.add( proof.pi_kp, G1.mulScalar( vk_proof.Kp[s], witness[s]));
|
||||||
}
|
}
|
||||||
|
|
||||||
let polA = [];
|
let polA = [];
|
||||||
let polB = [];
|
let polB = [];
|
||||||
let polC = [];
|
let polC = [];
|
||||||
|
|
||||||
for (let s= 0; s< vk_proof.nSignals; s++) {
|
for (let s= 0; s< vk_proof.nVars; s++) {
|
||||||
polA = PolF.add(
|
polA = PolF.add(
|
||||||
polA,
|
polA,
|
||||||
PolF.mul(
|
PolF.mul(
|
||||||
@ -81,7 +77,19 @@ module.exports = function genProof(vk_proof, witness) {
|
|||||||
const h = PolF.div(polFull, vk_proof.polZ );
|
const h = PolF.div(polFull, vk_proof.polZ );
|
||||||
|
|
||||||
for (let i = 0; i < h.length; i++) {
|
for (let i = 0; i < h.length; i++) {
|
||||||
proof.pi_h = G1.add( proof.pi_h, G1.mulEscalar( vk_proof.hExps[i], h[i]));
|
proof.pi_h = G1.add( proof.pi_h, G1.mulScalar( vk_proof.hExps[i], h[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proof.pi_a = G1.affine(proof.pi_a);
|
||||||
|
proof.pi_b = G2.affine(proof.pi_b);
|
||||||
|
proof.pi_c = G1.affine(proof.pi_c);
|
||||||
|
proof.pi_ap = G1.affine(proof.pi_ap);
|
||||||
|
proof.pi_bp = G1.affine(proof.pi_bp);
|
||||||
|
proof.pi_cp = G1.affine(proof.pi_cp);
|
||||||
|
proof.pi_kp = G1.affine(proof.pi_kp);
|
||||||
|
proof.pi_h = G1.affine(proof.pi_h);
|
||||||
|
|
||||||
|
const publicSignals = witness.slice(1, vk_proof.nPublic+1);
|
||||||
|
|
||||||
|
return {proof, publicSignals};
|
||||||
};
|
};
|
||||||
|
108
src/ratzqfield.js
Normal file
108
src/ratzqfield.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
const fUtils = require("./futils.js");
|
||||||
|
|
||||||
|
class RatZqField {
|
||||||
|
constructor(F) {
|
||||||
|
this.F = F;
|
||||||
|
this.zero = [F.zero, F.one];
|
||||||
|
this.one = [F.one, F.one];
|
||||||
|
this.two = [F.two, F.one];
|
||||||
|
this.twoinv = [F.one, F.two];
|
||||||
|
this.q = F.q;
|
||||||
|
}
|
||||||
|
|
||||||
|
add(a,b) {
|
||||||
|
return [
|
||||||
|
this.F.add(
|
||||||
|
this.F.mul(a[0], b[1]),
|
||||||
|
this.F.mul(a[1], b[0])),
|
||||||
|
this.F.mul(a[1], b[1])];
|
||||||
|
}
|
||||||
|
|
||||||
|
double(a) {
|
||||||
|
return [this.F.add(a[0], a[0]), a[1]];
|
||||||
|
}
|
||||||
|
|
||||||
|
sub(a,b) {
|
||||||
|
return [
|
||||||
|
this.F.sub(
|
||||||
|
this.F.mul(a[0], b[1]),
|
||||||
|
this.F.mul(a[1], b[0])),
|
||||||
|
this.F.mul(a[1], b[1])];
|
||||||
|
}
|
||||||
|
|
||||||
|
neg(a) {
|
||||||
|
return [this.F.neg(a[0]), a[1]];
|
||||||
|
}
|
||||||
|
|
||||||
|
mul(a,b) {
|
||||||
|
return [
|
||||||
|
this.F.mul(a[0], b[0]),
|
||||||
|
this.F.mul(a[1], b[1]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(a) {
|
||||||
|
return [a[0], a[1]];
|
||||||
|
}
|
||||||
|
|
||||||
|
div(a, b) {
|
||||||
|
return [
|
||||||
|
this.F.mul(a[0], b[1]),
|
||||||
|
this.F.mul(a[1], b[0]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
inverse(a) {
|
||||||
|
return [a[1], a[0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
square(a) {
|
||||||
|
return [
|
||||||
|
this.F.square(a[0]),
|
||||||
|
this.F.square(a[1])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
mulScalar(base, e) {
|
||||||
|
return [this.F.mulScalar(base[0], e) , base[1]];
|
||||||
|
}
|
||||||
|
|
||||||
|
exp(base, e) {
|
||||||
|
return fUtils.exp(this, base, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
equals(a, b) {
|
||||||
|
return this.F.equals(
|
||||||
|
this.F.mul(a[0], b[1]),
|
||||||
|
this.F.mul(a[1], b[0])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
isZero(a) {
|
||||||
|
return this.F.isZero(a[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
affine(a) {
|
||||||
|
return [this.F.div(a[0], a[1]), this.F.one];
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(a) {
|
||||||
|
const ca = this.affine(a);
|
||||||
|
return `"0x${ca[0].toString(16)}"`;
|
||||||
|
}
|
||||||
|
|
||||||
|
random() {
|
||||||
|
return [this.F.random(), this.F.one];
|
||||||
|
}
|
||||||
|
|
||||||
|
fromF(a) {
|
||||||
|
return [a, this.F.one];
|
||||||
|
}
|
||||||
|
|
||||||
|
toF(a) {
|
||||||
|
return this.affine(a)[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = RatZqField;
|
101
src/setup.js
101
src/setup.js
@ -1,23 +1,23 @@
|
|||||||
const bigInt = require("big-integer");
|
const bigInt = require("./bigint.js");
|
||||||
|
|
||||||
const ZnField = require("./znfield.js");
|
const BN128 = require("./BN128.js");
|
||||||
const PolField = require("./polfield.js");
|
const PolField = require("./polfield.js");
|
||||||
const G1Curve = require("./g1curve");
|
const ZqField = require("./zqfield.js");
|
||||||
const G2Curve = require("./g2curve");
|
|
||||||
|
|
||||||
const F = new ZnField(bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
|
const bn128 = new BN128();
|
||||||
const PolF = new PolField(F);
|
const G1 = bn128.G1;
|
||||||
const G1 = new G1Curve();
|
const G2 = bn128.G2;
|
||||||
const G2 = new G2Curve();
|
const PolF = new PolField(new ZqField(bn128.r));
|
||||||
|
const F = new ZqField(bn128.r);
|
||||||
|
|
||||||
module.exports = function setup(circuit) {
|
module.exports = function setup(circuit) {
|
||||||
const setup = {
|
const setup = {
|
||||||
vk_proof : {
|
vk_proof : {
|
||||||
nSignals: circuit.nSignals,
|
nVars: circuit.nVars,
|
||||||
nPublic: circuit.nPublic
|
nPublic: circuit.nPubInputs + circuit.nOutputs
|
||||||
},
|
},
|
||||||
vk_verifier: {
|
vk_verifier: {
|
||||||
nPublic: circuit.nPublic
|
nPublic: circuit.nPubInputs + circuit.nOutputs
|
||||||
},
|
},
|
||||||
toxic: {}
|
toxic: {}
|
||||||
};
|
};
|
||||||
@ -26,6 +26,8 @@ module.exports = function setup(circuit) {
|
|||||||
setup.toxic.t = F.random();
|
setup.toxic.t = F.random();
|
||||||
calculateEncriptedValuesAtT(setup, circuit);
|
calculateEncriptedValuesAtT(setup, circuit);
|
||||||
calculateHexps(setup, circuit);
|
calculateHexps(setup, circuit);
|
||||||
|
|
||||||
|
return setup;
|
||||||
};
|
};
|
||||||
|
|
||||||
function calculatePolinomials(setup, circuit) {
|
function calculatePolinomials(setup, circuit) {
|
||||||
@ -33,7 +35,7 @@ function calculatePolinomials(setup, circuit) {
|
|||||||
const aPoints = [];
|
const aPoints = [];
|
||||||
const bPoints = [];
|
const bPoints = [];
|
||||||
const cPoints = [];
|
const cPoints = [];
|
||||||
for (let s = 0; circuit.nSignals; s++) {
|
for (let s = 0; s<circuit.nSignals; s++) {
|
||||||
aPoints[s] = [];
|
aPoints[s] = [];
|
||||||
bPoints[s] = [];
|
bPoints[s] = [];
|
||||||
cPoints[s] = [];
|
cPoints[s] = [];
|
||||||
@ -49,6 +51,7 @@ function calculatePolinomials(setup, circuit) {
|
|||||||
setup.vk_proof.polsB = [];
|
setup.vk_proof.polsB = [];
|
||||||
setup.vk_proof.polsC = [];
|
setup.vk_proof.polsC = [];
|
||||||
for (let s=0; s<circuit.nSignals; s++) {
|
for (let s=0; s<circuit.nSignals; s++) {
|
||||||
|
console.log(`Caclcualte Pol ${s}/${circuit.nSignals}`);
|
||||||
setup.vk_proof.polsA.push(PolF.lagrange( aPoints[s] ));
|
setup.vk_proof.polsA.push(PolF.lagrange( aPoints[s] ));
|
||||||
setup.vk_proof.polsB.push(PolF.lagrange( bPoints[s] ));
|
setup.vk_proof.polsB.push(PolF.lagrange( bPoints[s] ));
|
||||||
setup.vk_proof.polsC.push(PolF.lagrange( cPoints[s] ));
|
setup.vk_proof.polsC.push(PolF.lagrange( cPoints[s] ));
|
||||||
@ -83,56 +86,64 @@ function calculateEncriptedValuesAtT(setup, circuit) {
|
|||||||
|
|
||||||
const gb = F.mul(setup.toxic.kbeta, setup.toxic.kgamma);
|
const gb = F.mul(setup.toxic.kbeta, setup.toxic.kgamma);
|
||||||
|
|
||||||
setup.vk_verifier.vk_a = G2.mulEscalar( G2.g, setup.toxic.ka);
|
setup.vk_verifier.vk_a = G2.affine(G2.mulScalar( G2.g, setup.toxic.ka));
|
||||||
setup.vk_verifier.vk_b = G1.mulEscalar( G1.g, setup.toxic.kb);
|
setup.vk_verifier.vk_b = G1.affine(G1.mulScalar( G1.g, setup.toxic.kb));
|
||||||
setup.vk_verifier.vk_c = G2.mulEscalar( G2.g, setup.toxic.kc);
|
setup.vk_verifier.vk_c = G2.affine(G2.mulScalar( G2.g, setup.toxic.kc));
|
||||||
setup.vk_verifier.vk_gb_1 = G1.mulEscalar( G1.g, gb);
|
setup.vk_verifier.vk_gb_1 = G1.affine(G1.mulScalar( G1.g, gb));
|
||||||
setup.vk_verifier.vk_gb_2 = G2.mulEscalar( G2.g, gb);
|
setup.vk_verifier.vk_gb_2 = G2.affine(G2.mulScalar( G2.g, gb));
|
||||||
setup.vk_verifier.vk_g = G2.mulEscalar( G2.g, setup.toxic.kgamma);
|
setup.vk_verifier.vk_g = G2.affine(G2.mulScalar( G2.g, setup.toxic.kgamma));
|
||||||
|
|
||||||
for (let s=0; s<circuit.nSignals; s++) {
|
for (let s=0; s<circuit.nSignals; s++) {
|
||||||
|
|
||||||
// A[i] = G1 * polA(t)
|
// A[i] = G1 * polA(t)
|
||||||
const A = G1.mulEscalar(
|
const at = PolF.eval(setup.vk_proof.polsA[s], setup.toxic.t);
|
||||||
G1.g,
|
const A = G1.affine(G1.mulScalar(G1.g, at));
|
||||||
PolF.eval(setup.vk_proof.polsA[s], setup.vk_proof.t));
|
|
||||||
setup.vk_proof.A.push(A);
|
setup.vk_proof.A.push(A);
|
||||||
|
|
||||||
if (s < circuit.nPublicSignals) {
|
if (s <= setup.vk_proof.nPublic) {
|
||||||
setup.vk_verifier.A.pusj(A);
|
setup.vk_verifier.A.push(A);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// B1[i] = G1 * polB(t)
|
// B1[i] = G1 * polB(t)
|
||||||
const B1 = G1.mulEscalar(
|
const bt = PolF.eval(setup.vk_proof.polsB[s], setup.toxic.t);
|
||||||
G1.g,
|
const B1 = G1.affine(G1.mulScalar(G1.g, bt));
|
||||||
PolF.eval(setup.vk_proof.polsB[s], setup.vk_proof.t));
|
|
||||||
|
|
||||||
// B2[i] = G2 * polB(t)
|
// B2[i] = G2 * polB(t)
|
||||||
const B2 = G2.mulEscalar(
|
const B2 = G2.affine(G2.mulScalar(G2.g, bt));
|
||||||
G2.g,
|
|
||||||
PolF.eval(setup.vk_proof.polsB[s], setup.vk_proof.t));
|
|
||||||
setup.vk_proof.B.push(B2);
|
setup.vk_proof.B.push(B2);
|
||||||
|
|
||||||
// C[i] = G1 * polC(t)
|
// C[i] = G1 * polC(t)
|
||||||
const C = G1.mulEscalar(
|
const ct = PolF.eval(setup.vk_proof.polsC[s], setup.toxic.t);
|
||||||
G1.g,
|
const C = G1.affine(G1.mulScalar( G1.g, ct));
|
||||||
PolF.eval(setup.vk_proof.polsC[s], setup.vk_proof.t));
|
|
||||||
setup.vk_proof.C.push (C);
|
setup.vk_proof.C.push (C);
|
||||||
|
|
||||||
// K = G1 * (A+B+C)
|
// K = G1 * (A+B+C)
|
||||||
const K = G1.mulEscalar(
|
|
||||||
G1.g,
|
|
||||||
G1.add(G1.add(A, B1), C));
|
|
||||||
|
|
||||||
setup.vk_proof.Ap.push(G1.mulEscalar(A, setup.toxic.ka));
|
const kt = F.add(F.add(at, bt), ct);
|
||||||
setup.vk_proof.Bp.push(G1.mulEscalar(B1, setup.toxic.kb));
|
const K = G1.affine(G1.mulScalar( G1.g, kt));
|
||||||
setup.vk_proof.Cp.push(G1.mulEscalar(C, setup.toxic.kc));
|
|
||||||
setup.vk_proof.Kp.push(G1.mulEscalar(K, setup.toxic.beta));
|
|
||||||
|
|
||||||
|
const Ktest = G1.affine(G1.add(G1.add(A, B1), C));
|
||||||
|
|
||||||
|
if (!G1.equals(K, Ktest)) {
|
||||||
|
console.log ("=====FAIL======");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
setup.vk_proof.Ap.push(G1.affine(G1.mulScalar(A, setup.toxic.ka)));
|
||||||
|
setup.vk_proof.Bp.push(G1.affine(G1.mulScalar(B1, setup.toxic.kb)));
|
||||||
|
setup.vk_proof.Cp.push(G1.affine(G1.mulScalar(C, setup.toxic.kc)));
|
||||||
|
setup.vk_proof.Kp.push(G1.affine(G1.mulScalar(K, setup.toxic.kbeta)));
|
||||||
}
|
}
|
||||||
|
|
||||||
setup.vk_verifier.vk_z = G2.mulEscalar(
|
setup.vk_verifier.vk_z = G2.affine(G2.mulScalar(
|
||||||
G2.g,
|
G2.g,
|
||||||
PolF.eval(setup.vk_proof.polZ, setup.vk_proof.t));
|
PolF.eval(setup.vk_proof.polZ, setup.toxic.t)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateHexps(setup, circuit) {
|
function calculateHexps(setup, circuit) {
|
||||||
@ -140,9 +151,9 @@ function calculateHexps(setup, circuit) {
|
|||||||
let maxB = 0;
|
let maxB = 0;
|
||||||
let maxC = 0;
|
let maxC = 0;
|
||||||
for (let s=0; s<circuit.nSignals; s++) {
|
for (let s=0; s<circuit.nSignals; s++) {
|
||||||
maxA = Math.max(maxA, setup.vk_proof.polsA[s]);
|
maxA = Math.max(maxA, setup.vk_proof.polsA[s].length);
|
||||||
maxB = Math.max(maxB, setup.vk_proof.polsB[s]);
|
maxB = Math.max(maxB, setup.vk_proof.polsB[s].length);
|
||||||
maxC = Math.max(maxC, setup.vk_proof.polsC[s]);
|
maxC = Math.max(maxC, setup.vk_proof.polsC[s].length);
|
||||||
}
|
}
|
||||||
|
|
||||||
let maxFull = Math.max(maxA * maxB - 1, maxC);
|
let maxFull = Math.max(maxA * maxB - 1, maxC);
|
||||||
@ -153,7 +164,7 @@ function calculateHexps(setup, circuit) {
|
|||||||
setup.vk_proof.hExps[0] = G1.g;
|
setup.vk_proof.hExps[0] = G1.g;
|
||||||
let eT = setup.toxic.t;
|
let eT = setup.toxic.t;
|
||||||
for (let i=1; i<maxH; i++) {
|
for (let i=1; i<maxH; i++) {
|
||||||
setup.vk_proof.hExps[i] = G1.mulEscalar(G1.g, eT);
|
setup.vk_proof.hExps[i] = G1.affine(G1.mulScalar(G1.g, eT));
|
||||||
eT = F.mul(eT, setup.toxic.t);
|
eT = F.mul(eT, setup.toxic.t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,52 +1,52 @@
|
|||||||
const G1Curve = require("./g1curve");
|
const BN128 = require("./BN128.js");
|
||||||
const G2Curve = require("./g2curve");
|
|
||||||
const GT = require("./gt");
|
|
||||||
|
|
||||||
const G1 = new G1Curve();
|
const bn128 = new BN128();
|
||||||
const G2 = new G2Curve();
|
const G1 = bn128.G1;
|
||||||
const Gt = new GT();
|
const G2 = bn128.G2;
|
||||||
|
|
||||||
const pairing = require("./pairing");
|
const pairing = bn128.pairing;
|
||||||
|
|
||||||
module.exports = function isValid(vk_verifier, proof, publicSignals) {
|
module.exports = function isValid(vk_verifier, proof, publicSignals) {
|
||||||
|
|
||||||
|
let full_pi_a = vk_verifier.A[0];
|
||||||
for (let s= 0; s< vk_verifier.nPublic; s++) {
|
for (let s= 0; s< vk_verifier.nPublic; s++) {
|
||||||
full_pi_a = G1.add( full_pi_a, G1.mulEscalar( vk_verifier.A[s], publicSignals[s]));
|
full_pi_a = G1.add( full_pi_a, G1.mulScalar( vk_verifier.A[s+1], publicSignals[s]));
|
||||||
}
|
}
|
||||||
|
|
||||||
let full_pi_a = G1.add(proof.pi_a, vk_verifier.A[vk_verifier.nPublic]);
|
full_pi_a = G1.add( full_pi_a, proof.pi_a);
|
||||||
|
|
||||||
if (! Gt.equal(
|
if (! bn128.F12.equals(
|
||||||
pairing( proof.pi_a , vk_verifier.vk_a ),
|
bn128.pairing( proof.pi_a , vk_verifier.vk_a ),
|
||||||
pairing( proof.pi_ap , G2.g )))
|
bn128.pairing( proof.pi_ap , G2.g )))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (! Gt.equal(
|
if (! bn128.F12.equals(
|
||||||
pairing( vk_verifier.vk_b, proof.pi_b ),
|
bn128.pairing( vk_verifier.vk_b, proof.pi_b ),
|
||||||
pairing( proof.pi_ap , G2.g )))
|
bn128.pairing( proof.pi_bp , G2.g )))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (! Gt.equal(
|
if (! bn128.F12.equals(
|
||||||
pairing( proof.pi_c , vk_verifier.vk_c ),
|
bn128.pairing( proof.pi_c , vk_verifier.vk_c ),
|
||||||
pairing( proof.pi_cp , G2.g )))
|
bn128.pairing( proof.pi_cp , G2.g )))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (! Gt.equal(
|
if (! bn128.F12.equals(
|
||||||
pairing( full_pi_a , proof.pi_b ),
|
bn128.pairing( full_pi_a , proof.pi_b ),
|
||||||
Gt.mul(
|
bn128.F12.mul(
|
||||||
pairing( proof.pi_h , vk_verifier.vk_z ),
|
bn128.pairing( proof.pi_h , vk_verifier.vk_z ),
|
||||||
pairing( proof.pi_b , G2.g ),
|
bn128.pairing( proof.pi_c , G2.g ),
|
||||||
|
)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (! bn128.F12.equals(
|
||||||
|
bn128.F12.mul(
|
||||||
|
bn128.pairing( G1.add(full_pi_a, proof.pi_c) , vk_verifier.vk_gb_2 ),
|
||||||
|
bn128.pairing( vk_verifier.vk_gb_1 , proof.pi_b ),
|
||||||
),
|
),
|
||||||
pairing( proof.pi_kp , vk_verifier.vk_g )))
|
bn128.pairing( proof.pi_kp , vk_verifier.vk_g )))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (! Gt.equal(
|
|
||||||
Gt.mul(
|
|
||||||
pairing( G1.add(full_pi_a, proof.pi_c) , vk_verifier.vk_gb_2 ),
|
|
||||||
pairing( vk_verifier.vk_gb_1 , proof.pi_b ),
|
|
||||||
),
|
|
||||||
pairing( proof.pi_kp , vk_verifier.vk_g )))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
const crypto = require("crypto");
|
||||||
|
|
||||||
const bigInt = require("./bigint");
|
const bigInt = require("./bigint");
|
||||||
const fUtils = require("./futils.js");
|
const fUtils = require("./futils.js");
|
||||||
|
|
||||||
@ -28,8 +30,8 @@ class ZqField {
|
|||||||
return this.mul(a, this.inverse(b));
|
return this.mul(a, this.inverse(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
mulEscalar(base, e) {
|
mulScalar(base, e) {
|
||||||
return fUtils.mulEscalar(this, base, e);
|
return this.mul(base, bigInt(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
exp(base, e) {
|
exp(base, e) {
|
||||||
@ -40,6 +42,16 @@ class ZqField {
|
|||||||
const ca = this.affine(a);
|
const ca = this.affine(a);
|
||||||
return `"0x${ca.toString(16)}"`;
|
return `"0x${ca.toString(16)}"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
random() {
|
||||||
|
let res = bigInt(0);
|
||||||
|
let n = bigInt(this.q);
|
||||||
|
while (!n.isZero()) {
|
||||||
|
res = res.shl(8).add(bigInt(crypto.randomBytes(1)[0]));
|
||||||
|
n = n.shr(8);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ describe("Curve G1 Test", () => {
|
|||||||
it("r*one == 0", () => {
|
it("r*one == 0", () => {
|
||||||
const bn128 = new BN128();
|
const bn128 = new BN128();
|
||||||
|
|
||||||
const res = bn128.G1.mulEscalar(bn128.G1.g, bn128.r);
|
const res = bn128.G1.mulScalar(bn128.G1.g, bn128.r);
|
||||||
|
|
||||||
assert(bn128.G1.equals(res, bn128.G1.zero), "G1 does not have range r");
|
assert(bn128.G1.equals(res, bn128.G1.zero), "G1 does not have range r");
|
||||||
});
|
});
|
||||||
@ -43,12 +43,12 @@ describe("Curve G1 Test", () => {
|
|||||||
const r1 = bigInt(33);
|
const r1 = bigInt(33);
|
||||||
const r2 = bigInt(44);
|
const r2 = bigInt(44);
|
||||||
|
|
||||||
const gr1 = bn128.G1.mulEscalar(bn128.G1.g, r1);
|
const gr1 = bn128.G1.mulScalar(bn128.G1.g, r1);
|
||||||
const gr2 = bn128.G1.mulEscalar(bn128.G1.g, r2);
|
const gr2 = bn128.G1.mulScalar(bn128.G1.g, r2);
|
||||||
|
|
||||||
const grsum1 = bn128.G1.add(gr1, gr2);
|
const grsum1 = bn128.G1.add(gr1, gr2);
|
||||||
|
|
||||||
const grsum2 = bn128.G1.mulEscalar(bn128.G1.g, r1.add(r2));
|
const grsum2 = bn128.G1.mulScalar(bn128.G1.g, r1.add(r2));
|
||||||
|
|
||||||
assert(bn128.G1.equals(grsum1, grsum2));
|
assert(bn128.G1.equals(grsum1, grsum2));
|
||||||
});
|
});
|
||||||
@ -58,7 +58,7 @@ describe("Curve G2 Test", () => {
|
|||||||
it ("r*one == 0", () => {
|
it ("r*one == 0", () => {
|
||||||
const bn128 = new BN128();
|
const bn128 = new BN128();
|
||||||
|
|
||||||
const res = bn128.G2.mulEscalar(bn128.G2.g, bn128.r);
|
const res = bn128.G2.mulScalar(bn128.G2.g, bn128.r);
|
||||||
|
|
||||||
assert(bn128.G2.equals(res, bn128.G2.zero), "G2 does not have range r");
|
assert(bn128.G2.equals(res, bn128.G2.zero), "G2 does not have range r");
|
||||||
});
|
});
|
||||||
@ -69,12 +69,12 @@ describe("Curve G2 Test", () => {
|
|||||||
const r1 = bigInt(33);
|
const r1 = bigInt(33);
|
||||||
const r2 = bigInt(44);
|
const r2 = bigInt(44);
|
||||||
|
|
||||||
const gr1 = bn128.G2.mulEscalar(bn128.G2.g, r1);
|
const gr1 = bn128.G2.mulScalar(bn128.G2.g, r1);
|
||||||
const gr2 = bn128.G2.mulEscalar(bn128.G2.g, r2);
|
const gr2 = bn128.G2.mulScalar(bn128.G2.g, r2);
|
||||||
|
|
||||||
const grsum1 = bn128.G2.add(gr1, gr2);
|
const grsum1 = bn128.G2.add(gr1, gr2);
|
||||||
|
|
||||||
const grsum2 = bn128.G2.mulEscalar(bn128.G2.g, r1.add(r2));
|
const grsum2 = bn128.G2.mulScalar(bn128.G2.g, r1.add(r2));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
console.log(G2.toString(grsum1));
|
console.log(G2.toString(grsum1));
|
||||||
@ -148,11 +148,11 @@ describe("Pairing", () => {
|
|||||||
for (let i=0; i<1; i++) {
|
for (let i=0; i<1; i++) {
|
||||||
const bn128 = new BN128();
|
const bn128 = new BN128();
|
||||||
|
|
||||||
const g1a = bn128.G1.mulEscalar(bn128.G1.g, 25);
|
const g1a = bn128.G1.mulScalar(bn128.G1.g, 25);
|
||||||
const g2a = bn128.G2.mulEscalar(bn128.G2.g, 30);
|
const g2a = bn128.G2.mulScalar(bn128.G2.g, 30);
|
||||||
|
|
||||||
const g1b = bn128.G1.mulEscalar(bn128.G1.g, 30);
|
const g1b = bn128.G1.mulScalar(bn128.G1.g, 30);
|
||||||
const g2b = bn128.G2.mulEscalar(bn128.G2.g, 25);
|
const g2b = bn128.G2.mulScalar(bn128.G2.g, 25);
|
||||||
|
|
||||||
const pre1a = bn128.precomputeG1(g1a);
|
const pre1a = bn128.precomputeG1(g1a);
|
||||||
const pre2a = bn128.precomputeG2(g2a);
|
const pre2a = bn128.precomputeG2(g2a);
|
||||||
|
20
test/calculatewitness.js
Normal file
20
test/calculatewitness.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
const chai = require("chai");
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
const Circuit = require("../src/circuit.js");
|
||||||
|
const BN128 = require("../src/BN128.js");
|
||||||
|
const F1Field = require("../src/zqfield.js");
|
||||||
|
|
||||||
|
const assert = chai.assert;
|
||||||
|
|
||||||
|
|
||||||
|
describe("Calculate witness", () => {
|
||||||
|
it("Should calculate the witness of a sum circuit", () => {
|
||||||
|
|
||||||
|
const cirDef = JSON.parse(fs.readFileSync("../jaz/sum.json", "utf8"));
|
||||||
|
const cir = new Circuit(cirDef);
|
||||||
|
const witness = cir.calculateWitness({"a": "33", "b": "34"});
|
||||||
|
|
||||||
|
assert.equal(witness[cir.getSignalIdx("main.out")].toString(), "67");
|
||||||
|
});
|
||||||
|
});
|
60
test/pols.js
60
test/pols.js
@ -2,6 +2,7 @@ const chai = require("chai");
|
|||||||
|
|
||||||
const bigInt = require("../src/bigint.js");
|
const bigInt = require("../src/bigint.js");
|
||||||
const PolField = require("../src/polfield.js");
|
const PolField = require("../src/polfield.js");
|
||||||
|
const ZqField = require("../src/zqfield");
|
||||||
|
|
||||||
const assert = chai.assert;
|
const assert = chai.assert;
|
||||||
|
|
||||||
@ -9,7 +10,7 @@ const r = bigInt("2188824287183927522224640574525727508854836440041603434369820
|
|||||||
|
|
||||||
describe("Polinomial field", () => {
|
describe("Polinomial field", () => {
|
||||||
it("Should compute a multiplication", () => {
|
it("Should compute a multiplication", () => {
|
||||||
const PF = new PolField(r);
|
const PF = new PolField(new ZqField(r));
|
||||||
|
|
||||||
const a = [bigInt(1), bigInt(2), bigInt(3)];
|
const a = [bigInt(1), bigInt(2), bigInt(3)];
|
||||||
const b = [bigInt(1), bigInt(2), bigInt(3)];
|
const b = [bigInt(1), bigInt(2), bigInt(3)];
|
||||||
@ -18,7 +19,7 @@ describe("Polinomial field", () => {
|
|||||||
assert(PF.equals(res, [bigInt(1), bigInt(4), bigInt(10), bigInt(12), bigInt(9)]));
|
assert(PF.equals(res, [bigInt(1), bigInt(4), bigInt(10), bigInt(12), bigInt(9)]));
|
||||||
});
|
});
|
||||||
it("Should compute a multiplication 2", () => {
|
it("Should compute a multiplication 2", () => {
|
||||||
const PF = new PolField(r);
|
const PF = new PolField(new ZqField(r));
|
||||||
|
|
||||||
const a = [bigInt(5), bigInt(1)];
|
const a = [bigInt(5), bigInt(1)];
|
||||||
const b = [bigInt(-5), bigInt(1)];
|
const b = [bigInt(-5), bigInt(1)];
|
||||||
@ -27,7 +28,7 @@ describe("Polinomial field", () => {
|
|||||||
assert(PF.equals(res, [bigInt(-25), bigInt(0), bigInt(1)]));
|
assert(PF.equals(res, [bigInt(-25), bigInt(0), bigInt(1)]));
|
||||||
});
|
});
|
||||||
it("Should compute an addition", () => {
|
it("Should compute an addition", () => {
|
||||||
const PF = new PolField(r);
|
const PF = new PolField(new ZqField(r));
|
||||||
|
|
||||||
const a = [bigInt(5), bigInt(1)];
|
const a = [bigInt(5), bigInt(1)];
|
||||||
const b = [bigInt(-5), bigInt(1)];
|
const b = [bigInt(-5), bigInt(1)];
|
||||||
@ -36,7 +37,7 @@ describe("Polinomial field", () => {
|
|||||||
assert(PF.equals(res, [bigInt(0), bigInt(2)]));
|
assert(PF.equals(res, [bigInt(0), bigInt(2)]));
|
||||||
});
|
});
|
||||||
it("Should compute a substraction", () => {
|
it("Should compute a substraction", () => {
|
||||||
const PF = new PolField(r);
|
const PF = new PolField(new ZqField(r));
|
||||||
|
|
||||||
const a = [bigInt(5), bigInt(3), bigInt(4)];
|
const a = [bigInt(5), bigInt(3), bigInt(4)];
|
||||||
const b = [bigInt(5), bigInt(1)];
|
const b = [bigInt(5), bigInt(1)];
|
||||||
@ -45,7 +46,7 @@ describe("Polinomial field", () => {
|
|||||||
assert(PF.equals(res, [bigInt(0), bigInt(2), bigInt(4)]));
|
assert(PF.equals(res, [bigInt(0), bigInt(2), bigInt(4)]));
|
||||||
});
|
});
|
||||||
it("Should compute reciprocal", () => {
|
it("Should compute reciprocal", () => {
|
||||||
const PF = new PolField(r);
|
const PF = new PolField(new ZqField(r));
|
||||||
|
|
||||||
const a = [bigInt(4), bigInt(1), bigInt(-3), bigInt(-1), bigInt(2),bigInt(1), bigInt(-1), bigInt(1)];
|
const a = [bigInt(4), bigInt(1), bigInt(-3), bigInt(-1), bigInt(2),bigInt(1), bigInt(-1), bigInt(1)];
|
||||||
const res = PF._reciprocal(a, 3, 0);
|
const res = PF._reciprocal(a, 3, 0);
|
||||||
@ -53,7 +54,7 @@ describe("Polinomial field", () => {
|
|||||||
assert(PF.equals(res, [bigInt(12), bigInt(15), bigInt(3), bigInt(-4), bigInt(-3), bigInt(0), bigInt(1), bigInt(1)]));
|
assert(PF.equals(res, [bigInt(12), bigInt(15), bigInt(3), bigInt(-4), bigInt(-3), bigInt(0), bigInt(1), bigInt(1)]));
|
||||||
});
|
});
|
||||||
it("Should div2", () => {
|
it("Should div2", () => {
|
||||||
const PF = new PolField(r);
|
const PF = new PolField(new ZqField(r));
|
||||||
|
|
||||||
// x^6
|
// x^6
|
||||||
const a = [bigInt(0), bigInt(0), bigInt(0), bigInt(0), bigInt(0),bigInt(0), bigInt(1)];
|
const a = [bigInt(0), bigInt(0), bigInt(0), bigInt(0), bigInt(0),bigInt(0), bigInt(1)];
|
||||||
@ -67,7 +68,7 @@ describe("Polinomial field", () => {
|
|||||||
assert(PF.equals(res2, [bigInt(0), bigInt(1)]));
|
assert(PF.equals(res2, [bigInt(0), bigInt(1)]));
|
||||||
});
|
});
|
||||||
it("Should div", () => {
|
it("Should div", () => {
|
||||||
const PF = new PolField(r);
|
const PF = new PolField(new ZqField(r));
|
||||||
|
|
||||||
const a = [bigInt(1), bigInt(2), bigInt(3), bigInt(4), bigInt(5),bigInt(6), bigInt(7)];
|
const a = [bigInt(1), bigInt(2), bigInt(3), bigInt(4), bigInt(5),bigInt(6), bigInt(7)];
|
||||||
const b = [bigInt(8), bigInt(9), bigInt(10), bigInt(11), bigInt(12), bigInt(13)];
|
const b = [bigInt(8), bigInt(9), bigInt(10), bigInt(11), bigInt(12), bigInt(13)];
|
||||||
@ -79,7 +80,7 @@ describe("Polinomial field", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("Should div big/small", () => {
|
it("Should div big/small", () => {
|
||||||
const PF = new PolField(r);
|
const PF = new PolField(new ZqField(r));
|
||||||
|
|
||||||
const a = [bigInt(1), bigInt(2), bigInt(3), bigInt(4), bigInt(5),bigInt(6), bigInt(7)];
|
const a = [bigInt(1), bigInt(2), bigInt(3), bigInt(4), bigInt(5),bigInt(6), bigInt(7)];
|
||||||
const b = [bigInt(8), bigInt(9)];
|
const b = [bigInt(8), bigInt(9)];
|
||||||
@ -90,18 +91,55 @@ describe("Polinomial field", () => {
|
|||||||
assert(PF.equals(a, d));
|
assert(PF.equals(a, d));
|
||||||
});
|
});
|
||||||
it("Should div random big", () => {
|
it("Should div random big", () => {
|
||||||
const PF = new PolField(r);
|
const PF = new PolField(new ZqField(r));
|
||||||
|
|
||||||
const a = [];
|
const a = [];
|
||||||
const b = [];
|
const b = [];
|
||||||
for (let i=0; i<1000; i++) a.push(bigInt(Math.floor(Math.random()*100000) -500000));
|
for (let i=0; i<1000; i++) a.push(bigInt(Math.floor(Math.random()*100000) -500000));
|
||||||
for (let i=0; i<300; i++) b.push(bigInt(Math.floor(Math.random()*100000) -500000));
|
for (let i=0; i<900; i++) b.push(bigInt(Math.floor(Math.random()*100000) -500000));
|
||||||
|
|
||||||
const c = PF.mul(a,b);
|
const c = PF.mul(a,b);
|
||||||
|
|
||||||
const d = PF.div(c,b);
|
const d = PF.div(c,b);
|
||||||
|
|
||||||
assert(PF.equals(a, d));
|
assert(PF.equals(a, d));
|
||||||
}).timeout(10000000);
|
}).timeout(10000);
|
||||||
|
it("Should evaluate and zero", () => {
|
||||||
|
const PF = new PolField(new ZqField(r));
|
||||||
|
const p = [PF.F.neg(bigInt(2)), bigInt(1)];
|
||||||
|
const v = PF.eval(p, bigInt(2));
|
||||||
|
assert(PF.F.equals(v, bigInt(0)));
|
||||||
|
});
|
||||||
|
it("Should create lagrange polynomial minmal", () => {
|
||||||
|
const PF = new PolField(new ZqField(r));
|
||||||
|
|
||||||
|
const points=[];
|
||||||
|
points.push([bigInt(1), bigInt(1)]);
|
||||||
|
points.push([bigInt(2), bigInt(2)]);
|
||||||
|
points.push([bigInt(3), bigInt(5)]);
|
||||||
|
|
||||||
|
const p=PF.lagrange(points);
|
||||||
|
|
||||||
|
for (let i=0; i<points.length; i++) {
|
||||||
|
const v = PF.eval(p, points[i][0]);
|
||||||
|
assert(PF.F.equals(v, points[i][1]));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it("Should create lagrange polynomial", () => {
|
||||||
|
const PF = new PolField(new ZqField(r));
|
||||||
|
|
||||||
|
const points=[];
|
||||||
|
points.push([bigInt(1), bigInt(2)]);
|
||||||
|
points.push([bigInt(2), bigInt(-2)]);
|
||||||
|
points.push([bigInt(3), bigInt(0)]);
|
||||||
|
points.push([bigInt(4), bigInt(453345)]);
|
||||||
|
|
||||||
|
const p=PF.lagrange(points);
|
||||||
|
|
||||||
|
for (let i=0; i<points.length; i++) {
|
||||||
|
const v = PF.eval(p, points[i][0]);
|
||||||
|
assert(PF.F.equals(v, points[i][1]));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
70
test/ratzqfield.js
Normal file
70
test/ratzqfield.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
const chai = require("chai");
|
||||||
|
|
||||||
|
const bigInt = require("../src/bigint.js");
|
||||||
|
const ZqField = require("../src/zqfield.js");
|
||||||
|
const RatZqField = require("../src/ratzqfield.js");
|
||||||
|
|
||||||
|
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||||
|
const Z = new ZqField(q);
|
||||||
|
const R = new RatZqField(Z);
|
||||||
|
|
||||||
|
const assert = chai.assert;
|
||||||
|
|
||||||
|
function r(a,b) {
|
||||||
|
return [bigInt(a), bigInt(b)];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
describe("Rational zq Field", () => {
|
||||||
|
it("Should compare correctly", () => {
|
||||||
|
assert( R.equals(r(3,5), r(6,10)));
|
||||||
|
assert(!R.equals(r(3,5), r(6,11)));
|
||||||
|
});
|
||||||
|
it("Should add correctly", () => {
|
||||||
|
const a = r(7,4);
|
||||||
|
const b = r(5,12);
|
||||||
|
|
||||||
|
assert(R.equals( R.add(a,b), r(13, 6)));
|
||||||
|
});
|
||||||
|
it("Should substract", () => {
|
||||||
|
const a = r(7,4);
|
||||||
|
const b = r(5,12);
|
||||||
|
|
||||||
|
assert(R.equals( R.sub(a,b), r(4, 3)));
|
||||||
|
});
|
||||||
|
it("Should multiply", () => {
|
||||||
|
const a = r(7,4);
|
||||||
|
const b = r(5,12);
|
||||||
|
|
||||||
|
assert(R.equals( R.mul(a,b), r(35, 48)));
|
||||||
|
});
|
||||||
|
it("Should div", () => {
|
||||||
|
const a = r(7,4);
|
||||||
|
const b = r(5,12);
|
||||||
|
|
||||||
|
assert(R.equals( R.div(a,b), r(7*12, 5*4)));
|
||||||
|
});
|
||||||
|
it("Should square", () => {
|
||||||
|
const a = r(7,4);
|
||||||
|
|
||||||
|
assert(R.equals( R.square(a), r(49, 16)));
|
||||||
|
});
|
||||||
|
it("Should affine", () => {
|
||||||
|
const a = r(12,4);
|
||||||
|
const aa = R.affine(a);
|
||||||
|
assert(Z.equals( aa[0], bigInt(3)));
|
||||||
|
assert(Z.equals( aa[1], Z.one));
|
||||||
|
});
|
||||||
|
it("Should convert from Z to R", () => {
|
||||||
|
const vz = bigInt(34);
|
||||||
|
const vr = R.fromF(vz);
|
||||||
|
|
||||||
|
assert(R.equals( vr, r(34,1)));
|
||||||
|
});
|
||||||
|
it("Should convert from R to Z", () => {
|
||||||
|
const vr = r(32, 2);
|
||||||
|
const vz = R.toF(vr);
|
||||||
|
|
||||||
|
assert(Z.equals( vz, bigInt(16)));
|
||||||
|
});
|
||||||
|
});
|
67
test/zksnark.js
Normal file
67
test/zksnark.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
const chai = require("chai");
|
||||||
|
const fs = require("fs");
|
||||||
|
const bigInt = require("../src/bigint.js");
|
||||||
|
|
||||||
|
const Circuit = require("../src/circuit.js");
|
||||||
|
const zkSnark = require("../index.js");
|
||||||
|
|
||||||
|
const assert = chai.assert;
|
||||||
|
|
||||||
|
|
||||||
|
function stringifyBigInts(o) {
|
||||||
|
if ((typeof(o) == "bigint") || (o instanceof bigInt)) {
|
||||||
|
return o.toString(10);
|
||||||
|
} else if (Array.isArray(o)) {
|
||||||
|
return o.map(stringifyBigInts);
|
||||||
|
} else if (typeof o == "object") {
|
||||||
|
const res = {};
|
||||||
|
for (let k in o) {
|
||||||
|
res[k] = stringifyBigInts(o[k]);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function unstringifyBigInts(o) {
|
||||||
|
if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) {
|
||||||
|
return bigInt(o);
|
||||||
|
} else if (Array.isArray(o)) {
|
||||||
|
return o.map(unstringifyBigInts);
|
||||||
|
} else if (typeof o == "object") {
|
||||||
|
const res = {};
|
||||||
|
for (let k in o) {
|
||||||
|
res[k] = unstringifyBigInts(o[k]);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("zkSnark", () => {
|
||||||
|
it("Load a circuit, create trusted setup, create a proof and validate", () => {
|
||||||
|
|
||||||
|
const cirDef = JSON.parse(fs.readFileSync("../jaz/sum.json", "utf8"));
|
||||||
|
const cir = new Circuit(cirDef);
|
||||||
|
|
||||||
|
const setup = zkSnark.setup(cir);
|
||||||
|
const strSetup = stringifyBigInts(setup);
|
||||||
|
fs.writeFileSync("vk_proof.json", JSON.stringify(strSetup.vk_proof), "utf-8");
|
||||||
|
fs.writeFileSync("vk_verifier.json", JSON.stringify(strSetup.vk_verifier), "utf-8");
|
||||||
|
|
||||||
|
/*
|
||||||
|
const setup = {};
|
||||||
|
setup.vk_proof = unstringifyBigInts(JSON.parse(fs.readFileSync("vk_proof.json", "utf8")));
|
||||||
|
setup.vk_verifier = unstringifyBigInts(JSON.parse(fs.readFileSync("vk_verifier.json", "utf8")));
|
||||||
|
*/
|
||||||
|
const witness = cir.calculateWitness({"a": "33", "b": "34"});
|
||||||
|
|
||||||
|
assert.equal(witness[cir.getSignalIdx("main.out")].toString(), "67");
|
||||||
|
|
||||||
|
const {proof, publicSignals} = zkSnark.genProof(setup.vk_proof, witness);
|
||||||
|
|
||||||
|
assert( zkSnark.isValid(setup.vk_verifier, proof, publicSignals));
|
||||||
|
}).timeout(10000000);
|
||||||
|
});
|
1
vk_proof.json
Normal file
1
vk_proof.json
Normal file
File diff suppressed because one or more lines are too long
1
vk_verifier.json
Normal file
1
vk_verifier.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"nPublic":2,"A":[["0","1","0"],["0","1","0"],["0","1","0"]],"vk_a":[["10910302893854256300335313159192947444388132687074523434871198422054676751347","7128911999163755080071576365381312078199150810378083348330952764137111826309"],["18631850238317279011886579705479432506796416675676074259923090354119752710032","11613125271011748641588689311610150724463404115865535933368983811438235418330"],["1","0"]],"vk_b":["14021005419725675778621050747090735283429719877068464218769467811976154477903","13400327218680122582347155709033494654797979408389561950304209881074672567956","1"],"vk_c":[["3096051994409557504719773510360462097114704303646108617318273214347944304327","21060178932557065464613441158524747948458716806166605021180362439829514495363"],["13711469505507426929293229841903695489923719718740047084134989818704335937579","16689306268247690470861364441748198782838298216373469479699367433528545900642"],["1","0"]],"vk_gb_1":["6323076061844787963801699179984388237278671131058334789970950232032140773376","1289442623160734848462556712373448525459100416297212719395950333399658173112","1"],"vk_gb_2":[["14738403669696391106523308033989669531459082697567002658683173458264070358472","7115351592298265627577071367133297887460251153742186717064165044604072075208"],["5684452168257595880393745672144928966665179424697978770339950828964351397925","16005652883870491274891326398599328665806046577140362628567012925774147115231"],["1","0"]],"vk_g":[["13057967944664071939530697379611124014113572609236714070685841838860689079766","4921285704318374954421284662839198492272478322335189504342768676294475453825"],["16821731243154385058674189668904278548308574642868092417486261078313511500423","14329710484989081757569399730710287771777297111484092478685760712065088557056"],["1","0"]],"vk_z":[["9830782349217318574531840014041507435528173882006141768847850813321843762209","908701408738093737682928637200323566556898851221230193697915803980061312337"],["18420854262130852746249857908832658786725598484918874058527841900342812415992","11905336095877065527602013373361492354917686666454749599264218906638347950295"],["1","0"]]}
|
Loading…
Reference in New Issue
Block a user