UNPKG

ffwasm

Version:

Finite Field Library In Web Assembly

239 lines (211 loc) 7.9 kB
const tester = require("./test_utils/wasm_tester.js"); const bigInt = require("big-integer"); const ZqField = require("ffjavascript").ZqField; const bn128q = new bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583"); const bn128r = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); const secp256k1q = new bigInt("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16); const secp256k1r = new bigInt("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16); const mnt6753q = new bigInt("41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888458477323173057491593855069696241854796396165721416325350064441470418137846398469611935719059908164220784476160001"); const mnt6753r = new bigInt("41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888253786114353726529584385201591605722013126468931404347949840543007986327743462853720628051692141265303114721689601"); describe("field asm test", function () { this.timeout(1000000000); it("bn128r add", async () => { const tv = buildTestVector2(bn128r, "add"); await tester(bn128r, tv); }); it("bn128r sub", async () => { const tv = buildTestVector2(bn128r, "sub"); await tester(bn128r, tv); }); it("bn128r mul", async () => { const tv = buildTestVector2(bn128r, "mul"); await tester(bn128r, tv); }); it("bn128r eq", async () => { const tv = buildTestVector2(bn128r, "eq"); await tester(bn128r, tv); }); it("bn128r neq", async () => { const tv = buildTestVector2(bn128r, "neq"); await tester(bn128r, tv); }); it("bn128r gt", async () => { const tv = buildTestVector2(bn128r, "gt"); await tester(bn128r, tv); }); it("bn128r geq", async () => { const tv = buildTestVector2(bn128r, "geq"); await tester(bn128r, tv); }); it("bn128r lt", async () => { const tv = buildTestVector2(bn128r, "gt"); await tester(bn128r, tv); }); it("bn128r leq", async () => { const tv = buildTestVector2(bn128r, "geq"); await tester(bn128r, tv); }); it("bn128r idiv", async () => { const tv = buildTestVector2(bn128r, "idiv"); await tester(bn128r, tv); }); it("bn128r mod", async () => { const tv = buildTestVector2(bn128r, "mod"); await tester(bn128r, tv); }); it("bn128r pow", async () => { const tv = buildTestVector2(bn128r, "pow"); await tester(bn128r, tv); }); it("bn128r inv", async () => { const tv = buildTestVector1(bn128r, "inv"); await tester(bn128r, tv); }); it("bn128r div", async () => { const tv = buildTestVector2(bn128r, "div"); await tester(bn128r, tv); }); it("bn128r neg", async () => { const tv = buildTestVector1(bn128r, "neg"); await tester(bn128r, tv); }); it("bn128r shl", async () => { const tv = buildTestVector2(bn128r, "shl"); await tester(bn128r, tv); }); it("bn128r shr", async () => { const tv = buildTestVector2(bn128r, "shr"); await tester(bn128r, tv); }); it("bn128r band", async () => { const tv = buildTestVector2(bn128r, "band"); await tester(bn128r, tv); }); it("bn128r bor", async () => { const tv = buildTestVector2(bn128r, "bor"); await tester(bn128r, tv); }); it("bn128r bxor", async () => { const tv = buildTestVector2(bn128r, "bxor"); await tester(bn128r, tv); }); it("bn128r bnot", async () => { const tv = buildTestVector1(bn128r, "bnot"); await tester(bn128r, tv); }); it("bn128r land", async () => { const tv = buildTestVector2(bn128r, "land"); await tester(bn128r, tv); }); it("bn128r lor", async () => { const tv = buildTestVector2(bn128r, "lor"); await tester(bn128r, tv); }); it("bn128r lnot", async () => { const tv = buildTestVector1(bn128r, "lnot"); await tester(bn128r, tv); }); }); function buildTestVector2(p, op) { const F = new ZqField(p); const tv = []; const nums = getCriticalNumbers(p, 2); const excludeZero = ["div", "mod", "idiv"].indexOf(op) >= 0; for (let i=0; i<nums.length; i++) { for (let j=0; j<nums.length; j++) { if ((excludeZero)&&(nums[j][0].isZero())) continue; tv.push([ [nums[i][1], nums[j][1], op], F[op](nums[i][0], nums[j][0]) ]); } } return tv; } function buildTestVector1(p, op) { const F = new ZqField(p); const tv = []; const nums = getCriticalNumbers(p, 2); const excludeZero = ["inv"].indexOf(op) >= 0; for (let i=0; i<nums.length; i++) { if ((excludeZero)&&(nums[i][0].isZero())) continue; tv.push([ [nums[i][1], op], F[op](nums[i][0]) ]); } return tv; } function getCriticalNumbers(p, lim) { const n64 = Math.floor((p.bitLength() - 1) / 64)+1; const R = bigInt.one.shiftLeft(n64*64); const numbers = []; addFrontier(0); addFrontier(bigInt(32)); addFrontier(bigInt(64)); addFrontier(bigInt(p.bitLength())); addFrontier(bigInt.one.shiftLeft(31)); addFrontier(p.minus(bigInt.one.shiftLeft(31))); addFrontier(bigInt.one.shiftLeft(32)); addFrontier(p.minus(bigInt.one.shiftLeft(32))); addFrontier(bigInt.one.shiftLeft(63)); addFrontier(p.minus(bigInt.one.shiftLeft(63))); addFrontier(bigInt.one.shiftLeft(64)); addFrontier(p.minus(bigInt.one.shiftLeft(64))); addFrontier(bigInt.one.shiftLeft(p.bitLength()-1)); addFrontier(p.shiftRight(1)); function addFrontier(f) { for (let i=-lim; i<=lim; i++) { let n = bigInt(f).add(bigInt(i)); n = n.mod(p); if (n.isNegative()) n = p.add(n); addNumber(n); } } return numbers; function addNumber(n) { if (n.lt(bigInt("80000000", 16)) ) { addShortPositive(n); addShortMontgomeryPositive(n); } if (n.geq(p.minus(bigInt("80000000", 16))) ) { addShortNegative(n); addShortMontgomeryNegative(n); } addLongNormal(n); addLongMontgomery(n); function addShortPositive(a) { numbers.push([a, [parseInt(a), 0, ...getLong(0)]]); } function addShortMontgomeryPositive(a) { numbers.push([a, [parseInt(a), 0x40000000, ...getLong(toMontgomery(a)) ]]); } function addShortNegative(a) { const b = bigInt("80000000", 16 ).add(a.minus( p.minus(bigInt("80000000", 16 )))); numbers.push([a, [parseInt(b), 0, ...getLong(0)]]); } function addShortMontgomeryNegative(a) { const b = bigInt("80000000", 16 ).add(a.minus( p.minus(bigInt("80000000", 16 )))); numbers.push([a, [parseInt(b), 0x40000000, ...getLong(toMontgomery(a))]]); } function addLongNormal(a) { numbers.push([a, [0, 0x80000000, ...getLong(a)]]); } function addLongMontgomery(a) { numbers.push([a, [0, 0xC0000000, ...getLong(toMontgomery(a))]]); } function getLong(a) { const arr = []; let r = bigInt(a); while (!r.isZero()) { arr.push( parseInt(r.and(bigInt("FFFFFFFF", 16)))); r = r.shiftRight(32); } while (arr.length<n64*2) arr.push(0); return arr; } function toMontgomery(a) { return a.times(R).mod(p); } } }