diff --git a/bench.js b/bench.js new file mode 100755 index 0000000..e4723bc --- /dev/null +++ b/bench.js @@ -0,0 +1,128 @@ +#!/usr/bin/env node + +// Measuring elliptic curve operations for ffjavascript +import { BigBuffer, buildBn128, buildBls12381, F1Field } from "ffjavascript"; +import { Bench } from "tinybench"; + +const curves = [buildBn128(false), buildBls12381(false)]; + +function bench_add_ff(F) { + const x = F.random(); + const y = F.random(); + return () => { + F.add(x, y); + }; +} + +function bench_mul_ff(F) { + const x = F.random(); + const y = F.random(); + return () => { + F.mul(x, y); + }; +} + +function bench_invert(F) { + const x = F.random(); + return () => { + F.invert(x); + }; +} + +function bench_add_ec(G, Fr) { + const x = G.timesScalar(G.g, Fr.random()); + const y = G.timesScalar(G.g, Fr.random()); + return () => { + G.add(x, y); + }; +} + +function bench_mul_ec(G, Fr) { + const x = G.F.random(); + const y = G.timesScalar(G.g, Fr.random()); + return () => { + G.timesScalar(y, x); + }; +} + +function bench_pairing(curve) { + const x = curve.Fr.random(); + const y = curve.Fr.random(); + const g1 = curve.G1.timesScalar(curve.G1.g, x); + const g2 = curve.G2.timesScalar(curve.G2.g, y); + return () => { + curve.pairing(g1, g2); + }; +} + +function bench_fft(bench, name, F, range) { + for (var i = range[0]; i < range[1]; i++) { + const n = Math.pow(2, i); + const x = new BigBuffer(n * F.n8); + for (let i = 0; i < n; i++) { + x.set(F.random(), i * F.n8); + } + bench.add(name + "/" + n, async () => { + await F.fft(x); + }); + } +} + +function bench_msm(bench, name, G, Fr, range) { + for (var i = range[0]; i < range[1]; i++) { + let n = Math.pow(2, i); + const scalars = new BigBuffer(n * Fr.n8); + const bases = new BigBuffer(n * G.F.n8 * 2); + for (let i = 0; i < n; i++) { + scalars.set(Fr.random(), i * Fr.n8); + bases.set(G.toAffine(G.timesFr(G.g, Fr.random())), i * G.F.n8 * 2); + } + bench.add(name + "/" + n, async () => { + await G.multiExpAffine(bases, scalars, false, ""); + }); + } +} + +async function run() { + const bench = new Bench(); + + for (const curve of curves) { + const c = await curve; + // If we do not do it like that, then the pairing operation does not work + // properly. + let name = c.name; + if (name == "bls12381") { + name = "bls12_381"; + } + if (name == "bn128") { + name = "bn254"; + } + + bench + .add(name + "/add_ff", bench_add_ff(c.Fr)) + .add(name + "/mul_ff", bench_mul_ff(c.Fr)) + .add(name + "/invert", bench_invert(c.Fr)) + .add(name + "/mul_G1", bench_mul_ec(c.G1, c.Fr)) + .add(name + "/mul_G2", bench_mul_ec(c.G2, c.Fr)) + .add(name + "/pairing", bench_pairing(c)) + .add(name + "/add_G1", bench_add_ec(c.G1, c.Fr)) + .add(name + "/add_G2", bench_add_ec(c.G2, c.Fr)); + + bench_msm(bench, name + "/msm_G1", c.G1, c.Fr, [1, 21]); + bench_msm(bench, name + "/msm_G2", c.G2, c.Fr, [1, 21]); + bench_fft(bench, name + "/fft", c.Fr, [1, 21]); + } + + await bench.run(); + console.table(bench.table()); + const results = bench.tasks.map((x) => { + // remove samples to avoid the dataset from exploding + let { ["samples"]: unused, ...info } = x.result; + return { name: x.name, ...info }; + }); + process.stderr.write(JSON.stringify(results)); +} + +run().then(() => { + process.exit(0); +}); diff --git a/package-lock.json b/package-lock.json index a7587b4..cd41be7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,8 @@ "chai": "^4.2.0", "eslint": "^8.0.1", "mocha": "^10.0.0", - "rollup": "^2.38.5" + "rollup": "^2.38.5", + "tinybench": "^2.5.0" } }, "node_modules/@eslint-community/eslint-utils": { @@ -1621,6 +1622,12 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "node_modules/tinybench": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.0.tgz", + "integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==", + "dev": true + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3007,6 +3014,12 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "tinybench": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.0.tgz", + "integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==", + "dev": true + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", diff --git a/package.json b/package.json index 5e9963a..ebd50da 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ }, "scripts": { "test": "mocha", - "build": "rollup -c rollup.cjs.config.js" + "build": "rollup -c rollup.cjs.config.js", + "bench": "node ./bench.js" }, "repository": { "type": "git", @@ -41,6 +42,7 @@ "chai": "^4.2.0", "eslint": "^8.0.1", "mocha": "^10.0.0", - "rollup": "^2.38.5" + "rollup": "^2.38.5", + "tinybench": "^2.5.0" } }