diff --git a/package-lock.json b/package-lock.json index 2881c9a..44007c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1529,6 +1529,21 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, + "fflib": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/fflib/-/fflib-0.0.1.tgz", + "integrity": "sha512-bWTudSfCjkNkOOeSNQf8DmBidxxuzqyjeIdZBfY38T7R+jt381sdx1SYpyve5MQdDlQg1k7UHeb0L/J8WWFWYA==", + "requires": { + "big-integer": "^1.6.48" + }, + "dependencies": { + "big-integer": { + "version": "1.6.48", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", + "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==" + } + } + }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", diff --git a/package.json b/package.json index 9aa5f55..6861042 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "blake-hash": "^1.1.0", "blake2b": "^2.1.3", "circom": "0.0.35", + "fflib": "0.0.1", "snarkjs": "^0.1.20", "typedarray-to-buffer": "^3.1.5", "web3": "^1.0.0-beta.55" diff --git a/src/babyjub.js b/src/babyjub.js index b3630fd..fe3b27d 100644 --- a/src/babyjub.js +++ b/src/babyjub.js @@ -1,5 +1,6 @@ -const bn128 = require("snarkjs").bn128; -const bigInt = require("snarkjs").bigInt; +const bigInt = require("big-integer"); +const ZqField = require("fflib").ZqField; +const utils = require("./utils.js"); exports.addPoint = addPoint; exports.mulPointEscalar = mulPointEscalar; @@ -16,14 +17,14 @@ exports.Base8 = [ bigInt("16950150798460657717958625567821834550301663161624707787222815936182638968203") ]; exports.order = bigInt("21888242871839275222246405745257275088614511777268538073601725287587578984328"); -exports.subOrder = exports.order.shr(3); -exports.p = bn128.r; +exports.subOrder = exports.order.shiftRight(3); +exports.p = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); exports.A = bigInt("168700"); exports.D = bigInt("168696"); function addPoint(a,b) { - const q = bn128.r; + const F = new ZqField(exports.p); const res = []; @@ -31,8 +32,25 @@ function addPoint(a,b) { res[0] = bigInt((a[0]*b[1] + b[0]*a[1]) * bigInt(bigInt("1") + d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q); res[1] = bigInt((a[1]*b[1] - cta*a[0]*b[0]) * bigInt(bigInt("1") - d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q); */ - res[0] = bigInt((bigInt(a[0]).mul(b[1]).add(bigInt(b[0]).mul(a[1]))).mul(bigInt(bigInt("1").add(exports.D.mul(a[0]).mul(b[0]).mul(a[1]).mul(b[1]))).inverse(q))).affine(q); - res[1] = bigInt((bigInt(a[1]).mul(b[1]).sub(exports.A.mul(a[0]).mul(b[0]))).mul(bigInt(bigInt("1").sub(exports.D.mul(a[0]).mul(b[0]).mul(a[1]).mul(b[1]))).inverse(q))).affine(q); + + const beta = F.mul(a[0],b[1]); + const gamma = F.mul(a[1],b[0]); + const delta = F.mul( + F.sub(a[1], F.mul(exports.A, a[0])), + F.add(b[0], b[1]) + ); + const tau = F.mul(beta, gamma); + const dtau = F.mul(exports.D, tau); + + res[0] = F.div( + F.add(beta, gamma), + F.add(bigInt.one, dtau) + ); + + res[1] = F.div( + F.add(delta, F.sub(F.mul(exports.A,beta), gamma)), + F.sub(bigInt.one, dtau) + ); return res; } @@ -47,7 +65,7 @@ function mulPointEscalar(base, e) { res = addPoint(res, exp); } exp = addPoint(exp, exp); - rem = rem.shr(1); + rem = rem.shiftRight(1); } return res; @@ -60,12 +78,12 @@ function inSubgroup(P) { } function inCurve(P) { - const F = bn128.Fr; + const F = new ZqField(exports.p); const x2 = F.square(P[0]); const y2 = F.square(P[1]); - if (!F.equals( + if (!F.eq( F.add(F.mul(exports.A, x2), y2), F.add(F.one, F.mul(F.mul(x2, y2), exports.D)))) return false; @@ -73,15 +91,15 @@ function inCurve(P) { } function packPoint(P) { - const buff = bigInt.leInt2Buff(P[1], 32); - if (P[0].greater(exports.p.shr(1))) { + const buff = utils.leInt2Buff(P[1], 32); + if (P[0].greater(exports.p.shiftRight(1))) { buff[31] = buff[31] | 0x80; } return buff; } function unpackPoint(_buff) { - const F = bn128.Fr; + const F = new ZqField(exports.p); const buff = Buffer.from(_buff); let sign = false; @@ -90,7 +108,7 @@ function unpackPoint(_buff) { sign = true; buff[31] = buff[31] & 0x7F; } - P[1] = bigInt.leBuff2int(buff); + P[1] = utils.leBuff2int(buff); if (P[1].greaterOrEquals(exports.p)) return null; const y2 = F.square(P[1]); @@ -103,7 +121,7 @@ function unpackPoint(_buff) { if (sign) x = F.neg(x); - P[0] = F.affine(x); + P[0] = x; return P; } diff --git a/test/babyjub_js.js b/test/babyjub_js.js index 8e1fc33..b65d71c 100644 --- a/test/babyjub_js.js +++ b/test/babyjub_js.js @@ -1,7 +1,5 @@ const chai = require("chai"); -const path = require("path"); -const snarkjs = require("snarkjs"); -const compiler = require("circom"); +const bigInt = require("big-integer"); const babyjub = require("../src/babyjub.js"); const assert = chai.assert; @@ -16,14 +14,14 @@ describe("Baby Jub js test", function () { it("Should add point (0,1) and (0,1)", () => { const p1 = [ - snarkjs.bigInt(0), - snarkjs.bigInt(1)]; + bigInt(0), + bigInt(1)]; const p2 = [ - snarkjs.bigInt(0), - snarkjs.bigInt(1) + bigInt(0), + bigInt(1) ]; - const out = babyjub.addPoint(p1, p2) + const out = babyjub.addPoint(p1, p2); assert(out[0].equals(0)); assert(out[1].equals(1)); }); @@ -41,43 +39,43 @@ describe("Baby Jub js test", function () { it("Should add 2 same numbers", () => { const p1 = [ - snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), - snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), + bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), + bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), ]; const p2 = [ - snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), - snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), + bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), + bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), ]; - const out = babyjub.addPoint(p1, p2) - assert(out[0].equals(snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"))); - assert(out[1].equals(snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"))); + const out = babyjub.addPoint(p1, p2); + assert(out[0].equals(bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"))); + assert(out[1].equals(bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"))); }); it("Should add 2 different numbers", () => { const p1 = [ - snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), - snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), + bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), + bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), ]; const p2 = [ - snarkjs.bigInt("16540640123574156134436876038791482806971768689494387082833631921987005038935"), - snarkjs.bigInt("20819045374670962167435360035096875258406992893633759881276124905556507972311"), + bigInt("16540640123574156134436876038791482806971768689494387082833631921987005038935"), + bigInt("20819045374670962167435360035096875258406992893633759881276124905556507972311"), ]; - const out = babyjub.addPoint(p1, p2) + const out = babyjub.addPoint(p1, p2); - assert(out[0].equals(snarkjs.bigInt("7916061937171219682591368294088513039687205273691143098332585753343424131937"))); - assert(out[1].equals(snarkjs.bigInt("14035240266687799601661095864649209771790948434046947201833777492504781204499"))); + assert(out[0].equals(bigInt("7916061937171219682591368294088513039687205273691143098332585753343424131937"))); + assert(out[1].equals(bigInt("14035240266687799601661095864649209771790948434046947201833777492504781204499"))); }); it("should mulPointEscalar 0", () => { const p = [ - snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), - snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), + bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), + bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), ]; - const r = babyjub.mulPointEscalar(p, snarkjs.bigInt("3")); + const r = babyjub.mulPointEscalar(p, bigInt("3")); let r2 = babyjub.addPoint(p, p); r2 = babyjub.addPoint(r2, p); assert.equal(r2[0].toString(), r[0].toString()); @@ -88,65 +86,65 @@ describe("Baby Jub js test", function () { it("should mulPointEscalar 1", () => { const p = [ - snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), - snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), + bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), + bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), ]; - const r = babyjub.mulPointEscalar(p, snarkjs.bigInt("14035240266687799601661095864649209771790948434046947201833777492504781204499")); + const r = babyjub.mulPointEscalar(p, bigInt("14035240266687799601661095864649209771790948434046947201833777492504781204499")); assert.equal(r[0].toString(), "17070357974431721403481313912716834497662307308519659060910483826664480189605"); assert.equal(r[1].toString(), "4014745322800118607127020275658861516666525056516280575712425373174125159339"); }); it("should mulPointEscalar 2", () => { const p = [ - snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"), - snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"), + bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"), + bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"), ]; - const r = babyjub.mulPointEscalar(p, snarkjs.bigInt("20819045374670962167435360035096875258406992893633759881276124905556507972311")); + const r = babyjub.mulPointEscalar(p, bigInt("20819045374670962167435360035096875258406992893633759881276124905556507972311")); assert.equal(r[0].toString(), "13563888653650925984868671744672725781658357821216877865297235725727006259983"); assert.equal(r[1].toString(), "8442587202676550862664528699803615547505326611544120184665036919364004251662"); }); it("should inCurve 1", () => { const p = [ - snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), - snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), + bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), + bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), ]; assert(babyjub.inCurve(p)); }); it("should inCurve 2", () => { const p = [ - snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"), - snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"), + bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"), + bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"), ]; assert(babyjub.inCurve(p)); }); it("should inSubgroup 1", () => { const p = [ - snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), - snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), + bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), + bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), ]; assert(babyjub.inSubgroup(p)); }); it("should inSubgroup 2", () => { const p = [ - snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"), - snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"), + bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"), + bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"), ]; assert(babyjub.inSubgroup(p)); }); it("should packPoint - unpackPoint 1", () => { const p = [ - snarkjs.bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), - snarkjs.bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), + bigInt("17777552123799933955779906779655732241715742912184938656739573121738514868268"), + bigInt("2626589144620713026669568689430873010625803728049924121243784502389097019475"), ]; const buf = babyjub.packPoint(p); - assert.equal(buf.toString('hex'), '53b81ed5bffe9545b54016234682e7b2f699bd42a5e9eae27ff4051bc698ce85'); + assert.equal(buf.toString("hex"), "53b81ed5bffe9545b54016234682e7b2f699bd42a5e9eae27ff4051bc698ce85"); const p2 = babyjub.unpackPoint(buf); assert.equal(p2[0].toString(), "17777552123799933955779906779655732241715742912184938656739573121738514868268"); assert.equal(p2[1].toString(), "2626589144620713026669568689430873010625803728049924121243784502389097019475"); @@ -154,11 +152,11 @@ describe("Baby Jub js test", function () { it("should packPoint - unpackPoint 2", () => { const p = [ - snarkjs.bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"), - snarkjs.bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"), + bigInt("6890855772600357754907169075114257697580319025794532037257385534741338397365"), + bigInt("4338620300185947561074059802482547481416142213883829469920100239455078257889"), ]; const buf = babyjub.packPoint(p); - assert.equal(buf.toString('hex'), 'e114eb17eddf794f063a68fecac515e3620e131976108555735c8b0773929709'); + assert.equal(buf.toString("hex"), "e114eb17eddf794f063a68fecac515e3620e131976108555735c8b0773929709"); const p2 = babyjub.unpackPoint(buf); assert.equal(p2[0].toString(), "6890855772600357754907169075114257697580319025794532037257385534741338397365"); assert.equal(p2[1].toString(), "4338620300185947561074059802482547481416142213883829469920100239455078257889");