From 4e8d1272514d58063930a48a203e86aa3445ffb1 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Thu, 18 Mar 2021 12:20:09 +0300 Subject: [PATCH 1/2] add benches --- .gitignore | 1 + .prettierignore | 1 + Makefile | 3 +- benches/README.md | 6 + benches/fixtures.js | 49 ++++ benches/index.js | 196 ++++++++++++++++ benches/package-lock.json | 480 ++++++++++++++++++++++++++++++++++++++ benches/package.json | 14 ++ package.json | 2 + 9 files changed, 751 insertions(+), 1 deletion(-) create mode 100644 benches/README.md create mode 100644 benches/fixtures.js create mode 100644 benches/index.js create mode 100644 benches/package-lock.json create mode 100644 benches/package.json diff --git a/.gitignore b/.gitignore index 18437a3..6e0d27a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/benches/node_modules /node_modules /target /tests/browser diff --git a/.prettierignore b/.prettierignore index c87afff..fccc18b 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,4 +3,5 @@ /tests/fixtures /util/gen-fixtures/secp256k1 +benches/package-lock.json package-lock.json diff --git a/Makefile b/Makefile index 555153b..34bb5a3 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,8 @@ clean: .PHONY: format format: cargo-fmt - npx prettier -w . + npx prettier -w . + npx sort-package-json package.json benches/package.json .PHONY: lint lint: diff --git a/benches/README.md b/benches/README.md new file mode 100644 index 0000000..069a41d --- /dev/null +++ b/benches/README.md @@ -0,0 +1,6 @@ +## Run benches + +``` +npm install +npm start +``` diff --git a/benches/fixtures.js b/benches/fixtures.js new file mode 100644 index 0000000..dc283c7 --- /dev/null +++ b/benches/fixtures.js @@ -0,0 +1,49 @@ +import * as tiny_secp256k1 from "../lib/index.js"; +import _fecdsa from "../tests/fixtures/ecdsa.json"; +import _fpoints from "../tests/fixtures/points.json"; +import _fprivates from "../tests/fixtures/privates.json"; + +export const fecdsa = _fecdsa.valid.map((f) => ({ + d: Buffer.from(f.d, "hex"), + Q: Buffer.from(tiny_secp256k1.pointFromScalar(Buffer.from(f.d, "hex"))), + m: Buffer.from(f.m, "hex"), + signature: Buffer.from(f.signature, "hex"), +})); + +export const fpoints = { + isPoint: _fpoints.valid.isPoint.map((f) => ({ + P: Buffer.from(f.P, "hex"), + })), + pointAdd: _fpoints.valid.pointAdd.map((f) => ({ + P: Buffer.from(f.P, "hex"), + Q: Buffer.from(f.Q, "hex"), + })), + pointAddScalar: _fpoints.valid.pointAddScalar.map((f) => ({ + P: Buffer.from(f.P, "hex"), + d: Buffer.from(f.d, "hex"), + })), + pointCompress: _fpoints.valid.pointCompress.map((f) => ({ + P: Buffer.from(f.P, "hex"), + })), + pointFromScalar: _fpoints.valid.pointFromScalar.map((f) => ({ + d: Buffer.from(f.d, "hex"), + })), + pointMultiply: _fpoints.valid.pointMultiply.map((f) => ({ + P: Buffer.from(f.P, "hex"), + d: Buffer.from(f.d, "hex"), + })), +}; + +export const fprivates = { + isPrivate: _fprivates.valid.isPrivate.map((f) => ({ + d: Buffer.from(f.d, "hex"), + })), + privateAdd: _fprivates.valid.privateAdd.map((f) => ({ + d: Buffer.from(f.d, "hex"), + tweak: Buffer.from(f.tweak, "hex"), + })), + privateSub: _fprivates.valid.privateSub.map((f) => ({ + d: Buffer.from(f.d, "hex"), + tweak: Buffer.from(f.tweak, "hex"), + })), +}; diff --git a/benches/index.js b/benches/index.js new file mode 100644 index 0000000..090b91f --- /dev/null +++ b/benches/index.js @@ -0,0 +1,196 @@ +import tiny_secp256k1_prev_js from "tiny-secp256k1/js.js"; +import tiny_secp256k1_prev_native from "tiny-secp256k1/native.js"; +import * as tiny_secp256k1 from "../lib/index.js"; +import { fecdsa, fpoints, fprivates } from "./fixtures.js"; + +const modules = [ + { + name: "tiny-secp256k1 (rust addon)", + secp256k1: tiny_secp256k1.__addon, + }, + { + name: "tiny-secp256k1 (wasm)", + secp256k1: tiny_secp256k1.__wasm, + }, + { + name: "tiny-secp256k1@1.1.6 (C++ addon, NAN/V8)", + secp256k1: tiny_secp256k1_prev_native, + }, + { + name: "tiny-secp256k1@1.1.6 (elliptic)", + secp256k1: tiny_secp256k1_prev_js, + }, + // cryptocoinjs/secp256k1-node (C++ addon, N-API) + // cryptocoinjs/secp256k1-node (elliptic) +]; + +const benchmarks = [ + { + name: "isPoint", + bench: createBenchmarkFn(fpoints.isPoint, (secp256k1, f) => + secp256k1.isPoint(f.P) + ), + }, + { + name: "isPrivate", + bench: createBenchmarkFn(fprivates.isPrivate, (secp256k1, f) => + secp256k1.isPrivate(f.P, f.d) + ), + }, + { + name: "pointAdd", + bench: createBenchmarkFn(fpoints.pointAdd, (secp256k1, f) => + secp256k1.pointAdd(f.P, f.Q) + ), + }, + { + name: "pointAddScalar", + bench: createBenchmarkFn(fpoints.pointAddScalar, (secp256k1, f) => + secp256k1.pointAddScalar(f.P, f.d) + ), + }, + { + name: "pointCompress", + bench: createBenchmarkFn(fpoints.pointCompress, (secp256k1, f) => + secp256k1.pointCompress(f.P) + ), + }, + { + name: "pointFromScalar", + bench: createBenchmarkFn(fpoints.pointFromScalar, (secp256k1, f) => + secp256k1.pointFromScalar(f.d) + ), + }, + { + name: "pointMultiply", + bench: createBenchmarkFn(fpoints.pointMultiply, (secp256k1, f) => + secp256k1.pointMultiply(f.P, f.d) + ), + }, + { + name: "privateAdd", + bench: createBenchmarkFn(fprivates.privateAdd, (secp256k1, f) => + secp256k1.privateAdd(f.d, f.tweak) + ), + }, + { + name: "privateSub", + bench: createBenchmarkFn(fprivates.privateSub, (secp256k1, f) => + secp256k1.privateSub(f.d, f.tweak) + ), + }, + { + name: "sign", + bench: createBenchmarkFn(fecdsa, (secp256k1, f) => + secp256k1.sign(f.m, f.d) + ), + }, + { + name: "verify", + bench: createBenchmarkFn(fecdsa, (secp256k1, f) => + secp256k1.verify(f.m, f.Q, f.signature) + ), + }, +]; + +// Covert milliseconds as Number to nanoseconds as BigInt +const millis2nanos = (ms) => BigInt(ms) * 10n ** 6n; + +// Warmup bench function during +function warmingUp(bench, minIter, maxTime) { + const start = process.hrtime.bigint(); + for (let i = 0; ; ) { + bench(); + if (process.hrtime.bigint() - start > maxTime && ++i >= minIter) { + break; + } + } +} + +// Create benchmark function from fixtures +function createBenchmarkFn(fixtures, fn) { + return function (secp256k1) { + for (const f of fixtures) { + fn(secp256k1, f); + } + return fixtures.length; + }; +} + +// Run benchmarks +const lineEqual = new Array(100).fill("=").join(""); +const lineDash = new Array(100).fill("-").join(""); +let isFirstResult = true; +for (const benchmark of benchmarks) { + const { + name, + bench, + warmingUpMinIter, + warmingUpMaxTime, + benchmarkMinIter, + benchmarkMaxTime, + } = { + warmingUpMinIter: 1, + warmingUpMaxTime: millis2nanos(200), + benchmarkMinIter: 2, + benchmarkMaxTime: millis2nanos(500), + ...benchmark, + }; + + if (isFirstResult) { + console.log(lineEqual); + isFirstResult = false; + } + console.log(`Benchmarking function: ${name}`); + console.log(lineDash); + const results = []; + for (const module of modules) { + warmingUp( + () => bench(module.secp256k1), + warmingUpMinIter, + warmingUpMaxTime + ); + + const results_ns = []; + const start = process.hrtime.bigint(); + let start_fn = start; + for (let i = 0; ; ) { + const ops = bench(module.secp256k1); + const current = process.hrtime.bigint(); + results_ns.push(Number(current - start_fn) / ops); + if (current - start > benchmarkMaxTime && ++i >= benchmarkMinIter) { + break; + } + start_fn = current; + } + + const ops_avg_ns = + results_ns.reduce((total, time) => total + time, 0) / results_ns.length; + const ops_err_ns = + results_ns.length > 1 + ? results_ns.reduce( + (total, time) => total + Math.abs(ops_avg_ns - time), + 0 + ) / + (results_ns.length - 1) + : 0; + const ops_err = (ops_err_ns / ops_avg_ns) * 100; + + console.log( + `${module.name}: ${(ops_avg_ns / 1000).toFixed(2)} us/op (${( + 10 ** 9 / + ops_avg_ns + ).toFixed(2)} op/s), ±${ops_err.toFixed(2)} %` + ); + + results.push({ name: module.name, ops_avg_ns }); + } + if (results.length > 1) { + const fastest = results.reduce((a, b) => + a.ops_avg_ns < b.ops_avg_ns ? a : b + ); + console.log(lineDash); + console.log(`Fastest: ${fastest.name}`); + } + console.log(lineEqual); +} diff --git a/benches/package-lock.json b/benches/package-lock.json new file mode 100644 index 0000000..a7eb86d --- /dev/null +++ b/benches/package-lock.json @@ -0,0 +1,480 @@ +{ + "name": "tiny-secp256k1-benches", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "tiny-secp256k1-benches", + "version": "0.0.0", + "license": "MIT", + "devDependencies": { + "ms": "^2.1.3", + "tiny-secp256k1": "=1.1.6" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "dev": true + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/tiny-secp256k1": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.6.tgz", + "integrity": "sha512-FmqJZGduTyvsr2cF3375fqGHUovSwDi/QytexX1Se4BPuPZpTE5Ftp5fg+EFSuEf3lhZqgCRjEG3ydUQ/aNiwA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.3.0", + "bn.js": "^4.11.8", + "create-hmac": "^1.1.7", + "elliptic": "^6.4.0", + "nan": "^2.13.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + } + }, + "dependencies": { + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "dev": true + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "tiny-secp256k1": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.6.tgz", + "integrity": "sha512-FmqJZGduTyvsr2cF3375fqGHUovSwDi/QytexX1Se4BPuPZpTE5Ftp5fg+EFSuEf3lhZqgCRjEG3ydUQ/aNiwA==", + "dev": true, + "requires": { + "bindings": "^1.3.0", + "bn.js": "^4.11.8", + "create-hmac": "^1.1.7", + "elliptic": "^6.4.0", + "nan": "^2.13.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + } + } +} diff --git a/benches/package.json b/benches/package.json new file mode 100644 index 0000000..e511931 --- /dev/null +++ b/benches/package.json @@ -0,0 +1,14 @@ +{ + "name": "tiny-secp256k1-benches", + "version": "0.0.0", + "private": true, + "description": "tiny-secp256k1 benchmarks", + "license": "MIT", + "type": "module", + "scripts": { + "start": "node --experimental-json-modules index.js" + }, + "devDependencies": { + "tiny-secp256k1": "=1.1.6" + } +} diff --git a/package.json b/package.json index f0c93ab..aeb6152 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "tiny-secp256k1", "version": "1.1.6", + "private": true, "description": "A tiny secp256k1 JS", "homepage": "https://github.com/bitcoinjs/tiny-secp256k1#readme", "bugs": { @@ -25,6 +26,7 @@ "path-browserify": "^1.0.1", "prettier": "^2.2.1", "process": "^0.11.10", + "sort-package-json": "^1.49.0", "stream-browserify": "^3.0.0", "tap-difflet": "^0.7.2", "tape": "^5.2.2", From 7e81a07fce5c6b0e302cf07111cb6af71df43c60 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Thu, 18 Mar 2021 13:51:27 +0300 Subject: [PATCH 2/2] add secp256k1 to benches --- benches/cryptocoinjs_secp256k1.js | 24 +++++++++++ benches/fixtures.js | 50 +++++++++++++--------- benches/index.js | 21 +++++++--- benches/package-lock.json | 69 +++++++++++++++++++++++++------ benches/package.json | 1 + lib/api.js | 4 +- 6 files changed, 129 insertions(+), 40 deletions(-) create mode 100644 benches/cryptocoinjs_secp256k1.js diff --git a/benches/cryptocoinjs_secp256k1.js b/benches/cryptocoinjs_secp256k1.js new file mode 100644 index 0000000..d75bfe2 --- /dev/null +++ b/benches/cryptocoinjs_secp256k1.js @@ -0,0 +1,24 @@ +import secp256k1_js from "secp256k1/elliptic.js"; +import secp256k1_native from "secp256k1/bindings.js"; + +export const js = createApi(secp256k1_js); +export const native = createApi(secp256k1_native); + +function createApi(secp256k1) { + return { + isPoint: (p) => secp256k1.publicKeyVerify(p), + // isPointCompressed + isPrivate: (d) => secp256k1.privateKeyVerify(d), + pointAdd: (pA, pB) => secp256k1.publicKeyCombine([pA, pB]), + pointAddScalar: (p, tweak) => secp256k1.publicKeyTweakAdd(p, tweak), + // pointCompress + pointFromScalar: (d) => secp256k1.publicKeyCreate(d), + pointMultiply: (p, tweak) => secp256k1.publicKeyTweakMul(p, tweak), + privateAdd: (d, tweak) => + secp256k1.privateKeyTweakAdd(new Uint8Array(d), tweak), + // privateSub + sign: (h, d) => secp256k1.ecdsaSign(h, d), + // signWithEntropy + verify: (h, Q, signature) => secp256k1.ecdsaVerify(signature, h, Q), + }; +} diff --git a/benches/fixtures.js b/benches/fixtures.js index dc283c7..4eb27f9 100644 --- a/benches/fixtures.js +++ b/benches/fixtures.js @@ -14,36 +14,46 @@ export const fpoints = { isPoint: _fpoints.valid.isPoint.map((f) => ({ P: Buffer.from(f.P, "hex"), })), - pointAdd: _fpoints.valid.pointAdd.map((f) => ({ - P: Buffer.from(f.P, "hex"), - Q: Buffer.from(f.Q, "hex"), - })), - pointAddScalar: _fpoints.valid.pointAddScalar.map((f) => ({ - P: Buffer.from(f.P, "hex"), - d: Buffer.from(f.d, "hex"), - })), + pointAdd: _fpoints.valid.pointAdd + .filter((f) => f.expected !== null) + .map((f) => ({ + P: Buffer.from(f.P, "hex"), + Q: Buffer.from(f.Q, "hex"), + })), + pointAddScalar: _fpoints.valid.pointAddScalar + .filter((f) => f.expected !== null) + .map((f) => ({ + P: Buffer.from(f.P, "hex"), + d: Buffer.from(f.d, "hex"), + })), pointCompress: _fpoints.valid.pointCompress.map((f) => ({ P: Buffer.from(f.P, "hex"), })), pointFromScalar: _fpoints.valid.pointFromScalar.map((f) => ({ d: Buffer.from(f.d, "hex"), })), - pointMultiply: _fpoints.valid.pointMultiply.map((f) => ({ - P: Buffer.from(f.P, "hex"), - d: Buffer.from(f.d, "hex"), - })), + pointMultiply: _fpoints.valid.pointMultiply + .filter((f) => f.expected !== null) + .map((f) => ({ + P: Buffer.from(f.P, "hex"), + d: Buffer.from(f.d, "hex"), + })), }; export const fprivates = { isPrivate: _fprivates.valid.isPrivate.map((f) => ({ d: Buffer.from(f.d, "hex"), })), - privateAdd: _fprivates.valid.privateAdd.map((f) => ({ - d: Buffer.from(f.d, "hex"), - tweak: Buffer.from(f.tweak, "hex"), - })), - privateSub: _fprivates.valid.privateSub.map((f) => ({ - d: Buffer.from(f.d, "hex"), - tweak: Buffer.from(f.tweak, "hex"), - })), + privateAdd: _fprivates.valid.privateAdd + .filter((f) => f.expected !== null) + .map((f) => ({ + d: Buffer.from(f.d, "hex"), + tweak: Buffer.from(f.tweak, "hex"), + })), + privateSub: _fprivates.valid.privateSub + .filter((f) => f.expected !== null) + .map((f) => ({ + d: Buffer.from(f.d, "hex"), + tweak: Buffer.from(f.tweak, "hex"), + })), }; diff --git a/benches/index.js b/benches/index.js index 090b91f..21d527d 100644 --- a/benches/index.js +++ b/benches/index.js @@ -1,6 +1,7 @@ import tiny_secp256k1_prev_js from "tiny-secp256k1/js.js"; import tiny_secp256k1_prev_native from "tiny-secp256k1/native.js"; import * as tiny_secp256k1 from "../lib/index.js"; +import * as cryptocoinjs_secp256k1 from "./cryptocoinjs_secp256k1.js"; import { fecdsa, fpoints, fprivates } from "./fixtures.js"; const modules = [ @@ -20,8 +21,14 @@ const modules = [ name: "tiny-secp256k1@1.1.6 (elliptic)", secp256k1: tiny_secp256k1_prev_js, }, - // cryptocoinjs/secp256k1-node (C++ addon, N-API) - // cryptocoinjs/secp256k1-node (elliptic) + { + name: "secp256k1@4.0.2 (C++ addon, N-API)", + secp256k1: cryptocoinjs_secp256k1.native, + }, + { + name: "secp256k1@4.0.2 (elliptic)", + secp256k1: cryptocoinjs_secp256k1.js, + }, ]; const benchmarks = [ @@ -34,7 +41,7 @@ const benchmarks = [ { name: "isPrivate", bench: createBenchmarkFn(fprivates.isPrivate, (secp256k1, f) => - secp256k1.isPrivate(f.P, f.d) + secp256k1.isPrivate(f.d) ), }, { @@ -131,9 +138,9 @@ for (const benchmark of benchmarks) { benchmarkMaxTime, } = { warmingUpMinIter: 1, - warmingUpMaxTime: millis2nanos(200), benchmarkMinIter: 2, - benchmarkMaxTime: millis2nanos(500), + warmingUpMaxTime: millis2nanos(2000), + benchmarkMaxTime: millis2nanos(5000), ...benchmark, }; @@ -145,6 +152,10 @@ for (const benchmark of benchmarks) { console.log(lineDash); const results = []; for (const module of modules) { + if (module.secp256k1[name] === undefined) { + continue; + } + warmingUp( () => bench(module.secp256k1), warmingUpMinIter, diff --git a/benches/package-lock.json b/benches/package-lock.json index a7eb86d..5e60dd5 100644 --- a/benches/package-lock.json +++ b/benches/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0", "license": "MIT", "devDependencies": { - "ms": "^2.1.3", + "secp256k1": "^4.0.2", "tiny-secp256k1": "=1.1.6" } }, @@ -156,18 +156,29 @@ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", "dev": true }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/nan": { "version": "2.14.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", "dev": true }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "node_modules/node-gyp-build": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", + "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==", + "dev": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -212,6 +223,21 @@ } ] }, + "node_modules/secp256k1": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz", + "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "elliptic": "^6.5.2", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", @@ -399,18 +425,24 @@ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", "dev": true }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "nan": { "version": "2.14.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", "dev": true }, + "node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "node-gyp-build": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", + "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==", + "dev": true + }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -438,6 +470,17 @@ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, + "secp256k1": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz", + "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==", + "dev": true, + "requires": { + "elliptic": "^6.5.2", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, "sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", diff --git a/benches/package.json b/benches/package.json index e511931..d30768f 100644 --- a/benches/package.json +++ b/benches/package.json @@ -9,6 +9,7 @@ "start": "node --experimental-json-modules index.js" }, "devDependencies": { + "secp256k1": "=4.0.2", "tiny-secp256k1": "=1.1.6" } } diff --git a/lib/api.js b/lib/api.js index b08ab13..9739612 100644 --- a/lib/api.js +++ b/lib/api.js @@ -29,8 +29,8 @@ export default function createApi(secp256k1) { return validate.isPointCompressed(p) && secp256k1.isPoint(p); }, - isPrivate(x) { - return validate.isPrivate(x); + isPrivate(d) { + return validate.isPrivate(d); }, pointAdd(pA, pB, compressed) {