fields and bn128 moved to ffjavascript
This commit is contained in:
parent
58f9034286
commit
ee0addb07d
2
cli.js
2
cli.js
@ -25,7 +25,7 @@ const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const zkSnark = require("./index.js");
|
||||
const {stringifyBigInts, unstringifyBigInts} = require("./src/stringifybigint.js");
|
||||
const {stringifyBigInts, unstringifyBigInts} = require("./src/utils.js");
|
||||
|
||||
const loadR1cs = require("r1csfile").load;
|
||||
const WitnessCalculatorBuilder = require("circom_runtime").WitnessCalculatorBuilder;
|
||||
|
7
index.js
7
index.js
@ -33,9 +33,6 @@ exports.kimleeoh = {
|
||||
isValid: require("./src/verifier_kimleeoh.js")
|
||||
};
|
||||
|
||||
exports.stringifyBigInts = require("./src/stringifybigint.js").stringifyBigInts;
|
||||
exports.unstringifyBigInts = require("./src/stringifybigint.js").unstringifyBigInts;
|
||||
exports.stringifyBigInts = require("./src/utils.js").stringifyBigInts;
|
||||
exports.unstringifyBigInts = require("./src/utils.js").unstringifyBigInts;
|
||||
|
||||
|
||||
const Bn128 = require("./src/bn128.js");
|
||||
exports.bn128 = new Bn128();
|
||||
|
@ -32,7 +32,7 @@
|
||||
"chai": "^4.2.0",
|
||||
"circom_runtime": "0.0.3",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"ffjavascript": "0.0.3",
|
||||
"ffjavascript": "0.0.4",
|
||||
"keccak": "^3.0.0",
|
||||
"r1csfile": "0.0.3",
|
||||
"yargs": "^12.0.5"
|
||||
|
@ -1,522 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
/* global BigInt */
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
let wBigInt;
|
||||
|
||||
if (typeof(BigInt) != "undefined") {
|
||||
wBigInt = BigInt;
|
||||
wBigInt.one = wBigInt(1);
|
||||
wBigInt.zero = wBigInt(0);
|
||||
|
||||
// Affine
|
||||
wBigInt.genAffine = (q) => {
|
||||
const nq = -q;
|
||||
return (a) => {
|
||||
let aux = a;
|
||||
if (aux < 0) {
|
||||
if (aux <= nq) {
|
||||
aux = aux % q;
|
||||
}
|
||||
if (aux < wBigInt.zero) {
|
||||
aux = aux + q;
|
||||
}
|
||||
} else {
|
||||
if (aux >= q) {
|
||||
aux = aux % q;
|
||||
}
|
||||
}
|
||||
return aux.valueOf();
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Inverse
|
||||
wBigInt.genInverse = (q) => {
|
||||
return (a) => {
|
||||
let t = wBigInt.zero;
|
||||
let r = q;
|
||||
let newt = wBigInt.one;
|
||||
let newr = wBigInt.affine(a, q);
|
||||
while (newr!=wBigInt.zero) {
|
||||
let q = r/newr;
|
||||
[t, newt] = [newt, t-q*newt];
|
||||
[r, newr] = [newr, r-q*newr];
|
||||
}
|
||||
if (t<wBigInt.zero) t += q;
|
||||
return t;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Add
|
||||
wBigInt.genAdd = (q) => {
|
||||
if (q) {
|
||||
return (a,b) => (a+b) % q;
|
||||
} else {
|
||||
return (a,b) => a+b;
|
||||
}
|
||||
};
|
||||
|
||||
// Sub
|
||||
wBigInt.genSub = (q) => {
|
||||
if (q) {
|
||||
return (a,b) => (a-b) % q;
|
||||
} else {
|
||||
return (a,b) => a-b;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Neg
|
||||
wBigInt.genNeg = (q) => {
|
||||
if (q) {
|
||||
return (a) => (-a) % q;
|
||||
} else {
|
||||
return (a) => -a;
|
||||
}
|
||||
};
|
||||
|
||||
// Mul
|
||||
wBigInt.genMul = (q) => {
|
||||
if (q) {
|
||||
return (a,b) => (a*b) % q;
|
||||
} else {
|
||||
return (a,b) => a*b;
|
||||
}
|
||||
};
|
||||
|
||||
// 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
|
||||
wBigInt.genEquals = (q) => {
|
||||
if (q) {
|
||||
return (a,b) => (a.affine(q) == b.affine(q));
|
||||
} else {
|
||||
return (a,b) => a == b;
|
||||
}
|
||||
};
|
||||
|
||||
// Square
|
||||
wBigInt.genSquare = (q) => {
|
||||
if (q) {
|
||||
return (a) => (a*a) %q;
|
||||
} else {
|
||||
return (a) => a*a;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Double
|
||||
wBigInt.genDouble = (q) => {
|
||||
if (q) {
|
||||
return (a) => (a+a) %q;
|
||||
} else {
|
||||
return (a) => a+a;
|
||||
}
|
||||
};
|
||||
|
||||
// IsZero
|
||||
wBigInt.genIsZero = (q) => {
|
||||
if (q) {
|
||||
return (a) => (a.affine(q) == wBigInt.zero);
|
||||
} else {
|
||||
return (a) => a == wBigInt.zero;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Other minor functions
|
||||
wBigInt.prototype.isOdd = function() {
|
||||
return (this & wBigInt.one) == wBigInt(1);
|
||||
};
|
||||
|
||||
wBigInt.prototype.isNegative = function() {
|
||||
return this < wBigInt.zero;
|
||||
};
|
||||
|
||||
wBigInt.prototype.and = function(m) {
|
||||
return this & m;
|
||||
};
|
||||
|
||||
wBigInt.prototype.div = function(c) {
|
||||
return this / c;
|
||||
};
|
||||
|
||||
wBigInt.prototype.mod = function(c) {
|
||||
return this % c;
|
||||
};
|
||||
|
||||
wBigInt.prototype.pow = function(c) {
|
||||
return this ** c;
|
||||
};
|
||||
|
||||
wBigInt.prototype.abs = function() {
|
||||
return (this > wBigInt.zero) ? this : -this;
|
||||
};
|
||||
|
||||
wBigInt.prototype.modPow = function(e, m) {
|
||||
let acc = wBigInt.one;
|
||||
let exp = this;
|
||||
let rem = e;
|
||||
while (rem) {
|
||||
if (rem & wBigInt.one) {
|
||||
acc = (acc * exp) %m;
|
||||
}
|
||||
exp = (exp * exp) % m;
|
||||
rem = rem >> wBigInt.one;
|
||||
}
|
||||
return acc;
|
||||
};
|
||||
|
||||
wBigInt.prototype.greaterOrEquals = function(b) {
|
||||
return this >= b;
|
||||
};
|
||||
|
||||
wBigInt.prototype.greater = function(b) {
|
||||
return this > b;
|
||||
};
|
||||
wBigInt.prototype.gt = wBigInt.prototype.greater;
|
||||
|
||||
wBigInt.prototype.lesserOrEquals = function(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 == b;
|
||||
};
|
||||
wBigInt.prototype.eq = wBigInt.prototype.equals;
|
||||
|
||||
wBigInt.prototype.neq = function(b) {
|
||||
return this != b;
|
||||
};
|
||||
|
||||
wBigInt.prototype.toJSNumber = function() {
|
||||
return Number(this);
|
||||
};
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
var oldProto = bigInt.prototype;
|
||||
wBigInt = function(a) {
|
||||
if ((typeof a == "string") && (a.slice(0,2) == "0x")) {
|
||||
return bigInt(a.slice(2), 16);
|
||||
} else {
|
||||
return bigInt(a);
|
||||
}
|
||||
};
|
||||
wBigInt.one = bigInt.one;
|
||||
wBigInt.zero = bigInt.zero;
|
||||
wBigInt.prototype = oldProto;
|
||||
|
||||
wBigInt.prototype.div = function(c) {
|
||||
return this.divide(c);
|
||||
};
|
||||
|
||||
// Affine
|
||||
wBigInt.genAffine = (q) => {
|
||||
const nq = wBigInt.zero.minus(q);
|
||||
return (a) => {
|
||||
let aux = a;
|
||||
if (aux.isNegative()) {
|
||||
if (aux.lesserOrEquals(nq)) {
|
||||
aux = aux.mod(q);
|
||||
}
|
||||
if (aux.isNegative()) {
|
||||
aux = aux.add(q);
|
||||
}
|
||||
} else {
|
||||
if (aux.greaterOrEquals(q)) {
|
||||
aux = aux.mod(q);
|
||||
}
|
||||
}
|
||||
return aux;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Inverse
|
||||
wBigInt.genInverse = (q) => {
|
||||
return (a) => a.affine(q).modInv(q);
|
||||
};
|
||||
|
||||
// Add
|
||||
wBigInt.genAdd = (q) => {
|
||||
if (q) {
|
||||
return (a,b) => {
|
||||
const r = a.add(b);
|
||||
return r.greaterOrEquals(q) ? r.minus(q) : r;
|
||||
};
|
||||
} else {
|
||||
return (a,b) => a.add(b);
|
||||
}
|
||||
};
|
||||
|
||||
// Sub
|
||||
wBigInt.genSub = (q) => {
|
||||
if (q) {
|
||||
return (a,b) => a.greaterOrEquals(b) ? a.minus(b) : a.minus(b).add(q);
|
||||
} else {
|
||||
return (a,b) => a.minus(b);
|
||||
}
|
||||
};
|
||||
|
||||
wBigInt.genNeg = (q) => {
|
||||
if (q) {
|
||||
return (a) => a.isZero() ? a : q.minus(a);
|
||||
} else {
|
||||
return (a) => wBigInt.zero.minus(a);
|
||||
}
|
||||
};
|
||||
|
||||
// Mul
|
||||
wBigInt.genMul = (q) => {
|
||||
if (q) {
|
||||
return (a,b) => a.times(b).mod(q);
|
||||
} else {
|
||||
return (a,b) => a.times(b);
|
||||
}
|
||||
};
|
||||
|
||||
// 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
|
||||
wBigInt.genSquare = (q) => {
|
||||
if (q) {
|
||||
return (a) => a.square().mod(q);
|
||||
} else {
|
||||
return (a) => a.square();
|
||||
}
|
||||
};
|
||||
|
||||
// Double
|
||||
wBigInt.genDouble = (q) => {
|
||||
if (q) {
|
||||
return (a) => a.add(a).mod(q);
|
||||
} else {
|
||||
return (a) => a.add(a);
|
||||
}
|
||||
};
|
||||
|
||||
// Equals
|
||||
wBigInt.genEquals = (q) => {
|
||||
if (q) {
|
||||
return (a,b) => a.affine(q).equals(b.affine(q));
|
||||
} else {
|
||||
return (a,b) => a.equals(b);
|
||||
}
|
||||
};
|
||||
|
||||
// IsZero
|
||||
wBigInt.genIsZero = (q) => {
|
||||
if (q) {
|
||||
return (a) => (a.affine(q).isZero());
|
||||
} else {
|
||||
return (a) => a.isZero();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
wBigInt.affine = function(a, q) {
|
||||
return wBigInt.genAffine(q)(a);
|
||||
};
|
||||
|
||||
wBigInt.prototype.affine = function (q) {
|
||||
return wBigInt.affine(this, q);
|
||||
};
|
||||
|
||||
wBigInt.inverse = function(a, q) {
|
||||
return wBigInt.genInverse(q)(a);
|
||||
};
|
||||
|
||||
wBigInt.prototype.inverse = function (q) {
|
||||
return wBigInt.genInverse(q)(this);
|
||||
};
|
||||
|
||||
wBigInt.add = function(a, b, q) {
|
||||
return wBigInt.genAdd(q)(a,b);
|
||||
};
|
||||
|
||||
wBigInt.prototype.add = function (a, q) {
|
||||
return wBigInt.genAdd(q)(this, a);
|
||||
};
|
||||
|
||||
wBigInt.sub = function(a, b, q) {
|
||||
return wBigInt.genSub(q)(a,b);
|
||||
};
|
||||
|
||||
wBigInt.prototype.sub = function (a, q) {
|
||||
return wBigInt.genSub(q)(this, a);
|
||||
};
|
||||
|
||||
wBigInt.neg = function(a, q) {
|
||||
return wBigInt.genNeg(q)(a);
|
||||
};
|
||||
|
||||
wBigInt.prototype.neg = function (q) {
|
||||
return wBigInt.genNeg(q)(this);
|
||||
};
|
||||
|
||||
wBigInt.mul = function(a, b, q) {
|
||||
return wBigInt.genMul(q)(a,b);
|
||||
};
|
||||
|
||||
wBigInt.prototype.mul = function (a, q) {
|
||||
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) {
|
||||
return wBigInt.genEquals(q)(a,b);
|
||||
};
|
||||
|
||||
wBigInt.prototype.equals = function (a, q) {
|
||||
return wBigInt.genEquals(q)(this, a);
|
||||
};
|
||||
|
||||
wBigInt.square = function(a, q) {
|
||||
return wBigInt.genSquare(q)(a);
|
||||
};
|
||||
|
||||
wBigInt.prototype.square = function (q) {
|
||||
return wBigInt.genSquare(q)(this);
|
||||
};
|
||||
|
||||
wBigInt.double = function(a, q) {
|
||||
return wBigInt.genDouble(q)(a);
|
||||
};
|
||||
|
||||
wBigInt.prototype.double = function (q) {
|
||||
return wBigInt.genDouble(q)(this);
|
||||
};
|
||||
|
||||
wBigInt.isZero = function(a, q) {
|
||||
return wBigInt.genIsZero(q)(a);
|
||||
};
|
||||
|
||||
wBigInt.prototype.isZero = function (q) {
|
||||
return wBigInt.genIsZero(q)(this);
|
||||
};
|
||||
|
||||
wBigInt.leBuff2int = function(buff) {
|
||||
let res = wBigInt.zero;
|
||||
for (let i=0; i<buff.length; i++) {
|
||||
const n = wBigInt(buff[i]);
|
||||
res = res.add(n.shl(i*8));
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
wBigInt.leInt2Buff = function(n, len) {
|
||||
let r = n;
|
||||
let o =0;
|
||||
const buff = Buffer.alloc(len);
|
||||
while ((r.greater(wBigInt.zero))&&(o<buff.length)) {
|
||||
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.leInt2Buff = function (len) {
|
||||
return wBigInt.leInt2Buff(this,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;
|
||||
|
445
src/bn128.js
445
src/bn128.js
@ -1,445 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
const F1Field = require("ffjavascript").ZqField;
|
||||
const F2Field = require("./f2field.js");
|
||||
const F3Field = require("./f3field.js");
|
||||
const GCurve = require("./gcurve.js");
|
||||
|
||||
class BN128 {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.q = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583");
|
||||
this.r = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
this.g1 = [ bigInt(1), bigInt(2), bigInt(1)];
|
||||
this.g2 = [
|
||||
[
|
||||
bigInt("10857046999023057135944570762232829481370756359578518086990519993285655852781"),
|
||||
bigInt("11559732032986387107991004021392285783925812861821192530917403151452391805634")
|
||||
],
|
||||
[
|
||||
bigInt("8495653923123431417604973247489272438418190587263600148770280649306958101930"),
|
||||
bigInt("4082367875863433681332203403145435568316851327593401208105741076214120093531")
|
||||
],
|
||||
[
|
||||
bigInt("1"),
|
||||
bigInt("0")
|
||||
]
|
||||
];
|
||||
|
||||
this.nonResidueF2 = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208582");
|
||||
this.nonResidueF6 = [ bigInt("9"), bigInt("1") ];
|
||||
|
||||
this.F1 = new F1Field(this.q);
|
||||
this.F2 = new F2Field(this.F1, this.nonResidueF2);
|
||||
this.G1 = new GCurve(this.F1, this.g1);
|
||||
this.G2 = new GCurve(this.F2, this.g2);
|
||||
this.F6 = new F3Field(this.F2, this.nonResidueF6);
|
||||
this.F12 = new F2Field(this.F6, this.nonResidueF6);
|
||||
this.Fr = new F1Field(this.r);
|
||||
const self = this;
|
||||
this.F12._mulByNonResidue = function(a) {
|
||||
return [self.F2.mul(this.nonResidue, a[2]), a[0], a[1]];
|
||||
};
|
||||
|
||||
this._preparePairing();
|
||||
|
||||
}
|
||||
|
||||
_preparePairing() {
|
||||
this.loopCount = bigInt("29793968203157093288");// CONSTANT
|
||||
|
||||
// Set loopCountNeg
|
||||
if (this.loopCount.isNegative()) {
|
||||
this.loopCount = this.loopCount.neg();
|
||||
this.loopCountNeg = true;
|
||||
} else {
|
||||
this.loopCountNeg = false;
|
||||
}
|
||||
|
||||
// Set loop_count_bits
|
||||
let lc = this.loopCount;
|
||||
this.loop_count_bits = []; // Constant
|
||||
while (!lc.isZero()) {
|
||||
this.loop_count_bits.push( lc.isOdd() );
|
||||
lc = lc.shiftRight(1);
|
||||
}
|
||||
|
||||
this.two_inv = this.F1.inv(bigInt(2));
|
||||
|
||||
this.coef_b = bigInt(3);
|
||||
this.twist = [bigInt(9) , bigInt(1)];
|
||||
this.twist_coeff_b = this.F2.mulScalar( this.F2.inv(this.twist), this.coef_b );
|
||||
|
||||
this.frobenius_coeffs_c1_1 = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208582");
|
||||
this.twist_mul_by_q_X =
|
||||
[
|
||||
bigInt("21575463638280843010398324269430826099269044274347216827212613867836435027261"),
|
||||
bigInt("10307601595873709700152284273816112264069230130616436755625194854815875713954")
|
||||
];
|
||||
this.twist_mul_by_q_Y =
|
||||
[
|
||||
bigInt("2821565182194536844548159561693502659359617185244120367078079554186484126554"),
|
||||
bigInt("3505843767911556378687030309984248845540243509899259641013678093033130930403")
|
||||
];
|
||||
|
||||
this.final_exponent = bigInt("552484233613224096312617126783173147097382103762957654188882734314196910839907541213974502761540629817009608548654680343627701153829446747810907373256841551006201639677726139946029199968412598804882391702273019083653272047566316584365559776493027495458238373902875937659943504873220554161550525926302303331747463515644711876653177129578303191095900909191624817826566688241804408081892785725967931714097716709526092261278071952560171111444072049229123565057483750161460024353346284167282452756217662335528813519139808291170539072125381230815729071544861602750936964829313608137325426383735122175229541155376346436093930287402089517426973178917569713384748081827255472576937471496195752727188261435633271238710131736096299798168852925540549342330775279877006784354801422249722573783561685179618816480037695005515426162362431072245638324744480");
|
||||
|
||||
}
|
||||
|
||||
|
||||
pairing(p1, p2) {
|
||||
|
||||
const pre1 = this.precomputeG1(p1);
|
||||
const pre2 = this.precomputeG2(p2);
|
||||
|
||||
const r1 = this.millerLoop(pre1, pre2);
|
||||
|
||||
const res = this.finalExponentiation(r1);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
precomputeG1(p) {
|
||||
const Pcopy = this.G1.affine(p);
|
||||
|
||||
const res = {};
|
||||
res.PX = Pcopy[0];
|
||||
res.PY = Pcopy[1];
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
precomputeG2(p) {
|
||||
|
||||
const Qcopy = this.G2.affine(p);
|
||||
|
||||
const res = {
|
||||
QX: Qcopy[0],
|
||||
QY: Qcopy[1],
|
||||
coeffs: []
|
||||
};
|
||||
|
||||
const R = {
|
||||
X: Qcopy[0],
|
||||
Y: Qcopy[1],
|
||||
Z: this.F2.one
|
||||
};
|
||||
|
||||
let c;
|
||||
|
||||
for (let i = this.loop_count_bits.length-2; i >= 0; --i)
|
||||
{
|
||||
const bit = this.loop_count_bits[i];
|
||||
|
||||
c = this._doubleStep(R);
|
||||
res.coeffs.push(c);
|
||||
|
||||
if (bit)
|
||||
{
|
||||
c = this._addStep(Qcopy, R);
|
||||
res.coeffs.push(c);
|
||||
}
|
||||
}
|
||||
|
||||
const Q1 = this.G2.affine(this._g2MulByQ(Qcopy));
|
||||
if (!this.F2.eq(Q1[2], this.F2.one))
|
||||
{
|
||||
throw new Error("Expected values are not equal");
|
||||
}
|
||||
const Q2 = this.G2.affine(this._g2MulByQ(Q1));
|
||||
if (!this.F2.eq(Q2[2], this.F2.one))
|
||||
{
|
||||
throw new Error("Expected values are not equal");
|
||||
}
|
||||
|
||||
if (this.loopCountNeg)
|
||||
{
|
||||
R.Y = this.F2.neg(R.Y);
|
||||
}
|
||||
Q2[1] = this.F2.neg(Q2[1]);
|
||||
|
||||
c = this._addStep(Q1, R);
|
||||
res.coeffs.push(c);
|
||||
|
||||
c = this._addStep(Q2, R);
|
||||
res.coeffs.push(c);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
millerLoop(pre1, pre2) {
|
||||
let f = this.F12.one;
|
||||
|
||||
let idx = 0;
|
||||
|
||||
let c;
|
||||
|
||||
for (let i = this.loop_count_bits.length-2; i >= 0; --i)
|
||||
{
|
||||
const bit = this.loop_count_bits[i];
|
||||
|
||||
/* code below gets executed for all bits (EXCEPT the MSB itself) of
|
||||
alt_bn128_param_p (skipping leading zeros) in MSB to LSB
|
||||
order */
|
||||
|
||||
c = pre2.coeffs[idx++];
|
||||
f = this.F12.square(f);
|
||||
f = this._mul_by_024(
|
||||
f,
|
||||
c.ell_0,
|
||||
this.F2.mulScalar(c.ell_VW , pre1.PY),
|
||||
this.F2.mulScalar(c.ell_VV , pre1.PX));
|
||||
|
||||
if (bit)
|
||||
{
|
||||
c = pre2.coeffs[idx++];
|
||||
f = this._mul_by_024(
|
||||
f,
|
||||
c.ell_0,
|
||||
this.F2.mulScalar(c.ell_VW, pre1.PY),
|
||||
this.F2.mulScalar(c.ell_VV, pre1.PX));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this.loopCountNeg)
|
||||
{
|
||||
f = this.F12.inverse(f);
|
||||
}
|
||||
|
||||
c = pre2.coeffs[idx++];
|
||||
f = this._mul_by_024(
|
||||
f,
|
||||
c.ell_0,
|
||||
this.F2.mulScalar(c.ell_VW, pre1.PY),
|
||||
this.F2.mulScalar(c.ell_VV, pre1.PX));
|
||||
|
||||
c = pre2.coeffs[idx++];
|
||||
f = this._mul_by_024(
|
||||
f,
|
||||
c.ell_0,
|
||||
this.F2.mulScalar(c.ell_VW, pre1.PY),
|
||||
this.F2.mulScalar(c.ell_VV, pre1.PX));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
finalExponentiation(elt) {
|
||||
// TODO: There is an optimization in FF
|
||||
|
||||
const res = this.F12.exp(elt,this.final_exponent);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
_doubleStep(current) {
|
||||
const X = current.X;
|
||||
const Y = current.Y;
|
||||
const Z = current.Z;
|
||||
|
||||
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 C = this.F2.square(Z); // C = Z1^2
|
||||
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 F = this.F2.add(E, this.F2.add(E,E)); // F = 3 * E
|
||||
const G =
|
||||
this.F2.mulScalar(
|
||||
this.F2.add( B , F ),
|
||||
this.two_inv); // G = (B+F)/2
|
||||
const H =
|
||||
this.F2.sub(
|
||||
this.F2.square( this.F2.add(Y,Z) ),
|
||||
this.F2.add( B , C)); // H = (Y1+Z1)^2-(B+C)
|
||||
const I = this.F2.sub(E, B); // I = E-B
|
||||
const J = this.F2.square(X); // J = X1^2
|
||||
const E_squared = this.F2.square(E); // E_squared = E^2
|
||||
|
||||
current.X = this.F2.mul( A, this.F2.sub(B,F) ); // X3 = A * (B-F)
|
||||
current.Y =
|
||||
this.F2.sub(
|
||||
this.F2.sub( this.F2.square(G) , E_squared ),
|
||||
this.F2.add( E_squared , E_squared )); // Y3 = G^2 - 3*E^2
|
||||
current.Z = this.F2.mul( B, H ); // Z3 = B * H
|
||||
|
||||
const c = {
|
||||
ell_0 : this.F2.mul( I, this.twist), // ell_0 = xi * I
|
||||
ell_VW: this.F2.neg( H ), // ell_VW = - H (later: * yP)
|
||||
ell_VV: this.F2.add( J , this.F2.add(J,J) ) // ell_VV = 3*J (later: * xP)
|
||||
};
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
_addStep(base, current) {
|
||||
|
||||
const X1 = current.X;
|
||||
const Y1 = current.Y;
|
||||
const Z1 = current.Z;
|
||||
const x2 = base[0];
|
||||
const y2 = base[1];
|
||||
|
||||
const D = this.F2.sub( X1, this.F2.mul(x2,Z1) ); // D = X1 - X2*Z1
|
||||
|
||||
// console.log("Y: "+ A[0].affine(this.q).toString(16));
|
||||
|
||||
const E = this.F2.sub( Y1, this.F2.mul(y2,Z1) ); // E = Y1 - Y2*Z1
|
||||
const F = this.F2.square(D); // F = D^2
|
||||
const G = this.F2.square(E); // G = E^2
|
||||
const H = this.F2.mul(D,F); // H = D*F
|
||||
const I = this.F2.mul(X1,F); // I = X1 * F
|
||||
const J =
|
||||
this.F2.sub(
|
||||
this.F2.add( H, this.F2.mul(Z1,G) ),
|
||||
this.F2.add( I, I )); // J = H + Z1*G - (I+I)
|
||||
|
||||
current.X = this.F2.mul( D , J ); // X3 = D*J
|
||||
current.Y =
|
||||
this.F2.sub(
|
||||
this.F2.mul( E , this.F2.sub(I,J) ),
|
||||
this.F2.mul( H , Y1)); // Y3 = E*(I-J)-(H*Y1)
|
||||
current.Z = this.F2.mul(Z1,H);
|
||||
const c = {
|
||||
ell_0 :
|
||||
this.F2.mul(
|
||||
this.twist,
|
||||
this.F2.sub(
|
||||
this.F2.mul(E , x2),
|
||||
this.F2.mul(D , y2))), // ell_0 = xi * (E * X2 - D * Y2)
|
||||
ell_VV : this.F2.neg(E), // ell_VV = - E (later: * xP)
|
||||
ell_VW : D // ell_VW = D (later: * yP )
|
||||
};
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
_mul_by_024(a, ell_0, ell_VW, ell_VV) {
|
||||
|
||||
// Old implementation
|
||||
/*
|
||||
const b = [
|
||||
[ell_0, this.F2.zero, ell_VV],
|
||||
[this.F2.zero, ell_VW, this.F2.zero]
|
||||
];
|
||||
|
||||
return this.F12.mul(a,b);
|
||||
*/
|
||||
|
||||
// This is a new implementation,
|
||||
// But it does not look worthy
|
||||
// at least in javascript.
|
||||
|
||||
let z0 = a[0][0];
|
||||
let z1 = a[0][1];
|
||||
let z2 = a[0][2];
|
||||
let z3 = a[1][0];
|
||||
let z4 = a[1][1];
|
||||
let z5 = a[1][2];
|
||||
|
||||
const x0 = ell_0;
|
||||
const x2 = ell_VV;
|
||||
const x4 = ell_VW;
|
||||
|
||||
const D0 = this.F2.mul(z0, x0);
|
||||
const D2 = this.F2.mul(z2, x2);
|
||||
const D4 = this.F2.mul(z4, x4);
|
||||
const t2 = this.F2.add(z0, z4);
|
||||
let t1 = this.F2.add(z0, z2);
|
||||
const s0 = this.F2.add(this.F2.add(z1,z3),z5);
|
||||
|
||||
// For z.a_.a_ = z0.
|
||||
let S1 = this.F2.mul(z1, x2);
|
||||
let T3 = this.F2.add(S1, D4);
|
||||
let T4 = this.F2.add( this.F2.mul(this.nonResidueF6, T3),D0);
|
||||
z0 = T4;
|
||||
|
||||
// For z.a_.b_ = z1
|
||||
T3 = this.F2.mul(z5, x4);
|
||||
S1 = this.F2.add(S1, T3);
|
||||
T3 = this.F2.add(T3, D2);
|
||||
T4 = this.F2.mul(this.nonResidueF6, T3);
|
||||
T3 = this.F2.mul(z1, x0);
|
||||
S1 = this.F2.add(S1, T3);
|
||||
T4 = this.F2.add(T4, T3);
|
||||
z1 = T4;
|
||||
|
||||
// For z.a_.c_ = z2
|
||||
let t0 = this.F2.add(x0, x2);
|
||||
T3 = this.F2.sub(
|
||||
this.F2.mul(t1, t0),
|
||||
this.F2.add(D0, D2));
|
||||
T4 = this.F2.mul(z3, x4);
|
||||
S1 = this.F2.add(S1, T4);
|
||||
|
||||
// For z.b_.a_ = z3 (z3 needs z2)
|
||||
t0 = this.F2.add(z2, z4);
|
||||
z2 = this.F2.add(T3, T4);
|
||||
t1 = this.F2.add(x2, x4);
|
||||
T3 = this.F2.sub(
|
||||
this.F2.mul(t0,t1),
|
||||
this.F2.add(D2, D4));
|
||||
|
||||
T4 = this.F2.mul(this.nonResidueF6, T3);
|
||||
T3 = this.F2.mul(z3, x0);
|
||||
S1 = this.F2.add(S1, T3);
|
||||
T4 = this.F2.add(T4, T3);
|
||||
z3 = T4;
|
||||
|
||||
// For z.b_.b_ = z4
|
||||
T3 = this.F2.mul(z5, x2);
|
||||
S1 = this.F2.add(S1, T3);
|
||||
T4 = this.F2.mul(this.nonResidueF6, T3);
|
||||
t0 = this.F2.add(x0, x4);
|
||||
T3 = this.F2.sub(
|
||||
this.F2.mul(t2,t0),
|
||||
this.F2.add(D0, D4));
|
||||
T4 = this.F2.add(T4, T3);
|
||||
z4 = T4;
|
||||
|
||||
// For z.b_.c_ = z5.
|
||||
t0 = this.F2.add(this.F2.add(x0, x2), x4);
|
||||
T3 = this.F2.sub(this.F2.mul(s0, t0), S1);
|
||||
z5 = T3;
|
||||
|
||||
return [
|
||||
[z0, z1, z2],
|
||||
[z3, z4, z5]
|
||||
];
|
||||
|
||||
|
||||
}
|
||||
|
||||
_g2MulByQ(p) {
|
||||
const fmx = [p[0][0], this.F1.mul(p[0][1], this.frobenius_coeffs_c1_1 )];
|
||||
const fmy = [p[1][0], this.F1.mul(p[1][1], this.frobenius_coeffs_c1_1 )];
|
||||
const fmz = [p[2][0], this.F1.mul(p[2][1], this.frobenius_coeffs_c1_1 )];
|
||||
return [
|
||||
this.F2.mul(this.twist_mul_by_q_X , fmx),
|
||||
this.F2.mul(this.twist_mul_by_q_Y , fmy),
|
||||
fmz
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BN128;
|
@ -1,233 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
module.exports = calculateWitness;
|
||||
|
||||
function calculateWitness(circuit, inputSignals, options) {
|
||||
options = options || {};
|
||||
if (!options.logFunction) options.logFunction = console.log;
|
||||
const ctx = new RTCtx(circuit, options);
|
||||
|
||||
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) {
|
||||
if (typeof(value) == "undefined") throw new Error("Signal not defined:" + s);
|
||||
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(idx));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (let i=0; i<ctx.witness.length; i++) {
|
||||
if (typeof(ctx.witness[i]) == "undefined") {
|
||||
throw new Error("Signal not assigned: " + circuit.signalNames(i));
|
||||
}
|
||||
if (options.logOutput) options.logFunction(circuit.signalNames(i) + " --> " + ctx.witness[i].toString());
|
||||
}
|
||||
return ctx.witness.slice(0, circuit.nVars);
|
||||
// return ctx.witness;
|
||||
}
|
||||
|
||||
class RTCtx {
|
||||
constructor(circuit, options) {
|
||||
this.options = options;
|
||||
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) {
|
||||
if (this.options.logTrigger) this.options.logFunction("Component Treiggered: " + this.circuit.components[c].name);
|
||||
|
||||
// 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;
|
||||
|
||||
if (this.options.logTrigger) this.options.logFunction("End Component Treiggered: " + this.circuit.components[c].name);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (this.options.logSet) this.options.logFunction("set " + fullName + " <-- " + value.toString());
|
||||
const sId = this.circuit.getSignalIdx(fullName);
|
||||
let firstInit =false;
|
||||
if (typeof(this.witness[sId]) == "undefined") {
|
||||
firstInit = true;
|
||||
}
|
||||
this.witness[sId] = bigInt(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 this.witness[sId];
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
if (this.options.logGet) this.options.logFunction("get --->" + fullName + " = " + this.witness[sId].toString() );
|
||||
return this.witness[sId];
|
||||
}
|
||||
|
||||
assert(a,b,errStr) {
|
||||
const ba = bigInt(a);
|
||||
const bb = bigInt(b);
|
||||
if (!ba.equals(bb)) {
|
||||
throw new Error("Constraint doesn't match "+ this.currentComponent+": "+ errStr + " -> "+ ba.toString() + " != " + bb.toString());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,191 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
const __P__ = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const __MASK__ = bigInt("28948022309329048855892746252171976963317496166410141009864396001978282409983"); // 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||
const calculateWitness = require("./calculateWitness.js");
|
||||
|
||||
module.exports = class Circuit {
|
||||
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.nConstraints = circuitDef.constraints.length;
|
||||
|
||||
this.signalName2Idx = circuitDef.signalName2Idx;
|
||||
this.components = circuitDef.components;
|
||||
this.componentName2Idx = circuitDef.componentName2Idx;
|
||||
this.signals = circuitDef.signals;
|
||||
this.constraints = circuitDef.constraints;
|
||||
|
||||
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, log) {
|
||||
return calculateWitness(this, input, log);
|
||||
}
|
||||
|
||||
checkWitness(w) {
|
||||
const evalLC = (lc, w) => {
|
||||
let acc = bigInt(0);
|
||||
for (let k in lc) {
|
||||
acc= acc.add(bigInt(w[k]).mul(bigInt(lc[k]))).mod(__P__);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
const checkConstraint = (ct, w) => {
|
||||
const a=evalLC(ct[0],w);
|
||||
const b=evalLC(ct[1],w);
|
||||
const c=evalLC(ct[2],w);
|
||||
const res = (a.mul(b).sub(c)).affine(__P__);
|
||||
if (!res.isZero()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
for (let i=0; i<this.constraints.length; i++) {
|
||||
if (!checkConstraint(this.constraints[i], w)) {
|
||||
this.printCostraint(this.constraints[i]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
printCostraint(c) {
|
||||
const lc2str = (lc) => {
|
||||
let S = "";
|
||||
for (let k in lc) {
|
||||
let name = this.signals[k].names[0];
|
||||
if (name == "one") name = "";
|
||||
let v = bigInt(lc[k]);
|
||||
let vs;
|
||||
if (!v.lesserOrEquals(__P__.shr(bigInt(1)))) {
|
||||
v = __P__.sub(v);
|
||||
vs = "-"+v.toString();
|
||||
} else {
|
||||
if (S!="") {
|
||||
vs = "+"+v.toString();
|
||||
} else {
|
||||
vs = "";
|
||||
}
|
||||
if (vs!="1") {
|
||||
vs = vs + v.toString();
|
||||
}
|
||||
}
|
||||
|
||||
S= S + " " + vs + name;
|
||||
}
|
||||
return S;
|
||||
};
|
||||
const S = `[ ${lc2str(c[0])} ] * [ ${lc2str(c[1])} ] - [ ${lc2str(c[2])} ] = 0`;
|
||||
console.log(S);
|
||||
}
|
||||
|
||||
printConstraints() {
|
||||
for (let i=0; i<this.constraints.length; i++) {
|
||||
this.printCostraint(this.constraints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
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(constraint, signalIdx) {
|
||||
return bigInt(this.constraints[constraint][0][signalIdx] || 0 );
|
||||
}
|
||||
|
||||
b(constraint, signalIdx) {
|
||||
return bigInt(this.constraints[constraint][1][signalIdx] || 0);
|
||||
}
|
||||
|
||||
c(constraint, signalIdx) {
|
||||
return bigInt(this.constraints[constraint][2][signalIdx] || 0);
|
||||
}
|
||||
};
|
133
src/f2field.js
133
src/f2field.js
@ -1,133 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
const fUtils = require("./futils.js");
|
||||
|
||||
class F2Field {
|
||||
constructor(F, nonResidue) {
|
||||
this.F = F;
|
||||
this.zero = [this.F.zero, this.F.zero];
|
||||
this.one = [this.F.one, this.F.zero];
|
||||
this.nonResidue = nonResidue;
|
||||
}
|
||||
|
||||
_mulByNonResidue(a) {
|
||||
return this.F.mul(this.nonResidue, a);
|
||||
}
|
||||
|
||||
copy(a) {
|
||||
return [this.F.copy(a[0]), this.F.copy(a[1])];
|
||||
}
|
||||
|
||||
add(a, b) {
|
||||
return [
|
||||
this.F.add(a[0], b[0]),
|
||||
this.F.add(a[1], b[1])
|
||||
];
|
||||
}
|
||||
|
||||
double(a) {
|
||||
return this.add(a,a);
|
||||
}
|
||||
|
||||
sub(a, b) {
|
||||
return [
|
||||
this.F.sub(a[0], b[0]),
|
||||
this.F.sub(a[1], b[1])
|
||||
];
|
||||
}
|
||||
|
||||
neg(a) {
|
||||
return this.sub(this.zero, a);
|
||||
}
|
||||
|
||||
mul(a, b) {
|
||||
const aA = this.F.mul(a[0] , b[0]);
|
||||
const bB = this.F.mul(a[1] , b[1]);
|
||||
|
||||
return [
|
||||
this.F.add( aA , this._mulByNonResidue(bB)),
|
||||
this.F.sub(
|
||||
this.F.mul(
|
||||
this.F.add(a[0], a[1]),
|
||||
this.F.add(b[0], b[1])),
|
||||
this.F.add(aA, bB))];
|
||||
}
|
||||
|
||||
inv(a) {
|
||||
const t0 = this.F.square(a[0]);
|
||||
const t1 = this.F.square(a[1]);
|
||||
const t2 = this.F.sub(t0, this._mulByNonResidue(t1));
|
||||
const t3 = this.F.inv(t2);
|
||||
return [
|
||||
this.F.mul(a[0], t3),
|
||||
this.F.neg(this.F.mul( a[1], t3)) ];
|
||||
}
|
||||
|
||||
div(a, b) {
|
||||
return this.mul(a, this.inv(b));
|
||||
}
|
||||
|
||||
square(a) {
|
||||
const ab = this.F.mul(a[0] , a[1]);
|
||||
|
||||
/*
|
||||
[
|
||||
(a + b) * (a + non_residue * b) - ab - non_residue * ab,
|
||||
ab + ab
|
||||
];
|
||||
*/
|
||||
|
||||
return [
|
||||
this.F.sub(
|
||||
this.F.mul(
|
||||
this.F.add(a[0], a[1]) ,
|
||||
this.F.add(
|
||||
a[0] ,
|
||||
this._mulByNonResidue(a[1]))),
|
||||
this.F.add(
|
||||
ab,
|
||||
this._mulByNonResidue(ab))),
|
||||
this.F.add(ab, ab)
|
||||
];
|
||||
}
|
||||
|
||||
isZero(a) {
|
||||
return this.F.isZero(a[0]) && this.F.isZero(a[1]);
|
||||
}
|
||||
|
||||
eq(a, b) {
|
||||
return this.F.eq(a[0], b[0]) && this.F.eq(a[1], b[1]);
|
||||
}
|
||||
|
||||
mulScalar(base, e) {
|
||||
return fUtils.mulScalar(this, base, e);
|
||||
}
|
||||
|
||||
exp(base, e) {
|
||||
return fUtils.exp(this, base, e);
|
||||
}
|
||||
|
||||
toString(a) {
|
||||
const cp = this.affine(a);
|
||||
return `[ ${this.F.toString(cp[0])} , ${this.F.toString(cp[1])} ]`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = F2Field;
|
177
src/f3field.js
177
src/f3field.js
@ -1,177 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
const fUtils = require("./futils.js");
|
||||
|
||||
class F3Field {
|
||||
constructor(F, nonResidue) {
|
||||
this.F = F;
|
||||
this.zero = [this.F.zero, this.F.zero, this.F.zero];
|
||||
this.one = [this.F.one, this.F.zero, this.F.zero];
|
||||
this.nonResidue = nonResidue;
|
||||
}
|
||||
|
||||
_mulByNonResidue(a) {
|
||||
return this.F.mul(this.nonResidue, a);
|
||||
}
|
||||
|
||||
copy(a) {
|
||||
return [this.F.copy(a[0]), this.F.copy(a[1]), this.F.copy(a[2])];
|
||||
}
|
||||
|
||||
add(a, b) {
|
||||
return [
|
||||
this.F.add(a[0], b[0]),
|
||||
this.F.add(a[1], b[1]),
|
||||
this.F.add(a[2], b[2])
|
||||
];
|
||||
}
|
||||
|
||||
double(a) {
|
||||
return this.add(a,a);
|
||||
}
|
||||
|
||||
sub(a, b) {
|
||||
return [
|
||||
this.F.sub(a[0], b[0]),
|
||||
this.F.sub(a[1], b[1]),
|
||||
this.F.sub(a[2], b[2])
|
||||
];
|
||||
}
|
||||
|
||||
neg(a) {
|
||||
return this.sub(this.zero, a);
|
||||
}
|
||||
|
||||
mul(a, b) {
|
||||
|
||||
const aA = this.F.mul(a[0] , b[0]);
|
||||
const bB = this.F.mul(a[1] , b[1]);
|
||||
const cC = this.F.mul(a[2] , b[2]);
|
||||
|
||||
return [
|
||||
this.F.add(
|
||||
aA,
|
||||
this._mulByNonResidue(
|
||||
this.F.sub(
|
||||
this.F.mul(
|
||||
this.F.add(a[1], a[2]),
|
||||
this.F.add(b[1], b[2])),
|
||||
this.F.add(bB, cC)))), // aA + non_residue*((b+c)*(B+C)-bB-cC),
|
||||
|
||||
this.F.add(
|
||||
this.F.sub(
|
||||
this.F.mul(
|
||||
this.F.add(a[0], a[1]),
|
||||
this.F.add(b[0], b[1])),
|
||||
this.F.add(aA, bB)),
|
||||
this._mulByNonResidue( cC)), // (a+b)*(A+B)-aA-bB+non_residue*cC
|
||||
|
||||
this.F.add(
|
||||
this.F.sub(
|
||||
this.F.mul(
|
||||
this.F.add(a[0], a[2]),
|
||||
this.F.add(b[0], b[2])),
|
||||
this.F.add(aA, cC)),
|
||||
bB)]; // (a+c)*(A+C)-aA+bB-cC)
|
||||
}
|
||||
|
||||
inv(a) {
|
||||
const t0 = this.F.square(a[0]); // t0 = a^2 ;
|
||||
const t1 = this.F.square(a[1]); // t1 = b^2 ;
|
||||
const t2 = this.F.square(a[2]); // t2 = c^2;
|
||||
const t3 = this.F.mul(a[0],a[1]); // t3 = ab
|
||||
const t4 = this.F.mul(a[0],a[2]); // t4 = ac
|
||||
const t5 = this.F.mul(a[1],a[2]); // t5 = bc;
|
||||
// c0 = t0 - non_residue * t5;
|
||||
const c0 = this.F.sub(t0, this._mulByNonResidue(t5));
|
||||
// c1 = non_residue * t2 - t3;
|
||||
const c1 = this.F.sub(this._mulByNonResidue(t2), t3);
|
||||
const c2 = this.F.sub(t1, t4); // c2 = t1-t4
|
||||
|
||||
// t6 = (a * c0 + non_residue * (c * c1 + b * c2)).inv();
|
||||
const t6 =
|
||||
this.F.inv(
|
||||
this.F.add(
|
||||
this.F.mul(a[0], c0),
|
||||
this._mulByNonResidue(
|
||||
this.F.add(
|
||||
this.F.mul(a[2], c1),
|
||||
this.F.mul(a[1], c2)))));
|
||||
|
||||
return [
|
||||
this.F.mul(t6, c0), // t6*c0
|
||||
this.F.mul(t6, c1), // t6*c1
|
||||
this.F.mul(t6, c2)]; // t6*c2
|
||||
}
|
||||
|
||||
div(a, b) {
|
||||
return this.mul(a, this.inv(b));
|
||||
}
|
||||
|
||||
square(a) {
|
||||
const s0 = this.F.square(a[0]); // s0 = a^2
|
||||
const ab = this.F.mul(a[0], a[1]); // ab = a*b
|
||||
const s1 = this.F.add(ab, ab); // s1 = 2ab;
|
||||
const s2 = this.F.square(
|
||||
this.F.add(this.F.sub(a[0],a[1]), a[2])); // s2 = (a - b + c)^2;
|
||||
const bc = this.F.mul(a[1],a[2]); // bc = b*c
|
||||
const s3 = this.F.add(bc, bc); // s3 = 2*bc
|
||||
const s4 = this.F.square(a[2]); // s4 = c^2
|
||||
|
||||
|
||||
return [
|
||||
this.F.add(
|
||||
s0,
|
||||
this._mulByNonResidue(s3)), // s0 + non_residue * s3,
|
||||
this.F.add(
|
||||
s1,
|
||||
this._mulByNonResidue(s4)), // s1 + non_residue * s4,
|
||||
this.F.sub(
|
||||
this.F.add( this.F.add(s1, s2) , s3 ),
|
||||
this.F.add(s0, s4))]; // s1 + s2 + s3 - s0 - s4
|
||||
}
|
||||
|
||||
isZero(a) {
|
||||
return this.F.isZero(a[0]) && this.F.isZero(a[1]) && this.F.isZero(a[2]);
|
||||
}
|
||||
|
||||
eq(a, b) {
|
||||
return this.F.eq(a[0], b[0]) && this.F.eq(a[1], b[1]) && this.F.eq(a[2], b[2]);
|
||||
}
|
||||
|
||||
affine(a) {
|
||||
return [this.F.affine(a[0]), this.F.affine(a[1]), this.F.affine(a[2])];
|
||||
}
|
||||
|
||||
mulScalar(base, e) {
|
||||
return fUtils.mulScalar(this, base, e);
|
||||
}
|
||||
|
||||
exp(base, e) {
|
||||
return fUtils.exp(this, base, e);
|
||||
}
|
||||
|
||||
toString(a) {
|
||||
const cp = this.affine(a);
|
||||
return `[ ${this.F.toString(cp[0])} , ${this.F.toString(cp[1])}, ${this.F.toString(cp[2])} ]`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = F3Field;
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
exports.mulScalar = (F, base, e) =>{
|
||||
let res = F.zero;
|
||||
let rem = bigInt(e);
|
||||
let exp = base;
|
||||
|
||||
while (! rem.isZero()) {
|
||||
if (rem.isOdd()) {
|
||||
res = F.add(res, exp);
|
||||
}
|
||||
exp = F.double(exp);
|
||||
rem = rem.shiftRight(1);
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
exports.exp = (F, base, e) =>{
|
||||
let res = F.one;
|
||||
let rem = bigInt(e);
|
||||
let exp = base;
|
||||
|
||||
while (! rem.isZero()) {
|
||||
if (rem.isOdd()) {
|
||||
res = F.mul(res, exp);
|
||||
}
|
||||
exp = F.square(exp);
|
||||
rem = rem.shiftRight(1);
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
186
src/gcurve.js
186
src/gcurve.js
@ -1,186 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
const fUtils = require("./futils.js");
|
||||
|
||||
class GCurve {
|
||||
|
||||
constructor(F, g) {
|
||||
this.F = F;
|
||||
this.g = g;
|
||||
if (this.g.length == 2) this.g[2] = this.F.one;
|
||||
this.zero = [this.F.zero, this.F.one, this.F.zero];
|
||||
}
|
||||
|
||||
add(p1, p2) {
|
||||
|
||||
const F = this.F;
|
||||
|
||||
if (this.eq(p1, this.zero)) return p2;
|
||||
if (this.eq(p2, this.zero)) return p1;
|
||||
|
||||
const res = new Array(3);
|
||||
|
||||
const Z1Z1 = F.square( p1[2] );
|
||||
const Z2Z2 = F.square( p2[2] );
|
||||
|
||||
const U1 = F.mul( p1[0] , Z2Z2 ); // U1 = X1 * Z2Z2
|
||||
const U2 = F.mul( p2[0] , Z1Z1 ); // U2 = X2 * Z1Z1
|
||||
|
||||
const Z1_cubed = F.mul( p1[2] , Z1Z1);
|
||||
const Z2_cubed = F.mul( p2[2] , Z2Z2);
|
||||
|
||||
const S1 = F.mul( p1[1] , Z2_cubed); // S1 = Y1 * Z2 * Z2Z2
|
||||
const S2 = F.mul( p2[1] , Z1_cubed); // S2 = Y2 * Z1 * Z1Z1
|
||||
|
||||
if (F.eq(U1,U2) && F.eq(S1,S2)) {
|
||||
return this.double(p1);
|
||||
}
|
||||
|
||||
const H = F.sub( U2 , U1 ); // H = U2-U1
|
||||
|
||||
const S2_minus_S1 = F.sub( S2 , S1 );
|
||||
|
||||
const I = F.square( F.add(H,H) ); // I = (2 * H)^2
|
||||
const J = F.mul( H , I ); // J = H * I
|
||||
|
||||
const r = F.add( S2_minus_S1 , S2_minus_S1 ); // r = 2 * (S2-S1)
|
||||
const V = F.mul( U1 , I ); // V = U1 * I
|
||||
|
||||
res[0] =
|
||||
F.sub(
|
||||
F.sub( F.square(r) , J ),
|
||||
F.add( V , V )); // X3 = r^2 - J - 2 * V
|
||||
|
||||
const S1_J = F.mul( S1 , J );
|
||||
|
||||
res[1] =
|
||||
F.sub(
|
||||
F.mul( r , F.sub(V,res[0])),
|
||||
F.add( S1_J,S1_J )); // Y3 = r * (V-X3)-2 S1 J
|
||||
|
||||
res[2] =
|
||||
F.mul(
|
||||
H,
|
||||
F.sub(
|
||||
F.square( F.add(p1[2],p2[2]) ),
|
||||
F.add( Z1Z1 , Z2Z2 ))); // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H
|
||||
|
||||
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) {
|
||||
const F = this.F;
|
||||
|
||||
const res = new Array(3);
|
||||
|
||||
if (this.eq(p, this.zero)) return p;
|
||||
|
||||
const A = F.square( p[0] ); // A = X1^2
|
||||
const B = F.square( p[1] ); // B = Y1^2
|
||||
const C = F.square( B ); // C = B^2
|
||||
|
||||
let D =
|
||||
F.sub(
|
||||
F.square( F.add(p[0] , B )),
|
||||
F.add( A , C));
|
||||
D = F.add(D,D); // D = 2 * ((X1 + B)^2 - A - C)
|
||||
|
||||
const E = F.add( F.add(A,A), A); // E = 3 * A
|
||||
const FF =F.square( E ); // F = E^2
|
||||
|
||||
res[0] = F.sub( FF , F.add(D,D) ); // X3 = F - 2 D
|
||||
|
||||
let eightC = F.add( C , C );
|
||||
eightC = F.add( eightC , eightC );
|
||||
eightC = F.add( eightC , eightC );
|
||||
|
||||
res[1] =
|
||||
F.sub(
|
||||
F.mul(
|
||||
E,
|
||||
F.sub( D, res[0] )),
|
||||
eightC); // Y3 = E * (D - X3) - 8 * C
|
||||
|
||||
const Y1Z1 = F.mul( p[1] , p[2] );
|
||||
res[2] = F.add( Y1Z1 , Y1Z1 ); // Z3 = 2 * Y1 * Z1
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
mulScalar(base, e) {
|
||||
return fUtils.mulScalar(this, base, e);
|
||||
}
|
||||
|
||||
affine(p) {
|
||||
const F = this.F;
|
||||
if (this.eq(p, this.zero)) {
|
||||
return this.zero;
|
||||
} else {
|
||||
const Z_inv = F.inv(p[2]);
|
||||
const Z2_inv = F.square(Z_inv);
|
||||
const Z3_inv = F.mul(Z2_inv, Z_inv);
|
||||
|
||||
const res = new Array(3);
|
||||
res[0] = F.mul(p[0],Z2_inv);
|
||||
res[1] = F.mul(p[1],Z3_inv);
|
||||
res[2] = F.one;
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
eq(p1, p2) {
|
||||
const F = this.F;
|
||||
|
||||
if (this.F.eq(p1[2], this.F.zero)) return this.F.eq(p2[2], this.F.zero);
|
||||
if (this.F.eq(p2[2], this.F.zero)) return false;
|
||||
|
||||
const Z1Z1 = F.square( p1[2] );
|
||||
const Z2Z2 = F.square( p2[2] );
|
||||
|
||||
const U1 = F.mul( p1[0] , Z2Z2 );
|
||||
const U2 = F.mul( p2[0] , Z1Z1 );
|
||||
|
||||
const Z1_cubed = F.mul( p1[2] , Z1Z1);
|
||||
const Z2_cubed = F.mul( p2[2] , Z2Z2);
|
||||
|
||||
const S1 = F.mul( p1[1] , Z2_cubed);
|
||||
const S2 = F.mul( p2[1] , Z1_cubed);
|
||||
|
||||
return (F.eq(U1,U2) && F.eq(S1,S2));
|
||||
}
|
||||
|
||||
toString(p) {
|
||||
const cp = this.affine(p);
|
||||
return `[ ${this.F.toString(cp[0])} , ${this.F.toString(cp[1])} ]`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GCurve;
|
||||
|
527
src/polfield.js
527
src/polfield.js
@ -1,527 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
This library does operations on polynomials with coefficients in a field F.
|
||||
|
||||
A polynomial P(x) = p0 + p1 * x + p2 * x^2 + ... + pn * x^n is represented
|
||||
by the array [ p0, p1, p2, ... , pn ].
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
class PolField {
|
||||
constructor (F) {
|
||||
this.F = F;
|
||||
|
||||
const q = this.F.p;
|
||||
let rem = q.minus(bigInt(1));
|
||||
let s = 0;
|
||||
while (!rem.isOdd()) {
|
||||
s ++;
|
||||
rem = rem.shiftRight(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.wi = new Array(s+1);
|
||||
this.w[s] = this.F.pow(five, rem);
|
||||
this.wi[s] = this.F.inv(this.w[s]);
|
||||
|
||||
let n=s-1;
|
||||
while (n>=0) {
|
||||
this.w[n] = this.F.square(this.w[n+1]);
|
||||
this.wi[n] = this.F.square(this.wi[n+1]);
|
||||
n--;
|
||||
}
|
||||
|
||||
|
||||
this.roots = [];
|
||||
/* for (let i=0; i<16; i++) {
|
||||
let r = this.F.one;
|
||||
n = 1 << i;
|
||||
const rootsi = new Array(n);
|
||||
for (let j=0; j<n; j++) {
|
||||
rootsi[j] = r;
|
||||
r = this.F.mul(r, this.w[i]);
|
||||
}
|
||||
|
||||
this.roots.push(rootsi);
|
||||
}
|
||||
*/
|
||||
this._setRoots(15);
|
||||
}
|
||||
|
||||
_setRoots(n) {
|
||||
for (let i=n; (i>=0) && (!this.roots[i]); i--) {
|
||||
let r = this.F.one;
|
||||
const nroots = 1 << i;
|
||||
const rootsi = new Array(nroots);
|
||||
for (let j=0; j<nroots; j++) {
|
||||
rootsi[j] = r;
|
||||
r = this.F.mul(r, this.w[i]);
|
||||
}
|
||||
|
||||
this.roots[i] = rootsi;
|
||||
}
|
||||
}
|
||||
|
||||
add(a, b) {
|
||||
const m = Math.max(a.length, b.length);
|
||||
const res = new Array(m);
|
||||
for (let i=0; i<m; i++) {
|
||||
res[i] = this.F.add(a[i] || this.F.zero, b[i] || this.F.zero);
|
||||
}
|
||||
return this.reduce(res);
|
||||
}
|
||||
|
||||
double(a) {
|
||||
return this.add(a,a);
|
||||
}
|
||||
|
||||
sub(a, b) {
|
||||
const m = Math.max(a.length, b.length);
|
||||
const res = new Array(m);
|
||||
for (let i=0; i<m; i++) {
|
||||
res[i] = this.F.sub(a[i] || this.F.zero, b[i] || this.F.zero);
|
||||
}
|
||||
return this.reduce(res);
|
||||
}
|
||||
|
||||
mulScalar(p, b) {
|
||||
if (this.F.eq(b, this.F.zero)) return [];
|
||||
if (this.F.eq(b, this.F.one)) return p;
|
||||
const res = new Array(p.length);
|
||||
for (let i=0; i<p.length; i++) {
|
||||
res[i] = this.F.mul(p[i], b);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
mul(a, b) {
|
||||
if (a.length == 0) return [];
|
||||
if (b.length == 0) return [];
|
||||
if (a.length == 1) return this.mulScalar(b, a[0]);
|
||||
if (b.length == 1) return this.mulScalar(a, b[0]);
|
||||
|
||||
if (b.length > a.length) {
|
||||
[b, a] = [a, b];
|
||||
}
|
||||
|
||||
if ((b.length <= 2) || (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 bitsResult = log2(longestN-1)+2;
|
||||
this._setRoots(bitsResult);
|
||||
|
||||
const m = 1 << bitsResult;
|
||||
const ea = this.extend(a,m);
|
||||
const eb = this.extend(b,m);
|
||||
|
||||
const ta = __fft(this, ea, bitsResult, 0, 1, false);
|
||||
const tb = __fft(this, eb, bitsResult, 0, 1, false);
|
||||
|
||||
const tres = new Array(m);
|
||||
|
||||
for (let i=0; i<m; i++) {
|
||||
tres[i] = this.F.mul(ta[i], tb[i]);
|
||||
}
|
||||
|
||||
const res = __fft(this, tres, bitsResult, 0, 1, true);
|
||||
|
||||
const twoinvm = this.F.inv( this.F.mulScalar(this.F.one, m) );
|
||||
const resn = new Array(m);
|
||||
for (let i=0; i<m; i++) {
|
||||
resn[i] = this.F.mul(res[(m-i)%m], twoinvm);
|
||||
}
|
||||
|
||||
return this.reduce(resn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
square(a) {
|
||||
return this.mul(a,a);
|
||||
}
|
||||
|
||||
scaleX(p, n) {
|
||||
if (n==0) {
|
||||
return p;
|
||||
} else if (n>0) {
|
||||
const z = new Array(n).fill(this.F.zero);
|
||||
return z.concat(p);
|
||||
} else {
|
||||
if (-n >= p.length) return [];
|
||||
return p.slice(-n);
|
||||
}
|
||||
}
|
||||
|
||||
eval2(p, x) {
|
||||
let v = this.F.zero;
|
||||
let ix = this.F.one;
|
||||
for (let i=0; i<p.length; i++) {
|
||||
v = this.F.add(v, this.F.mul(p[i], ix));
|
||||
ix = this.F.mul(ix, x);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
eval(p,x) {
|
||||
const F = this.F;
|
||||
if (p.length == 0) return F.zero;
|
||||
const m = this._next2Power(p.length);
|
||||
const ep = this.extend(p, m);
|
||||
|
||||
return _eval(ep, x, 0, 1, m);
|
||||
|
||||
function _eval(p, x, offset, step, n) {
|
||||
if (n==1) return p[offset];
|
||||
const newX = F.square(x);
|
||||
const res= F.add(
|
||||
_eval(p, newX, offset, step << 1, n >> 1),
|
||||
F.mul(
|
||||
x,
|
||||
_eval(p, newX, offset+step , step << 1, n >> 1)));
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
lagrange(points) {
|
||||
let roots = [this.F.one];
|
||||
for (let i=0; i<points.length; i++) {
|
||||
roots = this.mul(roots, [this.F.neg(points[i][0]), this.F.one]);
|
||||
}
|
||||
|
||||
let sum = [];
|
||||
for (let i=0; i<points.length; i++) {
|
||||
let mpol = this.ruffini(roots, points[i][0]);
|
||||
const factor =
|
||||
this.F.mul(
|
||||
this.F.inv(this.eval(mpol, points[i][0])),
|
||||
points[i][1]);
|
||||
mpol = this.mulScalar(mpol, factor);
|
||||
sum = this.add(sum, mpol);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
fft(p) {
|
||||
if (p.length <= 1) return p;
|
||||
const bits = log2(p.length-1)+1;
|
||||
this._setRoots(bits);
|
||||
|
||||
const m = 1 << bits;
|
||||
const ep = this.extend(p, m);
|
||||
const res = __fft(this, ep, bits, 0, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
ifft(p) {
|
||||
|
||||
if (p.length <= 1) return p;
|
||||
const bits = log2(p.length-1)+1;
|
||||
this._setRoots(bits);
|
||||
const m = 1 << bits;
|
||||
const ep = this.extend(p, m);
|
||||
const res = __fft(this, ep, bits, 0, 1);
|
||||
|
||||
const twoinvm = this.F.inv( this.F.mulScalar(this.F.one, m) );
|
||||
const resn = new Array(m);
|
||||
for (let i=0; i<m; i++) {
|
||||
resn[i] = this.F.mul(res[(m-i)%m], twoinvm);
|
||||
}
|
||||
|
||||
return resn;
|
||||
|
||||
}
|
||||
|
||||
|
||||
_fft(pall, bits, offset, step) {
|
||||
|
||||
const n = 1 << bits;
|
||||
if (n==1) {
|
||||
return [ pall[offset] ];
|
||||
}
|
||||
|
||||
const ndiv2 = n >> 1;
|
||||
const p1 = this._fft(pall, bits-1, offset, step*2);
|
||||
const p2 = this._fft(pall, bits-1, offset+step, step*2);
|
||||
|
||||
const out = new Array(n);
|
||||
|
||||
let m= this.F.one;
|
||||
for (let i=0; i<ndiv2; 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]));
|
||||
m = this.F.mul(m, this.w[bits]);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
extend(p, e) {
|
||||
if (e == p.length) return p;
|
||||
const z = new Array(e-p.length).fill(this.F.zero);
|
||||
|
||||
return p.concat(z);
|
||||
}
|
||||
|
||||
reduce(p) {
|
||||
if (p.length == 0) return p;
|
||||
if (! this.F.eq(p[p.length-1], this.F.zero) ) return p;
|
||||
let i=p.length-1;
|
||||
while( i>0 && this.F.eq(p[i], this.F.zero) ) i--;
|
||||
return p.slice(0, i+1);
|
||||
}
|
||||
|
||||
equals(a, b) {
|
||||
const pa = this.reduce(this.affine(a));
|
||||
const pb = this.reduce(this.affine(b));
|
||||
|
||||
if (pa.length != pb.length) return false;
|
||||
for (let i=0; i<pb.length; i++) {
|
||||
if (!this.F.eq(pa[i], pb[i])) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ruffini(p, r) {
|
||||
const res = new Array(p.length-1);
|
||||
res[res.length-1] = p[p.length-1];
|
||||
for (let i = res.length-2; i>=0; i--) {
|
||||
res[i] = this.F.add(this.F.mul(res[i+1], r), p[i+1]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
_next2Power(v) {
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v++;
|
||||
return v;
|
||||
}
|
||||
|
||||
toString(p) {
|
||||
const ap = this.affine(p);
|
||||
let S = "";
|
||||
for (let i=ap.length-1; i>=0; i--) {
|
||||
if (!this.F.eq(p[i], this.F.zero)) {
|
||||
if (S!="") S += " + ";
|
||||
S = S + p[i].toString(10);
|
||||
if (i>0) {
|
||||
S = S + "x";
|
||||
if (i>1) {
|
||||
S = S + "^" +i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return S;
|
||||
}
|
||||
|
||||
|
||||
_reciprocal(p, bits) {
|
||||
const k = 1 << bits;
|
||||
if (k==1) {
|
||||
return [ this.F.inv(p[0]) ];
|
||||
}
|
||||
const np = this.scaleX(p, -k/2);
|
||||
const q = this._reciprocal(np, bits-1);
|
||||
const a = this.scaleX(this.double(q), 3*k/2-2);
|
||||
const b = this.mul( this.square(q), p);
|
||||
|
||||
return this.scaleX(this.sub(a,b), -(k-2));
|
||||
}
|
||||
|
||||
// divides x^m / v
|
||||
_div2(m, v) {
|
||||
const kbits = log2(v.length-1)+1;
|
||||
const k = 1 << kbits;
|
||||
|
||||
const scaleV = k - v.length;
|
||||
|
||||
// rec = x^(k - 2) / v* x^scaleV =>
|
||||
// rec = x^(k-2-scaleV)/ v
|
||||
//
|
||||
// res = x^m/v = x^(m + (2*k-2 - scaleV) - (2*k-2 - scaleV)) /v =>
|
||||
// res = rec * x^(m - (2*k-2 - scaleV)) =>
|
||||
// res = rec * x^(m - 2*k + 2 + scaleV)
|
||||
|
||||
const rec = this._reciprocal(this.scaleX(v, scaleV), kbits);
|
||||
const res = this.scaleX(rec, m - 2*k + 2 + scaleV);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
div(_u, _v) {
|
||||
if (_u.length < _v.length) return [];
|
||||
const kbits = log2(_v.length-1)+1;
|
||||
const k = 1 << kbits;
|
||||
|
||||
const u = this.scaleX(_u, k-_v.length);
|
||||
const v = this.scaleX(_v, k-_v.length);
|
||||
|
||||
const n = v.length-1;
|
||||
let m = u.length-1;
|
||||
|
||||
const s = this._reciprocal(v, kbits);
|
||||
let t;
|
||||
if (m>2*n) {
|
||||
t = this.sub(this.scaleX([this.F.one], 2*n), this.mul(s, v));
|
||||
}
|
||||
|
||||
let q = [];
|
||||
let rem = u;
|
||||
let us, ut;
|
||||
let finish = false;
|
||||
|
||||
while (!finish) {
|
||||
us = this.mul(rem, s);
|
||||
q = this.add(q, this.scaleX(us, -2*n));
|
||||
|
||||
if ( m > 2*n ) {
|
||||
ut = this.mul(rem, t);
|
||||
rem = this.scaleX(ut, -2*n);
|
||||
m = rem.length-1;
|
||||
} else {
|
||||
finish = true;
|
||||
}
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
// returns the ith nth-root of one
|
||||
oneRoot(n, i) {
|
||||
let nbits = log2(n-1)+1;
|
||||
let res = this.F.one;
|
||||
let r = i;
|
||||
|
||||
if(i>=n) {
|
||||
throw new Error("Given 'i' should be lower than 'n'");
|
||||
}
|
||||
else if (1<<nbits !== n) {
|
||||
throw new Error(`Internal errlr: ${n} should equal ${1<<nbits}`);
|
||||
}
|
||||
|
||||
while (r>0) {
|
||||
if (r & 1 == 1) {
|
||||
res = this.F.mul(res, this.w[nbits]);
|
||||
}
|
||||
r = r >> 1;
|
||||
nbits --;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
computeVanishingPolinomial(bits, t) {
|
||||
const m = 1 << bits;
|
||||
return this.F.sub(this.F.pow(t, bigInt(m)), this.F.one);
|
||||
}
|
||||
|
||||
evaluateLagrangePolynomials(bits, t) {
|
||||
const m= 1 << bits;
|
||||
const tm = this.F.pow(t, bigInt(m));
|
||||
const u= new Array(m).fill(this.F.zero);
|
||||
this._setRoots(bits);
|
||||
const omega = this.w[bits];
|
||||
|
||||
if (this.F.eq(tm, this.F.one)) {
|
||||
for (let i = 0; i < m; i++) {
|
||||
if (this.F.eq(this.roots[bits][0],t)) { // i.e., t equals omega^i
|
||||
u[i] = this.F.one;
|
||||
return u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const z = this.F.sub(tm, this.F.one);
|
||||
// let l = this.F.mul(z, this.F.pow(this.F.twoinv, m));
|
||||
let l = this.F.mul(z, this.F.inv(bigInt(m)));
|
||||
for (let i = 0; i < m; i++) {
|
||||
u[i] = this.F.mul(l, this.F.inv(this.F.sub(t,this.roots[bits][i])));
|
||||
l = this.F.mul(l, omega);
|
||||
}
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
log2(V) {
|
||||
return log2(V);
|
||||
}
|
||||
}
|
||||
|
||||
function log2( V )
|
||||
{
|
||||
return( ( ( V & 0xFFFF0000 ) !== 0 ? ( V &= 0xFFFF0000, 16 ) : 0 ) | ( ( V & 0xFF00FF00 ) !== 0 ? ( V &= 0xFF00FF00, 8 ) : 0 ) | ( ( V & 0xF0F0F0F0 ) !== 0 ? ( V &= 0xF0F0F0F0, 4 ) : 0 ) | ( ( V & 0xCCCCCCCC ) !== 0 ? ( V &= 0xCCCCCCCC, 2 ) : 0 ) | ( ( V & 0xAAAAAAAA ) !== 0 ) );
|
||||
}
|
||||
|
||||
|
||||
function __fft(PF, pall, bits, offset, step) {
|
||||
|
||||
const n = 1 << bits;
|
||||
if (n==1) {
|
||||
return [ pall[offset] ];
|
||||
} else if (n==2) {
|
||||
return [
|
||||
PF.F.add(pall[offset], pall[offset + step]),
|
||||
PF.F.sub(pall[offset], pall[offset + step])];
|
||||
}
|
||||
|
||||
const ndiv2 = n >> 1;
|
||||
const p1 = __fft(PF, pall, bits-1, offset, step*2);
|
||||
const p2 = __fft(PF, pall, bits-1, offset+step, step*2);
|
||||
|
||||
const out = new Array(n);
|
||||
|
||||
for (let i=0; i<ndiv2; i++) {
|
||||
out[i] = PF.F.add(p1[i], PF.F.mul(PF.roots[bits][i], p2[i]));
|
||||
out[i+ndiv2] = PF.F.sub(p1[i], PF.F.mul(PF.roots[bits][i], p2[i]));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
module.exports = PolField;
|
@ -19,11 +19,10 @@
|
||||
|
||||
/* Implementation of this paper: https://eprint.iacr.org/2016/260.pdf */
|
||||
|
||||
const BN128 = require("./bn128.js");
|
||||
const PolField = require("./polfield.js");
|
||||
const bn128 = require("ffjavascript").bn128;
|
||||
const PolField = require("ffjavascript").PolField;
|
||||
const ZqField = require("ffjavascript").ZqField;
|
||||
|
||||
const bn128 = new BN128();
|
||||
const PolF = new PolField(new ZqField(bn128.r));
|
||||
const G1 = bn128.G1;
|
||||
const G2 = bn128.G2;
|
||||
|
@ -19,14 +19,13 @@
|
||||
|
||||
/* Implementation of this paper: https://eprint.iacr.org/2016/260.pdf */
|
||||
|
||||
const BN128 = require("./bn128.js");
|
||||
const PolField = require("./polfield.js");
|
||||
const bn128 = require("ffjavascript").bn128;
|
||||
const PolField = require("ffjavascript").PolField;
|
||||
const ZqField = require("ffjavascript").ZqField;
|
||||
const createKeccakHash = require("keccak");
|
||||
const utils = require("./utils");
|
||||
|
||||
|
||||
const bn128 = new BN128();
|
||||
const PolF = new PolField(new ZqField(bn128.r));
|
||||
const G1 = bn128.G1;
|
||||
const G2 = bn128.G2;
|
||||
|
@ -17,11 +17,10 @@
|
||||
snarkjs. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const BN128 = require("./bn128.js");
|
||||
const PolField = require("./polfield.js");
|
||||
const bn128 = require("ffjavascript").bn128;
|
||||
const PolField = require("ffjavascript").PolField;
|
||||
const ZqField = require("ffjavascript").ZqField;
|
||||
|
||||
const bn128 = new BN128();
|
||||
const PolF = new PolField(new ZqField(bn128.r));
|
||||
const G1 = bn128.G1;
|
||||
const G2 = bn128.G2;
|
||||
|
@ -1,296 +0,0 @@
|
||||
const fs = require("fs");
|
||||
const assert = require("assert");
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
module.exports.loadR1cs = loadR1cs;
|
||||
module.exports.loadR1csSynch = loadR1csSync;
|
||||
|
||||
async function loadR1cs(fileName) {
|
||||
const res = {};
|
||||
const fd = await fs.promises.open(fileName, "r");
|
||||
|
||||
const b = Buffer.allocUnsafe(4);
|
||||
await fd.read(b, 0, 4, 0);
|
||||
if (b.toString() != "r1cs") assert(false, "Invalid File format");
|
||||
|
||||
let p=4;
|
||||
|
||||
let v = await readU32();
|
||||
|
||||
if (v>1) assert(false, "Version not supported");
|
||||
|
||||
const nSections = await readU32();
|
||||
|
||||
let pHeader;
|
||||
let pConstraints;
|
||||
let headerSize;
|
||||
let constraintsSize;
|
||||
let pMap;
|
||||
let mapSize;
|
||||
for (let i=0; i<nSections; i++) {
|
||||
let ht = await readU32();
|
||||
let hl = await readDouble64();
|
||||
if (ht == 1) {
|
||||
if (typeof pHeader != "undefined") assert(false, "File has two headder sections");
|
||||
pHeader = p;
|
||||
headerSize = hl;
|
||||
} else if (ht==2) {
|
||||
if (typeof pConstraints != "undefined") assert(false, "File has two constraints sections");
|
||||
pConstraints = p;
|
||||
constraintsSize = hl;
|
||||
} else if (ht==3) {
|
||||
pMap = p;
|
||||
mapSize = hl;
|
||||
}
|
||||
p += hl;
|
||||
}
|
||||
|
||||
if (typeof pHeader == "undefined") assert(false, "File has two header");
|
||||
|
||||
// Read Header
|
||||
p = pHeader;
|
||||
const fieldDefSize = await readU32();
|
||||
const pFieldDef = p;
|
||||
|
||||
const defType = await readU32();
|
||||
if (defType != 1) if (typeof pConstraints != "undefined") assert(false, "Field type not supported");
|
||||
|
||||
res.prime = await readBigInt();
|
||||
|
||||
if ( p != pFieldDef + fieldDefSize) assert("Invalid fieldDef size");
|
||||
|
||||
const bigIntFormat = await readU32();
|
||||
if (bigIntFormat != 0) assert(false, "BigInt format not supported");
|
||||
|
||||
const idSize = await readU32();
|
||||
if (idSize != 4) assert(false, "idSize not supported. Mus be 4");
|
||||
|
||||
res.nVars = await readU32();
|
||||
res.nOutputs = await readU32();
|
||||
res.nPubInputs = await readU32();
|
||||
res.nPrvIns = await readU32();
|
||||
res.nLabels = await readU32();
|
||||
res.nConstraints = await readU32();
|
||||
|
||||
if (p != pHeader + headerSize) assert(false, "Invalid header section size");
|
||||
|
||||
// Read Constraints
|
||||
p = pConstraints;
|
||||
|
||||
res.constraints = [];
|
||||
for (let i=0; i<res.nConstraints; i++) {
|
||||
const c = await readConstraint();
|
||||
res.constraints.push(c);
|
||||
}
|
||||
if (p != pConstraints + constraintsSize) assert(false, "Invalid constraints size");
|
||||
|
||||
await fd.close();
|
||||
|
||||
return res;
|
||||
|
||||
async function readU32() {
|
||||
const b = Buffer.allocUnsafe(4);
|
||||
await fd.read(b, 0, 4, p);
|
||||
p+=4;
|
||||
|
||||
return b.readInt32LE(0);
|
||||
}
|
||||
|
||||
async function readDouble64() {
|
||||
const b = Buffer.allocUnsafe(8);
|
||||
await fd.read(b, 0, 8, p);
|
||||
|
||||
p+=8;
|
||||
|
||||
return b.readDoubleLE(0);
|
||||
}
|
||||
|
||||
async function readBigInt() {
|
||||
const bl = Buffer.allocUnsafe(1);
|
||||
await fd.read(bl, 0, 1, p);
|
||||
p++;
|
||||
|
||||
const l = bl[0];
|
||||
const b = Buffer.allocUnsafe(l);
|
||||
await fd.read(b, 0, l, p);
|
||||
p += l;
|
||||
|
||||
const arr = Uint8Array.from(b);
|
||||
|
||||
const arrr = new Array(arr.length);
|
||||
for (let i=0; i<arr.length; i++) {
|
||||
arrr[i] = arr[arr.length-1-i];
|
||||
}
|
||||
|
||||
const n = bigInt.fromArray(arrr, 256);
|
||||
|
||||
return n.toString();
|
||||
}
|
||||
|
||||
async function readConstraint() {
|
||||
const c = [];
|
||||
c.push(await readLC());
|
||||
c.push(await readLC());
|
||||
c.push(await readLC());
|
||||
return c;
|
||||
}
|
||||
|
||||
async function readLC() {
|
||||
const lc= {};
|
||||
const nIdx = await readU32();
|
||||
for (let i=0; i<nIdx; i++) {
|
||||
const idx = await readU32();
|
||||
const val = await readBigInt();
|
||||
lc[idx] = val;
|
||||
}
|
||||
return lc;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadR1cs(fileName) {
|
||||
const res = {};
|
||||
const fd = fs.openSync(fileName, "r");
|
||||
|
||||
const b = Buffer.allocUnsafe(4);
|
||||
fs.readSync(fd, b, 0, 4, 0);
|
||||
if (b.toString() != "r1cs") assert(false, "Invalid File format");
|
||||
|
||||
let p=4;
|
||||
|
||||
let v = readU32();
|
||||
|
||||
if (v>1) assert(false, "Version not supported");
|
||||
|
||||
const nSections = readU32();
|
||||
|
||||
let pHeader;
|
||||
let pConstraints;
|
||||
let headerSize;
|
||||
let constraintsSize;
|
||||
for (let i=0; i<nSections; i++) {
|
||||
let ht = readU32();
|
||||
let hl = readU64();
|
||||
if (ht == 1) {
|
||||
if (typeof pHeader != "undefined") assert(false, "File has two headder sections");
|
||||
pHeader = p;
|
||||
headerSize = hl;
|
||||
} else if (ht==2) {
|
||||
if (typeof pConstraints != "undefined") assert(false, "File has two constraints sections");
|
||||
pConstraints = p;
|
||||
constraintsSize = hl;
|
||||
}
|
||||
p += hl;
|
||||
}
|
||||
|
||||
if (typeof pHeader == "undefined") assert(false, "File has no header");
|
||||
|
||||
// Read Header
|
||||
p = pHeader;
|
||||
|
||||
const n8 = await readU32();
|
||||
res.prime = await readBigInt();
|
||||
|
||||
res.nWires = await readU32();
|
||||
res.nPubOuts = await readU32();
|
||||
res.nPubIns = await readU32();
|
||||
res.nPrvIns = await readU32();
|
||||
res.nLabels = await readU64();
|
||||
res.nConstraints = await readU32();
|
||||
|
||||
|
||||
const fieldDefSize = readU32();
|
||||
const pFieldDef = p;
|
||||
|
||||
const defType = readU32();
|
||||
if (defType != 1) if (typeof pConstraints != "undefined") assert(false, "Field type not supported");
|
||||
|
||||
res.prime = readBigInt();
|
||||
|
||||
if ( p != pFieldDef + fieldDefSize) assert("Invalid fieldDef size");
|
||||
|
||||
const bigIntFormat = readU32();
|
||||
if (bigIntFormat != 0) assert(false, "BigInt format not supported");
|
||||
|
||||
const idSize = readU32();
|
||||
if (idSize != 4) assert(false, "idSize not supported. Mus be 4");
|
||||
|
||||
res.nVars = readU32();
|
||||
res.nOutputs = readU32();
|
||||
res.nPubInputs = readU32();
|
||||
res.nPrvIns = readU32();
|
||||
res.nLabels = readU32();
|
||||
res.nConstraints = readU32();
|
||||
|
||||
if (p != pHeader + headerSize) assert(false, "Invalid header section size");
|
||||
|
||||
// Read Constraints
|
||||
p = pConstraints;
|
||||
|
||||
res.constraints = [];
|
||||
for (let i=0; i<res.nConstraints; i++) {
|
||||
const c = readConstraint();
|
||||
res.constraints.push(c);
|
||||
}
|
||||
if (p != pConstraints + constraintsSize) assert(false, "Invalid constraints size");
|
||||
|
||||
fs.closeSync(fd);
|
||||
|
||||
return res;
|
||||
|
||||
function readU32() {
|
||||
const b = Buffer.allocUnsafe(4);
|
||||
fs.readSync(fd, b, 0, 4, p);
|
||||
p+=4;
|
||||
|
||||
return b.readInt32LE(0);
|
||||
}
|
||||
|
||||
function readDouble64() {
|
||||
const b = Buffer.allocUnsafe(8);
|
||||
fs.readSync(fd, b, 0, 8, p);
|
||||
p+=8;
|
||||
|
||||
return b.readDoubleLE(0);
|
||||
}
|
||||
|
||||
function readBigInt() {
|
||||
const bl = Buffer.allocUnsafe(1);
|
||||
fs.readSync(fd, bl, 0, 1, p);
|
||||
p++;
|
||||
|
||||
const l = bl[0];
|
||||
const b = Buffer.allocUnsafe(l);
|
||||
fs.readSync(fd,b, 0, l, p);
|
||||
p += l;
|
||||
|
||||
const arr = Uint8Array.from(b);
|
||||
|
||||
const arrr = new Array(arr.length);
|
||||
for (let i=0; i<arr.length; i++) {
|
||||
arrr[i] = arr[arr.length-1-i];
|
||||
}
|
||||
|
||||
const n = bigInt.fromArray(arrr, 256);
|
||||
|
||||
return n.toString();
|
||||
}
|
||||
|
||||
function readConstraint() {
|
||||
const c = [];
|
||||
c.push(readLC());
|
||||
c.push(readLC());
|
||||
c.push(readLC());
|
||||
return c;
|
||||
}
|
||||
|
||||
function readLC() {
|
||||
const lc= {};
|
||||
const nIdx = readU32();
|
||||
for (let i=0; i<nIdx; i++) {
|
||||
const idx = readU32();
|
||||
const val = readBigInt();
|
||||
lc[idx] = val;
|
||||
}
|
||||
return lc;
|
||||
}
|
||||
}
|
127
src/ratfield.js
127
src/ratfield.js
@ -1,127 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
const fUtils = require("./futils.js");
|
||||
|
||||
class RatField {
|
||||
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]),
|
||||
];
|
||||
}
|
||||
|
||||
inv(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 = RatField;
|
@ -21,11 +21,10 @@
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
const BN128 = require("./bn128.js");
|
||||
const PolField = require("./polfield.js");
|
||||
const bn128 = require("ffjavascript").bn128;
|
||||
const PolField = require("ffjavascript").PolField;
|
||||
const ZqField = require("ffjavascript").ZqField;
|
||||
|
||||
const bn128 = new BN128();
|
||||
const G1 = bn128.G1;
|
||||
const G2 = bn128.G2;
|
||||
const PolF = new PolField(new ZqField(bn128.r));
|
||||
|
@ -21,11 +21,10 @@
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
const BN128 = require("./bn128.js");
|
||||
const PolField = require("./polfield.js");
|
||||
const bn128 = require("ffjavascript").bn128;
|
||||
const PolField = require("ffjavascript").PolField;
|
||||
const ZqField = require("ffjavascript").ZqField;
|
||||
|
||||
const bn128 = new BN128();
|
||||
const G1 = bn128.G1;
|
||||
const G2 = bn128.G2;
|
||||
const PolF = new PolField(new ZqField(bn128.r));
|
||||
|
@ -19,11 +19,10 @@
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
const BN128 = require("./bn128.js");
|
||||
const PolField = require("./polfield.js");
|
||||
const bn128 = require("ffjavascript").bn128;
|
||||
const PolField = require("ffjavascript").PolField;
|
||||
const ZqField = require("ffjavascript").ZqField;
|
||||
|
||||
const bn128 = new BN128();
|
||||
const G1 = bn128.G1;
|
||||
const G2 = bn128.G2;
|
||||
const PolF = new PolField(new ZqField(bn128.r));
|
||||
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
module.exports.stringifyBigInts = stringifyBigInts;
|
||||
module.exports.unstringifyBigInts = unstringifyBigInts;
|
||||
|
||||
function stringifyBigInts(o) {
|
||||
if ((typeof(o) == "bigint") || o.isZero !== undefined) {
|
||||
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;
|
||||
}
|
||||
}
|
47
src/utils.js
47
src/utils.js
@ -1,15 +1,21 @@
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
exports.beBuff2int = function(buff) {
|
||||
|
||||
module.exports.stringifyBigInts = stringifyBigInts;
|
||||
module.exports.unstringifyBigInts = unstringifyBigInts;
|
||||
module.exports.beBuff2int = beBuff2int;
|
||||
module.exports.beInt2Buff = beInt2Buff;
|
||||
|
||||
function beBuff2int(buff) {
|
||||
let res = bigInt.zero;
|
||||
for (let i=0; i<buff.length; i++) {
|
||||
const n = bigInt(buff[buff.length - i - 1]);
|
||||
res = res.add(n.shiftLeft(i*8));
|
||||
}
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
exports.beInt2Buff = function(n, len) {
|
||||
function beInt2Buff(n, len) {
|
||||
let r = n;
|
||||
let o =len-1;
|
||||
const buff = Buffer.alloc(len);
|
||||
@ -21,4 +27,37 @@ exports.beInt2Buff = function(n, len) {
|
||||
}
|
||||
if (r.greater(bigInt.zero)) throw new Error("Number does not feed in buffer");
|
||||
return buff;
|
||||
};
|
||||
}
|
||||
|
||||
function stringifyBigInts(o) {
|
||||
if ((typeof(o) == "bigint") || o.eq !== undefined) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
const BN128 = require("./bn128.js");
|
||||
|
||||
const bn128 = new BN128();
|
||||
const G1 = bn128.G1;
|
||||
const G2 = bn128.G2;
|
||||
|
||||
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++) {
|
||||
full_pi_a = G1.add( full_pi_a, G1.mulScalar( vk_verifier.A[s+1], publicSignals[s]));
|
||||
}
|
||||
|
||||
full_pi_a = G1.add( full_pi_a, proof.pi_a);
|
||||
|
||||
if (! bn128.F12.equals(
|
||||
bn128.pairing( proof.pi_a , vk_verifier.vk_a ),
|
||||
bn128.pairing( proof.pi_ap , G2.g )))
|
||||
return false;
|
||||
|
||||
if (! bn128.F12.equals(
|
||||
bn128.pairing( vk_verifier.vk_b, proof.pi_b ),
|
||||
bn128.pairing( proof.pi_bp , G2.g )))
|
||||
return false;
|
||||
|
||||
if (! bn128.F12.equals(
|
||||
bn128.pairing( proof.pi_c , vk_verifier.vk_c ),
|
||||
bn128.pairing( proof.pi_cp , 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 ),
|
||||
),
|
||||
bn128.pairing( proof.pi_kp , vk_verifier.vk_g )))
|
||||
return false;
|
||||
|
||||
if (! bn128.F12.equals(
|
||||
bn128.pairing( full_pi_a , proof.pi_b ),
|
||||
bn128.F12.mul(
|
||||
bn128.pairing( proof.pi_h , vk_verifier.vk_z ),
|
||||
bn128.pairing( proof.pi_c , G2.g ),
|
||||
)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
@ -20,9 +20,8 @@
|
||||
/* Implementation of this paper: https://eprint.iacr.org/2016/260.pdf */
|
||||
|
||||
|
||||
const BN128 = require("./bn128.js");
|
||||
const bn128 = require("ffjavascript").bn128;
|
||||
|
||||
const bn128 = new BN128();
|
||||
const G1 = bn128.G1;
|
||||
|
||||
module.exports = function isValid(vk_verifier, proof, publicSignals) {
|
||||
|
@ -20,11 +20,10 @@
|
||||
/* Implementation of this paper: https://eprint.iacr.org/2016/260.pdf */
|
||||
|
||||
|
||||
const BN128 = require("./bn128.js");
|
||||
const bn128 = require("ffjavascript").bn128;
|
||||
const createKeccakHash = require("keccak");
|
||||
const utils = require("./utils");
|
||||
|
||||
const bn128 = new BN128();
|
||||
const G1 = bn128.G1;
|
||||
const G2 = bn128.G2;
|
||||
|
||||
|
@ -17,9 +17,8 @@
|
||||
snarkjs. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const BN128 = require("./bn128.js");
|
||||
const bn128 = require("ffjavascript").bn128;
|
||||
|
||||
const bn128 = new BN128();
|
||||
const G1 = bn128.G1;
|
||||
const G2 = bn128.G2;
|
||||
|
||||
|
@ -1,151 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
const fUtils = require("./futils.js");
|
||||
|
||||
function getRandomByte() {
|
||||
if (typeof window !== "undefined") { // Browser
|
||||
if (typeof window.crypto !== "undefined") { // Supported
|
||||
let array = new Uint8Array(1);
|
||||
window.crypto.getRandomValues(array);
|
||||
return array[0];
|
||||
}
|
||||
else { // fallback
|
||||
return Math.floor(Math.random() * 256);
|
||||
}
|
||||
}
|
||||
else { // NodeJS
|
||||
return module.require("crypto").randomBytes(1)[0];
|
||||
}
|
||||
}
|
||||
|
||||
class ZqField {
|
||||
constructor(q) {
|
||||
this.q = bigInt(q);
|
||||
this.zero = bigInt.zero;
|
||||
this.one = bigInt.one;
|
||||
this.minusone = this.q.sub(this.one);
|
||||
this.add = bigInt.genAdd();
|
||||
this.double = bigInt.genDouble();
|
||||
this.sub = bigInt.genSub();
|
||||
this.neg = bigInt.genNeg();
|
||||
this.mul = bigInt.genMul(q);
|
||||
this.inverse = bigInt.genInverse(q);
|
||||
this.square = bigInt.genSquare(q);
|
||||
this.equals = bigInt.genEquals(q);
|
||||
this.affine = bigInt.genAffine(q);
|
||||
this.isZero = bigInt.genIsZero(q);
|
||||
this.two = this.add(this.one, this.one);
|
||||
this.twoinv = this.inverse(this.two);
|
||||
|
||||
const e = this.minusone.shr(this.one);
|
||||
this.nqr = this.two;
|
||||
let r = this.exp(this.nqr, e);
|
||||
while (!r.equals(this.minusone)) {
|
||||
this.nqr = this.nqr.add(this.one);
|
||||
r = this.exp(this.nqr, e);
|
||||
}
|
||||
|
||||
this.s = this.zero;
|
||||
this.t = this.minusone;
|
||||
|
||||
while (!this.t.isOdd()) {
|
||||
this.s = this.s.add(this.one);
|
||||
this.t = this.t.shr(this.one);
|
||||
}
|
||||
|
||||
this.nqr_to_t = this.exp(this.nqr, this.t);
|
||||
}
|
||||
|
||||
copy(a) {
|
||||
return bigInt(a);
|
||||
}
|
||||
|
||||
div(a, b) {
|
||||
return this.mul(a, this.inverse(b));
|
||||
}
|
||||
|
||||
mulScalar(base, e) {
|
||||
return this.mul(base, bigInt(e));
|
||||
}
|
||||
|
||||
exp(base, e) {
|
||||
return fUtils.exp(this, base, e);
|
||||
}
|
||||
|
||||
toString(a) {
|
||||
const ca = this.affine(a);
|
||||
return `"0x${ca.toString(16)}"`;
|
||||
}
|
||||
|
||||
random() {
|
||||
let res = bigInt(0);
|
||||
let n = bigInt(this.q);
|
||||
while (!n.isZero()) {
|
||||
res = res.shl(8).add(bigInt(getRandomByte()));
|
||||
n = n.shr(8);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
sqrt(n) {
|
||||
|
||||
n = this.affine(n);
|
||||
|
||||
if (n.equals(this.zero)) return this.zero;
|
||||
|
||||
// Test that have solution
|
||||
const res = this.exp(n, this.minusone.shr(this.one));
|
||||
if (!res.equals(this.one)) return null;
|
||||
|
||||
let m = parseInt(this.s);
|
||||
let c = this.nqr_to_t;
|
||||
let t = this.exp(n, this.t);
|
||||
let r = this.exp(n, this.add(this.t, this.one).shr(this.one) );
|
||||
|
||||
while (!t.equals(this.one)) {
|
||||
let sq = this.square(t);
|
||||
let i = 1;
|
||||
while (!sq.equals(this.one)) {
|
||||
i++;
|
||||
sq = this.square(sq);
|
||||
}
|
||||
|
||||
// b = c ^ m-i-1
|
||||
let b = c;
|
||||
for (let j=0; j< m-i-1; j ++) b = this.square(b);
|
||||
|
||||
m = i;
|
||||
c = this.square(b);
|
||||
t = this.mul(t, c);
|
||||
r = this.mul(r, b);
|
||||
}
|
||||
|
||||
if (r.greater(this.q.shr(this.one))) {
|
||||
r = this.neg(r);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
module.exports = ZqField;
|
254
test/algebra.js
254
test/algebra.js
@ -1,254 +0,0 @@
|
||||
/*
|
||||
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 bigInt = require("big-integer");
|
||||
const BN128 = require("../src/bn128.js");
|
||||
const F1Field = require("ffjavascript").ZqField;
|
||||
|
||||
const assert = chai.assert;
|
||||
|
||||
|
||||
describe("F1 testing", () => {
|
||||
it("Should compute euclidean", () => {
|
||||
const F = new F1Field(bigInt(7));
|
||||
const res = F.inv(bigInt(4));
|
||||
|
||||
assert(F.equals(res, bigInt(2)));
|
||||
});
|
||||
|
||||
it("Should multiply and divide in F1", () => {
|
||||
const bn128 = new BN128();
|
||||
const a = bigInt("1");
|
||||
const b = bn128.F1.affine(bigInt("-3"));
|
||||
const c = bn128.F1.mul(a,b);
|
||||
const d = bn128.F1.div(c,b);
|
||||
|
||||
assert(bn128.F1.equals(a, d));
|
||||
});
|
||||
|
||||
it("Should compute sqrts", () => {
|
||||
const bn128 = new BN128();
|
||||
const F = new F1Field(bn128.r);
|
||||
const a = bigInt("4");
|
||||
let b = F.sqrt(a);
|
||||
assert(F.equals(bigInt(0), F.sqrt(bigInt("0"))));
|
||||
assert(F.equals(b, bigInt("2")));
|
||||
assert(F.sqrt(F.nqr) === null);
|
||||
});
|
||||
|
||||
it("Should compute sqrt of 100 random numbers", () => {
|
||||
const bn128 = new BN128();
|
||||
const F = new F1Field(bn128.r);
|
||||
for (let j=0;j<100; j++) {
|
||||
let a = F.random();
|
||||
let s = F.sqrt(a);
|
||||
if (s != null) {
|
||||
assert(F.equals(F.square(s), a));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("Curve G1 Test", () => {
|
||||
it("r*one == 0", () => {
|
||||
const bn128 = new BN128();
|
||||
|
||||
const res = bn128.G1.mulScalar(bn128.G1.g, bn128.r);
|
||||
|
||||
assert(bn128.G1.equals(res, bn128.G1.zero), "G1 does not have range r");
|
||||
});
|
||||
|
||||
it("Should add match in various in G1", () => {
|
||||
|
||||
const bn128 = new BN128();
|
||||
|
||||
const r1 = bigInt(33);
|
||||
const r2 = bigInt(44);
|
||||
|
||||
const gr1 = bn128.G1.mulScalar(bn128.G1.g, r1);
|
||||
const gr2 = bn128.G1.mulScalar(bn128.G1.g, r2);
|
||||
|
||||
const grsum1 = bn128.G1.add(gr1, gr2);
|
||||
|
||||
const grsum2 = bn128.G1.mulScalar(bn128.G1.g, r1.add(r2));
|
||||
|
||||
assert(bn128.G1.equals(grsum1, grsum2));
|
||||
});
|
||||
});
|
||||
|
||||
describe("Curve G2 Test", () => {
|
||||
it ("r*one == 0", () => {
|
||||
const bn128 = new BN128();
|
||||
|
||||
const res = bn128.G2.mulScalar(bn128.G2.g, bn128.r);
|
||||
|
||||
assert(bn128.G2.equals(res, bn128.G2.zero), "G2 does not have range r");
|
||||
});
|
||||
|
||||
it("Should add match in various in G2", () => {
|
||||
const bn128 = new BN128();
|
||||
|
||||
const r1 = bigInt(33);
|
||||
const r2 = bigInt(44);
|
||||
|
||||
const gr1 = bn128.G2.mulScalar(bn128.G2.g, r1);
|
||||
const gr2 = bn128.G2.mulScalar(bn128.G2.g, r2);
|
||||
|
||||
const grsum1 = bn128.G2.add(gr1, gr2);
|
||||
|
||||
const grsum2 = bn128.G2.mulScalar(bn128.G2.g, r1.add(r2));
|
||||
|
||||
/*
|
||||
console.log(G2.toString(grsum1));
|
||||
console.log(G2.toString(grsum2));
|
||||
*/
|
||||
|
||||
assert(bn128.G2.equals(grsum1, grsum2));
|
||||
});
|
||||
});
|
||||
|
||||
describe("F6 testing", () => {
|
||||
it("Should multiply and divide in F6", () => {
|
||||
const bn128 = new BN128();
|
||||
const a =
|
||||
[
|
||||
[bigInt("1"), bigInt("2")],
|
||||
[bigInt("3"), bigInt("4")],
|
||||
[bigInt("5"), bigInt("6")]
|
||||
];
|
||||
const b =
|
||||
[
|
||||
[bigInt("12"), bigInt("11")],
|
||||
[bigInt("10"), bigInt("9")],
|
||||
[bigInt("8"), bigInt("7")]
|
||||
];
|
||||
const c = bn128.F6.mul(a,b);
|
||||
const d = bn128.F6.div(c,b);
|
||||
|
||||
assert(bn128.F6.equals(a, d));
|
||||
});
|
||||
});
|
||||
|
||||
describe("F12 testing", () => {
|
||||
it("Should multiply and divide in F12", () => {
|
||||
const bn128 = new BN128();
|
||||
const a =
|
||||
[
|
||||
[
|
||||
[bigInt("1"), bigInt("2")],
|
||||
[bigInt("3"), bigInt("4")],
|
||||
[bigInt("5"), bigInt("6")]
|
||||
],
|
||||
[
|
||||
[bigInt("7"), bigInt("8")],
|
||||
[bigInt("9"), bigInt("10")],
|
||||
[bigInt("11"), bigInt("12")]
|
||||
]
|
||||
];
|
||||
const b =
|
||||
[
|
||||
[
|
||||
[bigInt("12"), bigInt("11")],
|
||||
[bigInt("10"), bigInt("9")],
|
||||
[bigInt("8"), bigInt("7")]
|
||||
],
|
||||
[
|
||||
[bigInt("6"), bigInt("5")],
|
||||
[bigInt("4"), bigInt("3")],
|
||||
[bigInt("2"), bigInt("1")]
|
||||
]
|
||||
];
|
||||
const c = bn128.F12.mul(a,b);
|
||||
const d = bn128.F12.div(c,b);
|
||||
|
||||
assert(bn128.F12.equals(a, d));
|
||||
});
|
||||
});
|
||||
|
||||
describe("Pairing", () => {
|
||||
/*
|
||||
it("Should match pairing", () => {
|
||||
for (let i=0; i<1; i++) {
|
||||
const bn128 = new BN128();
|
||||
|
||||
const g1a = bn128.G1.mulScalar(bn128.G1.g, 25);
|
||||
const g2a = bn128.G2.mulScalar(bn128.G2.g, 30);
|
||||
|
||||
const g1b = bn128.G1.mulScalar(bn128.G1.g, 30);
|
||||
const g2b = bn128.G2.mulScalar(bn128.G2.g, 25);
|
||||
|
||||
const pre1a = bn128.precomputeG1(g1a);
|
||||
const pre2a = bn128.precomputeG2(g2a);
|
||||
const pre1b = bn128.precomputeG1(g1b);
|
||||
const pre2b = bn128.precomputeG2(g2b);
|
||||
|
||||
const r1 = bn128.millerLoop(pre1a, pre2a);
|
||||
const r2 = bn128.millerLoop(pre1b, pre2b);
|
||||
|
||||
const rbe = bn128.F12.mul(r1, bn128.F12.inverse(r2));
|
||||
|
||||
const res = bn128.finalExponentiation(rbe);
|
||||
|
||||
assert(bn128.F12.equals(res, bn128.F12.one));
|
||||
}
|
||||
}).timeout(10000);
|
||||
*/
|
||||
it("Should generate another pairing pairing", () => {
|
||||
for (let i=0; i<1; i++) {
|
||||
const bn128 = new BN128();
|
||||
|
||||
const g1a = bn128.G1.mulScalar(bn128.G1.g, 10);
|
||||
const g2a = bn128.G2.mulScalar(bn128.G2.g, 1);
|
||||
|
||||
const g1b = bn128.G1.mulScalar(bn128.G1.g, 1);
|
||||
const g2b = bn128.G2.mulScalar(bn128.G2.g, 10);
|
||||
|
||||
const pre1a = bn128.precomputeG1(g1a);
|
||||
const pre2a = bn128.precomputeG2(g2a);
|
||||
const pre1b = bn128.precomputeG1(g1b);
|
||||
const pre2b = bn128.precomputeG2(g2b);
|
||||
|
||||
const r1 = bn128.millerLoop(pre1a, pre2a);
|
||||
const r2 = bn128.finalExponentiation(r1);
|
||||
|
||||
const r3 = bn128.millerLoop(pre1b, pre2b);
|
||||
|
||||
const r4 = bn128.finalExponentiation(r3);
|
||||
|
||||
|
||||
console.log("ML1: " ,r1[0][0][0].affine(bn128.q).toString(16));
|
||||
console.log("FE1: " ,r2[0][0][0].affine(bn128.q).toString(16));
|
||||
console.log("ML2: " ,r3[0][0][0].affine(bn128.q).toString(16));
|
||||
console.log("FE2: " ,r4[0][0][0].affine(bn128.q).toString(16));
|
||||
|
||||
assert(bn128.F12.equals(r2, r4));
|
||||
|
||||
|
||||
/* const r2 = bn128.millerLoop(pre1b, pre2b);
|
||||
|
||||
const rbe = bn128.F12.mul(r1, bn128.F12.inverse(r2));
|
||||
|
||||
const res = bn128.finalExponentiation(rbe);
|
||||
|
||||
assert(bn128.F12.equals(res, bn128.F12.one)); */
|
||||
}
|
||||
}).timeout(10000);
|
||||
});
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
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 BN128 = require("../src/bn128.js");
|
||||
const F1Field = require("ffjavascript").ZqField;
|
||||
|
||||
const assert = chai.assert;
|
||||
|
||||
|
||||
describe("Calculate witness", () => {
|
||||
it("Should calculate the witness of a sum circuit", () => {
|
||||
|
||||
const cirDef = JSON.parse(fs.readFileSync(path.join(__dirname, "circuit", "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");
|
||||
});
|
||||
});
|
@ -2,7 +2,7 @@ template Multiplier(n) {
|
||||
signal private input a;
|
||||
signal private input b;
|
||||
signal output c;
|
||||
|
||||
|
||||
signal int[n];
|
||||
|
||||
int[0] <== a*a + b;
|
||||
@ -13,4 +13,4 @@ template Multiplier(n) {
|
||||
c <== int[n-1];
|
||||
}
|
||||
|
||||
component main = Multiplier(1000);
|
||||
component main = Multiplier(100);
|
||||
|
Binary file not shown.
Binary file not shown.
217
test/pols.js
217
test/pols.js
@ -1,217 +0,0 @@
|
||||
/*
|
||||
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 bigInt = require("big-integer");
|
||||
const PolField = require("../src/polfield.js");
|
||||
const ZqField = require("ffjavascript").ZqField;
|
||||
|
||||
const assert = chai.assert;
|
||||
|
||||
const r = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
|
||||
describe("Polynomial field", () => {
|
||||
it("Should compute a multiplication", () => {
|
||||
const PF = new PolField(new ZqField(r));
|
||||
|
||||
const a = [bigInt(1), bigInt(2), bigInt(3)];
|
||||
const b = [bigInt(1), bigInt(2), bigInt(3)];
|
||||
const res = PF.mul(a,b);
|
||||
|
||||
assert(PF.equals(res, [bigInt(1), bigInt(4), bigInt(10), bigInt(12), bigInt(9)]));
|
||||
});
|
||||
it("Should compute a multiplication 2", () => {
|
||||
const PF = new PolField(new ZqField(r));
|
||||
|
||||
const a = [bigInt(5), bigInt(1)];
|
||||
const b = [bigInt(-5), bigInt(1)];
|
||||
const res = PF.mul(a,b);
|
||||
|
||||
assert(PF.equals(res, [bigInt(-25), bigInt(0), bigInt(1)]));
|
||||
});
|
||||
it("Should compute an addition", () => {
|
||||
const PF = new PolField(new ZqField(r));
|
||||
|
||||
const a = [bigInt(5), bigInt(1)];
|
||||
const b = [bigInt(-5), bigInt(1)];
|
||||
const res = PF.add(a,b);
|
||||
|
||||
assert(PF.equals(res, [bigInt(0), bigInt(2)]));
|
||||
});
|
||||
it("Should compute a substraction", () => {
|
||||
const PF = new PolField(new ZqField(r));
|
||||
|
||||
const a = [bigInt(5), bigInt(3), bigInt(4)];
|
||||
const b = [bigInt(5), bigInt(1)];
|
||||
const res = PF.sub(a,b);
|
||||
|
||||
assert(PF.equals(res, [bigInt(0), bigInt(2), bigInt(4)]));
|
||||
});
|
||||
it("Should compute reciprocal", () => {
|
||||
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 res = PF._reciprocal(a, 3, 0);
|
||||
|
||||
assert(PF.equals(res, [bigInt(12), bigInt(15), bigInt(3), bigInt(-4), bigInt(-3), bigInt(0), bigInt(1), bigInt(1)]));
|
||||
});
|
||||
it("Should div2", () => {
|
||||
const PF = new PolField(new ZqField(r));
|
||||
|
||||
// x^6
|
||||
const a = [bigInt(0), bigInt(0), bigInt(0), bigInt(0), bigInt(0),bigInt(0), bigInt(1)];
|
||||
// x^5
|
||||
const b = [bigInt(0), bigInt(0), bigInt(0), bigInt(0), bigInt(0), bigInt(1)];
|
||||
|
||||
const res = PF._div2(6, b);
|
||||
assert(PF.equals(res, [bigInt(0), bigInt(1)]));
|
||||
|
||||
const res2 = PF.div(a,b);
|
||||
assert(PF.equals(res2, [bigInt(0), bigInt(1)]));
|
||||
});
|
||||
it("Should div", () => {
|
||||
const PF = new PolField(new ZqField(r));
|
||||
|
||||
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 c = PF.mul(a,b);
|
||||
const d = PF.div(c,b);
|
||||
|
||||
assert(PF.equals(a, d));
|
||||
});
|
||||
it("Should div big/small", () => {
|
||||
const PF = new PolField(new ZqField(r));
|
||||
|
||||
const a = [bigInt(1), bigInt(2), bigInt(3), bigInt(4), bigInt(5),bigInt(6), bigInt(7)];
|
||||
const b = [bigInt(8), bigInt(9)];
|
||||
|
||||
const c = PF.mul(a,b);
|
||||
const d = PF.div(c,b);
|
||||
|
||||
assert(PF.equals(a, d));
|
||||
});
|
||||
it("Should div random big", () => {
|
||||
const PF = new PolField(new ZqField(r));
|
||||
|
||||
const a = [];
|
||||
const b = [];
|
||||
for (let i=0; i<1000; i++) a.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 d = PF.div(c,b);
|
||||
|
||||
assert(PF.equals(a, d));
|
||||
}).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 evaluate bigger number", () => {
|
||||
const PF = new PolField(new ZqField(r));
|
||||
const p = [bigInt(1), bigInt(2), bigInt(3)];
|
||||
const v = PF.eval(p, bigInt(2));
|
||||
assert(PF.F.equals(v, bigInt(17)));
|
||||
});
|
||||
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]));
|
||||
}
|
||||
});
|
||||
it("Should test ruffini", () => {
|
||||
const PF = new PolField(new ZqField(r));
|
||||
const a = [bigInt(1), bigInt(2), bigInt(3), bigInt(4), bigInt(5),bigInt(6), bigInt(7)];
|
||||
|
||||
const b = PF.mul(a, [bigInt(-7), bigInt(1)]);
|
||||
const c = PF.ruffini(b, bigInt(7));
|
||||
|
||||
assert(PF.equals(a, c));
|
||||
});
|
||||
it("Should test roots", () => {
|
||||
const PF = new PolField(new ZqField(r));
|
||||
let rt;
|
||||
|
||||
|
||||
rt = PF.oneRoot(256, 16);
|
||||
for (let i=0; i<8; i++) {
|
||||
rt = PF.F.mul(rt, rt);
|
||||
}
|
||||
assert(rt.equals(PF.F.one));
|
||||
|
||||
rt = PF.oneRoot(256, 15);
|
||||
for (let i=0; i<8; i++) {
|
||||
rt = PF.F.mul(rt, rt);
|
||||
}
|
||||
assert(rt.equals(PF.F.one));
|
||||
|
||||
rt = PF.oneRoot(8, 3);
|
||||
for (let i=0; i<3; i++) {
|
||||
rt = PF.F.mul(rt, rt);
|
||||
}
|
||||
assert(rt.equals(PF.F.one));
|
||||
|
||||
rt = PF.oneRoot(8, 0);
|
||||
assert(rt.equals(PF.F.one));
|
||||
|
||||
});
|
||||
it("Should create a polynomial with values at roots with fft", () => {
|
||||
const PF = new PolField(new ZqField(r));
|
||||
const a = [bigInt(1), bigInt(2), bigInt(3), bigInt(4), bigInt(5),bigInt(6), bigInt(7)];
|
||||
|
||||
const p = PF.ifft(a);
|
||||
|
||||
for (let i=0; i<a.length; i++) {
|
||||
const s = PF.F.affine(PF.eval(p, PF.oneRoot(8,i)));
|
||||
assert(s.equals(a[i]));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
@ -1,126 +0,0 @@
|
||||
{
|
||||
"mainCode": "{\n}\n",
|
||||
"signalName2Idx": {
|
||||
"one": 0,
|
||||
"main.a": 3,
|
||||
"main.b": 4,
|
||||
"main.c": 5,
|
||||
"main.d": 6,
|
||||
"main.e": 1,
|
||||
"main.f": 2
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"name": "main",
|
||||
"params": {},
|
||||
"template": "Multiplier",
|
||||
"inputSignals": 4
|
||||
}
|
||||
],
|
||||
"componentName2Idx": {
|
||||
"main": 0
|
||||
},
|
||||
"signals": [
|
||||
{
|
||||
"names": [
|
||||
"one"
|
||||
],
|
||||
"triggerComponents": []
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"main.e"
|
||||
],
|
||||
"triggerComponents": []
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"main.f"
|
||||
],
|
||||
"triggerComponents": []
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"main.a"
|
||||
],
|
||||
"triggerComponents": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"main.b"
|
||||
],
|
||||
"triggerComponents": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"main.c"
|
||||
],
|
||||
"triggerComponents": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"main.d"
|
||||
],
|
||||
"triggerComponents": [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"constraints": [
|
||||
[
|
||||
{},
|
||||
{},
|
||||
{
|
||||
"0": "21888242871839275222246405745257275088548364400416034343698204186575808495616",
|
||||
"3": "1"
|
||||
}
|
||||
],
|
||||
[
|
||||
{},
|
||||
{},
|
||||
{
|
||||
"0": "21888242871839275222246405745257275088548364400416034343698204186575808495616",
|
||||
"4": "1"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"3": "21888242871839275222246405745257275088548364400416034343698204186575808495616"
|
||||
},
|
||||
{
|
||||
"4": "1"
|
||||
},
|
||||
{
|
||||
"1": "21888242871839275222246405745257275088548364400416034343698204186575808495616"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"5": "21888242871839275222246405745257275088548364400416034343698204186575808495616"
|
||||
},
|
||||
{
|
||||
"6": "1"
|
||||
},
|
||||
{
|
||||
"2": "21888242871839275222246405745257275088548364400416034343698204186575808495616"
|
||||
}
|
||||
]
|
||||
],
|
||||
"templates": {
|
||||
"Multiplier": "function(ctx) {\n ctx.assert(\"1\", ctx.getSignal(\"a\", []), \"/home/ixnay/iden3Dev/github/test/circom-test/circuit.circom:9:4\");\n ctx.assert(\"1\", ctx.getSignal(\"b\", []), \"/home/ixnay/iden3Dev/github/test/circom-test/circuit.circom:10:4\");\n ctx.setSignal(\"e\", [], bigInt(ctx.getSignal(\"a\", [])).mul(bigInt(ctx.getSignal(\"b\", []))).mod(__P__));\n ctx.setSignal(\"f\", [], bigInt(ctx.getSignal(\"c\", [])).mul(bigInt(ctx.getSignal(\"d\", []))).mod(__P__));\n}\n"
|
||||
},
|
||||
"functions": {},
|
||||
"nPrvInputs": 4,
|
||||
"nPubInputs": 0,
|
||||
"nInputs": 4,
|
||||
"nOutputs": 2,
|
||||
"nVars": 7,
|
||||
"nConstants": 0,
|
||||
"nSignals": 7
|
||||
}
|
Binary file not shown.
@ -1,89 +0,0 @@
|
||||
/*
|
||||
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 bigInt = require("big-integer");
|
||||
const ZqField = require("ffjavascript").ZqField;
|
||||
const RatField = require("../src/ratfield.js");
|
||||
|
||||
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const Z = new ZqField(q);
|
||||
const R = new RatField(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)));
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user