feat: use esm

BREAKING CHANGE:
Only esm is exported, no commonjs
Named exports (excluding `bls`) are no longer exported from the root.
`browser` and `node` exports are removed in favor of
implementation-specific naming.
This commit is contained in:
Cayman 2022-04-11 10:08:15 -05:00
parent 53df67a2dd
commit 0056e13ee5
No known key found for this signature in database
GPG Key ID: 54B21AEC3C53E1F5
57 changed files with 1109 additions and 601 deletions

View File

@ -13,13 +13,15 @@ module.exports = {
}, },
parser: "@typescript-eslint/parser", parser: "@typescript-eslint/parser",
parserOptions: { parserOptions: {
ecmaVersion: 10, ecmaVersion: "latest",
project: "./tsconfig.json" project: "./tsconfig.json",
sourceType: "module",
}, },
plugins: [ plugins: [
"@typescript-eslint", "@typescript-eslint",
"eslint-plugin-import", "eslint-plugin-import",
"prettier" "prettier",
"@chainsafe/eslint-plugin-node"
], ],
extends: [ extends: [
"eslint:recommended", "eslint:recommended",
@ -33,13 +35,13 @@ module.exports = {
"prettier/prettier": "error", "prettier/prettier": "error",
//doesnt work, it reports false errors //doesnt work, it reports false errors
"constructor-super": "off", "constructor-super": "off",
"@typescript-eslint/class-name-casing": "error", //"@typescript-eslint/class-name-casing": "error",
"@typescript-eslint/explicit-function-return-type": ["error", { "@typescript-eslint/explicit-function-return-type": ["error", {
"allowExpressions": true "allowExpressions": true
}], }],
"@typescript-eslint/func-call-spacing": "error", "@typescript-eslint/func-call-spacing": "error",
"@typescript-eslint/indent": ["error", 2], "@typescript-eslint/indent": ["error", 2],
"@typescript-eslint/interface-name-prefix": ["error", "always"], //"@typescript-eslint/interface-name-prefix": ["error", "always"],
"@typescript-eslint/member-ordering": "error", "@typescript-eslint/member-ordering": "error",
"@typescript-eslint/no-explicit-any": "error", "@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-require-imports": "error", "@typescript-eslint/no-require-imports": "error",
@ -47,7 +49,7 @@ module.exports = {
"varsIgnorePattern": "^_", "varsIgnorePattern": "^_",
"argsIgnorePattern": "^_", "argsIgnorePattern": "^_",
}], }],
"@typescript-eslint/ban-ts-ignore": "warn", "@typescript-eslint/ban-ts-comment": "warn",
"@typescript-eslint/no-use-before-define": "off", "@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/semi": "error", "@typescript-eslint/semi": "error",
"@typescript-eslint/type-annotation-spacing": "error", "@typescript-eslint/type-annotation-spacing": "error",
@ -76,7 +78,15 @@ module.exports = {
"no-prototype-builtins": 0, "no-prototype-builtins": 0,
"prefer-const": "error", "prefer-const": "error",
"quotes": ["error", "double"], "quotes": ["error", "double"],
"semi": "off" "semi": "off",
"@chainsafe/node/file-extension-in-import": [
"error",
"always",
{
"esm": true
}
],
"import/no-unresolved": "off",
}, },
"overrides": [ "overrides": [
{ {

View File

@ -1,2 +1,6 @@
extension: ["ts"]
colors: true colors: true
require: ts-node/register node-option:
- "experimental-specifier-resolution=node"
- "loader=ts-node/esm"

View File

@ -45,22 +45,22 @@ import {init, SecretKey, secretKeyToPublicKey, sign, verify} from "@chainsafe/bl
### Browser ### Browser
If you are in the browser, import from `/browser` to import directly the WASM version If you are in the browser, import from `/herumi` to import directly the WASM version
```ts ```ts
import bls from "@chainsafe/bls/browser"; import bls from "@chainsafe/bls/herumi";
``` ```
### Native bindings only ### Native bindings only
If you are in NodeJS, import from `/node` to skip browser specific code. Also install peer dependency `@chainsafe/blst` which has the native bindings If you are in NodeJS, import from `/blst-native` to skip browser specific code. Also install peer dependency `@chainsafe/blst` which has the native bindings
```bash ```bash
yarn add @chainsafe/bls @chainsafe/blst yarn add @chainsafe/bls @chainsafe/blst
``` ```
```ts ```ts
import bls from "@chainsafe/bls/node"; import bls from "@chainsafe/bls/blst-native";
``` ```
### Native bindings + WASM fallback ### Native bindings + WASM fallback
@ -86,7 +86,7 @@ The API is identical for all implementations.
## Benchmarks ## Benchmarks
- `blst`: [src/blst](src/blst) (node.js-only, bindings to C via node-gyp) - `blst`: [src/blst-native](src/blst-native) (node.js-only, bindings to C via node-gyp)
- `herumi`: [src/herumi](src/herumi) (node.js & browser, wasm) - `herumi`: [src/herumi](src/herumi) (node.js & browser, wasm)
- `noble`: [noble-bls12-381](https://github.com/paulmillr/noble-bls12-381) (node.js & browser, pure JS) - `noble`: [noble-bls12-381](https://github.com/paulmillr/noble-bls12-381) (node.js & browser, pure JS)

View File

@ -1,7 +1,7 @@
import {runBenchmark} from "./runner"; import {runBenchmark} from "./runner.js";
import {runForAllImplementations} from "../test/switch"; import {runForAllImplementations} from "../test/switch.js";
import {PublicKey, Signature} from "../src/interface"; import {PublicKey, Signature} from "../src/interface.js";
import {aggCount} from "./params"; import {aggCount} from "./params.js";
(async function () { (async function () {
await runForAllImplementations(async (bls, implementation) => { await runForAllImplementations(async (bls, implementation) => {

View File

@ -1,8 +1,8 @@
import {runBenchmark} from "./runner"; import {runBenchmark} from "./runner.js";
import {range, randomMessage} from "../test/util"; import {range, randomMessage} from "../test/util.js";
import {generateRandomSecretKey} from "@chainsafe/bls-keygen"; import {generateRandomSecretKey} from "@chainsafe/bls-keygen";
import * as noble from "noble-bls12-381"; import * as noble from "noble-bls12-381";
import {aggCount, runsNoble} from "./params"; import {aggCount, runsNoble} from "./params.js";
(async function () { (async function () {
{ {

View File

@ -1,11 +1,12 @@
{ {
"name": "bls-libs-benchmark", "name": "bls-libs-benchmark",
"version": "1.0.0", "version": "1.0.0",
"main": "index.js", "type": "module",
"exports": "./index.js",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"benchmark": "ts-node index", "benchmark": "ts-node-esm index",
"benchmark:all": "ts-node index && ts-node noble && ts-node verifyMultipleSignaturesSavings" "benchmark:all": "ts-node-esm index && ts-node-esm noble && ts-node-esm verifyMultipleSignaturesSavings"
}, },
"dependencies": { "dependencies": {
"noble-bls12-381": "^0.7.2" "noble-bls12-381": "^0.7.2"

View File

@ -1,5 +1,5 @@
import {runForAllImplementations} from "../test/switch"; import {runForAllImplementations} from "../test/switch.js";
import {range, randomMessage} from "../test/util"; import {range, randomMessage} from "../test/util.js";
(async function () { (async function () {
console.log("verifyMultipleSignatures savings"); console.log("verifyMultipleSignatures savings");

1
blst-native.d.ts vendored
View File

@ -1 +0,0 @@
export * from "./lib/blst";

View File

@ -1 +0,0 @@
module.exports = require("./lib/blst");

1
browser.d.ts vendored
View File

@ -1 +0,0 @@
export * from "./lib/herumi";

View File

@ -1 +0,0 @@
export * from "./lib/herumi";

1
herumi.d.ts vendored
View File

@ -1 +0,0 @@
export * from "./lib/herumi";

View File

@ -1 +0,0 @@
module.exports = require("./lib/herumi");

View File

@ -1,5 +1,5 @@
// eslint-disable-next-line @typescript-eslint/no-require-imports // eslint-disable-next-line @typescript-eslint/no-require-imports
const webpackConfig = require("./webpack.config"); const webpackConfig = require("./webpack.config.cjs");
module.exports = function (config) { module.exports = function (config) {
config.set({ config.set({

1
node.d.ts vendored
View File

@ -1 +0,0 @@
export * from "./lib/blst";

View File

@ -1 +0,0 @@
module.exports = require("./lib/blst");

View File

@ -2,8 +2,34 @@
"name": "@chainsafe/bls", "name": "@chainsafe/bls",
"version": "6.0.3", "version": "6.0.3",
"description": "Implementation of bls signature verification for ethereum 2.0", "description": "Implementation of bls signature verification for ethereum 2.0",
"main": "lib/index.js", "type": "module",
"exports": {
".": {
"import": "./lib/index.js"
},
"./register": {
"import": "./register.js"
},
"./types": {
"import": "./lib/types.js"
},
"./blst-native": {
"import": "./lib/blst-native/index.js"
},
"./herumi": {
"import": "./lib/herumi/index.js"
}
},
"types": "lib/index.d.ts", "types": "lib/index.d.ts",
"typesVersions": {
"*": {
"*": [
"*",
"lib/*",
"lib/*/index"
]
}
},
"module": "./browser", "module": "./browser",
"browser": "./browser", "browser": "./browser",
"homepage": "https://github.com/chainsafe/bls", "homepage": "https://github.com/chainsafe/bls",
@ -24,18 +50,19 @@
], ],
"scripts": { "scripts": {
"clean": "rm -rf lib && rm -rf dist && rm -f tsconfig.tsbuildinfo", "clean": "rm -rf lib && rm -rf dist && rm -f tsconfig.tsbuildinfo",
"check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"",
"build": "tsc --incremental --project tsconfig.build.json", "build": "tsc --incremental --project tsconfig.build.json",
"lint": "eslint --color --ext .ts src/ test/", "lint": "eslint --color --ext .ts src/ test/",
"lint:fix": "yarn run lint --fix", "lint:fix": "yarn run lint --fix",
"prepublishOnly": "yarn build", "prepublishOnly": "yarn build",
"test:web": "karma start", "test:web": "karma start karma.conf.cjs",
"test:unit": "mocha 'test/unit/**/*.test.ts'", "test:unit": "mocha 'test/unit/**/*.test.ts'",
"test:coverage": "nyc --cache-dir .nyc_output/.cache -r lcov -e .ts mocha 'test/unit/**/*.test.ts' && nyc report", "test:coverage": "nyc --cache-dir .nyc_output/.cache -r lcov -e .ts mocha 'test/unit/**/*.test.ts' && nyc report",
"test:spec": "mocha 'test/spec/**/*.test.ts'", "test:spec": "mocha 'test/spec/**/*.test.ts'",
"test": "yarn run test:unit && yarn run test:spec", "test": "yarn run test:unit && yarn run test:spec",
"download-test-cases": "ts-node test/downloadSpecTests.ts", "download-test-cases": "ts-node-esm test/downloadSpecTests.ts",
"coverage": "codecov -F bls", "coverage": "codecov -F bls",
"benchmark": "ts-node benchmark", "benchmark": "ts-node-esm benchmark",
"benchmark:all": "cd benchmark && yarn install && yarn benchmark:all" "benchmark:all": "cd benchmark && yarn install && yarn benchmark:all"
}, },
"dependencies": { "dependencies": {
@ -45,14 +72,15 @@
}, },
"devDependencies": { "devDependencies": {
"@chainsafe/blst": "^0.2.0", "@chainsafe/blst": "^0.2.0",
"@chainsafe/eslint-plugin-node": "^11.2.3",
"@chainsafe/lodestar-spec-test-util": "^0.18.0", "@chainsafe/lodestar-spec-test-util": "^0.18.0",
"@types/chai": "^4.2.9", "@types/chai": "^4.2.9",
"@types/mocha": "^8.0.4", "@types/mocha": "^8.0.4",
"@types/randombytes": "^2.0.0", "@types/randombytes": "^2.0.0",
"@typescript-eslint/eslint-plugin": "^2.20.0", "@typescript-eslint/eslint-plugin": "^4.31.1",
"@typescript-eslint/parser": "^2.20.0", "@typescript-eslint/parser": "^4.31.1",
"chai": "^4.2.0", "chai": "^4.3.6",
"eslint": "^6.8.0", "eslint": "^7.14.0",
"eslint-plugin-import": "^2.20.1", "eslint-plugin-import": "^2.20.1",
"eslint-plugin-prettier": "^3.1.4", "eslint-plugin-prettier": "^3.1.4",
"karma": "^4.4.1", "karma": "^4.4.1",
@ -62,18 +90,19 @@
"karma-mocha": "^1.3.0", "karma-mocha": "^1.3.0",
"karma-spec-reporter": "^0.0.32", "karma-spec-reporter": "^0.0.32",
"karma-webpack": "^4.0.2", "karma-webpack": "^4.0.2",
"mocha": "^8.2.1", "mocha": "^9.2.2",
"nyc": "^15.0.0", "nyc": "^15.0.0",
"prettier": "^2.1.2", "prettier": "^2.1.2",
"threads": "^1.6.3", "resolve-typescript-plugin": "^1.1.5",
"ts-loader": "^6.2.1", "threads": "^1.7.0",
"ts-node": "^8.6.2", "ts-loader": "^8.3.0",
"typescript": "^3.7.5", "ts-node": "^10.7.0",
"typescript": "^4.6.3",
"webpack": "^4.30.0", "webpack": "^4.30.0",
"webpack-cli": "^3.3.2" "webpack-cli": "^3.3.2"
}, },
"resolutions": { "resolutions": {
"mocha": "^8.2.1", "mocha": "^9.2.2",
"v8-profiler-next": "1.3.0" "v8-profiler-next": "1.3.0"
}, },
"peerDependencies": { "peerDependencies": {

View File

@ -1,5 +1,3 @@
const {init} = require("./lib");
// ----------------------------------------- // -----------------------------------------
// To be used in NodeJS testing environments // To be used in NodeJS testing environments
// node -r @chainsafe/bls/register // node -r @chainsafe/bls/register
@ -7,7 +5,7 @@ const {init} = require("./lib");
// blst-native initialization is syncronous // blst-native initialization is syncronous
// Initialize bls here instead of in before() so it's available inside describe() blocks // Initialize bls here instead of in before() so it's available inside describe() blocks
init("blst-native").catch((e) => { import("./lib/index.js").then(({init}) => init("blst-native")).catch((e) => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error(e); console.error(e);
process.exit(1); process.exit(1);

View File

@ -1,9 +1,9 @@
import {SecretKey} from "./secretKey"; import {SecretKey} from "./secretKey.js";
import {PublicKey} from "./publicKey"; import {PublicKey} from "./publicKey.js";
import {Signature} from "./signature"; import {Signature} from "./signature.js";
import {IBls} from "../interface"; import {IBls} from "../interface.js";
import {functionalInterfaceFactory} from "../functional"; import {functionalInterfaceFactory} from "../functional.js";
export * from "../constants"; export * from "../constants.js";
export {SecretKey, PublicKey, Signature}; export {SecretKey, PublicKey, Signature};

View File

@ -1,7 +1,7 @@
import * as blst from "@chainsafe/blst"; import * as blst from "@chainsafe/blst";
import {EmptyAggregateError} from "../errors"; import {EmptyAggregateError} from "../errors.js";
import {bytesToHex, hexToBytes} from "../helpers"; import {bytesToHex, hexToBytes} from "../helpers/index.js";
import {PointFormat, PublicKey as IPublicKey} from "../interface"; import {PointFormat, PublicKey as IPublicKey} from "../interface.js";
export class PublicKey extends blst.PublicKey implements IPublicKey { export class PublicKey extends blst.PublicKey implements IPublicKey {
constructor(value: ConstructorParameters<typeof blst.PublicKey>[0]) { constructor(value: ConstructorParameters<typeof blst.PublicKey>[0]) {

View File

@ -1,10 +1,10 @@
import * as blst from "@chainsafe/blst"; import * as blst from "@chainsafe/blst";
import {bytesToHex, hexToBytes, isZeroUint8Array, randomBytes} from "../helpers"; import {bytesToHex, hexToBytes, isZeroUint8Array, randomBytes} from "../helpers/index.js";
import {SECRET_KEY_LENGTH} from "../constants"; import {SECRET_KEY_LENGTH} from "../constants.js";
import {SecretKey as ISecretKey} from "../interface"; import {SecretKey as ISecretKey} from "../interface.js";
import {PublicKey} from "./publicKey"; import {PublicKey} from "./publicKey.js";
import {Signature} from "./signature"; import {Signature} from "./signature.js";
import {ZeroSecretKeyError} from "../errors"; import {ZeroSecretKeyError} from "../errors.js";
export class SecretKey implements ISecretKey { export class SecretKey implements ISecretKey {
readonly value: blst.SecretKey; readonly value: blst.SecretKey;

View File

@ -1,8 +1,8 @@
import * as blst from "@chainsafe/blst"; import * as blst from "@chainsafe/blst";
import {bytesToHex, hexToBytes} from "../helpers"; import {bytesToHex, hexToBytes} from "../helpers/index.js";
import {PointFormat, Signature as ISignature} from "../interface"; import {PointFormat, Signature as ISignature} from "../interface.js";
import {PublicKey} from "./publicKey"; import {PublicKey} from "./publicKey.js";
import {EmptyAggregateError, ZeroSignatureError} from "../errors"; import {EmptyAggregateError, ZeroSignatureError} from "../errors.js";
export class Signature extends blst.Signature implements ISignature { export class Signature extends blst.Signature implements ISignature {
constructor(value: ConstructorParameters<typeof blst.Signature>[0]) { constructor(value: ConstructorParameters<typeof blst.Signature>[0]) {

View File

@ -1,9 +1,10 @@
import {IBls} from "./interface"; import {IBls} from "./interface.js";
import {validateBytes} from "./helpers"; import {validateBytes} from "./helpers/index.js";
import {NotInitializedError} from "./errors"; import {NotInitializedError} from "./errors.js";
// Returned type is enforced at each implementation's index // Returned type is enforced at each implementation's index
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type // eslint-disable-next-line max-len
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type,@typescript-eslint/explicit-module-boundary-types
export function functionalInterfaceFactory({ export function functionalInterfaceFactory({
SecretKey, SecretKey,
PublicKey, PublicKey,

View File

@ -1,2 +1,2 @@
export * from "./hex"; export * from "./hex.js";
export * from "./utils"; export * from "./utils.js";

View File

@ -1,6 +1,6 @@
/* eslint-disable require-atomic-updates */ /* eslint-disable require-atomic-updates */
import bls from "bls-eth-wasm"; import bls from "bls-eth-wasm";
import {NotInitializedError} from "../errors"; import {NotInitializedError} from "../errors.js";
type Bls = typeof bls; type Bls = typeof bls;
let blsGlobal: Bls | null = null; let blsGlobal: Bls | null = null;
@ -8,7 +8,6 @@ let blsGlobalPromise: Promise<void> | null = null;
// Patch to fix multiVerify() calls on a browser with polyfilled NodeJS crypto // Patch to fix multiVerify() calls on a browser with polyfilled NodeJS crypto
declare global { declare global {
// eslint-disable-next-line @typescript-eslint/interface-name-prefix
interface Window { interface Window {
msCrypto: typeof window["crypto"]; msCrypto: typeof window["crypto"];
} }

View File

@ -1,10 +1,10 @@
import {SecretKey} from "./secretKey"; import {SecretKey} from "./secretKey.js";
import {PublicKey} from "./publicKey"; import {PublicKey} from "./publicKey.js";
import {Signature} from "./signature"; import {Signature} from "./signature.js";
import {init, destroy} from "./context"; import {init, destroy} from "./context.js";
import {IBls} from "../interface"; import {IBls} from "../interface.js";
import {functionalInterfaceFactory} from "../functional"; import {functionalInterfaceFactory} from "../functional.js";
export * from "../constants"; export * from "../constants.js";
export {SecretKey, PublicKey, Signature, init, destroy}; export {SecretKey, PublicKey, Signature, init, destroy};

View File

@ -1,9 +1,9 @@
import {PublicKeyType} from "bls-eth-wasm"; import type {PublicKeyType} from "bls-eth-wasm";
import {getContext} from "./context"; import {getContext} from "./context.js";
import {bytesToHex, hexToBytes, isZeroUint8Array} from "../helpers"; import {bytesToHex, hexToBytes, isZeroUint8Array} from "../helpers/index.js";
import {PointFormat, PublicKey as IPublicKey} from "../interface"; import {PointFormat, PublicKey as IPublicKey} from "../interface.js";
import {EmptyAggregateError, InvalidLengthError, ZeroPublicKeyError} from "../errors"; import {EmptyAggregateError, InvalidLengthError, ZeroPublicKeyError} from "../errors.js";
import {PUBLIC_KEY_LENGTH_COMPRESSED, PUBLIC_KEY_LENGTH_UNCOMPRESSED} from "../constants"; import {PUBLIC_KEY_LENGTH_COMPRESSED, PUBLIC_KEY_LENGTH_UNCOMPRESSED} from "../constants.js";
export class PublicKey implements IPublicKey { export class PublicKey implements IPublicKey {
readonly value: PublicKeyType; readonly value: PublicKeyType;

View File

@ -1,12 +1,12 @@
import {SecretKeyType} from "bls-eth-wasm"; import type {SecretKeyType} from "bls-eth-wasm";
import {generateRandomSecretKey} from "@chainsafe/bls-keygen"; import {generateRandomSecretKey} from "@chainsafe/bls-keygen";
import {SECRET_KEY_LENGTH} from "../constants"; import {SECRET_KEY_LENGTH} from "../constants.js";
import {getContext} from "./context"; import {getContext} from "./context.js";
import {PublicKey} from "./publicKey"; import {PublicKey} from "./publicKey.js";
import {Signature} from "./signature"; import {Signature} from "./signature.js";
import {bytesToHex, hexToBytes} from "../helpers"; import {bytesToHex, hexToBytes} from "../helpers/index.js";
import {SecretKey as ISecretKey} from "../interface"; import {SecretKey as ISecretKey} from "../interface.js";
import {InvalidLengthError, ZeroSecretKeyError} from "../errors"; import {InvalidLengthError, ZeroSecretKeyError} from "../errors.js";
export class SecretKey implements ISecretKey { export class SecretKey implements ISecretKey {
readonly value: SecretKeyType; readonly value: SecretKeyType;

View File

@ -1,10 +1,10 @@
import {SignatureType, multiVerify} from "bls-eth-wasm"; import type {SignatureType} from "bls-eth-wasm";
import {getContext} from "./context"; import {getContext} from "./context.js";
import {PublicKey} from "./publicKey"; import {PublicKey} from "./publicKey.js";
import {bytesToHex, concatUint8Arrays, hexToBytes, isZeroUint8Array} from "../helpers"; import {bytesToHex, concatUint8Arrays, hexToBytes, isZeroUint8Array} from "../helpers/index.js";
import {PointFormat, Signature as ISignature, CoordType} from "../interface"; import {PointFormat, Signature as ISignature, CoordType} from "../interface.js";
import {EmptyAggregateError, InvalidLengthError, InvalidOrderError} from "../errors"; import {EmptyAggregateError, InvalidLengthError, InvalidOrderError} from "../errors.js";
import {SIGNATURE_LENGTH_COMPRESSED, SIGNATURE_LENGTH_UNCOMPRESSED} from "../constants"; import {SIGNATURE_LENGTH_COMPRESSED, SIGNATURE_LENGTH_UNCOMPRESSED} from "../constants.js";
export class Signature implements ISignature { export class Signature implements ISignature {
readonly value: SignatureType; readonly value: SignatureType;
@ -53,7 +53,8 @@ export class Signature implements ISignature {
} }
static verifyMultipleSignatures(sets: {publicKey: PublicKey; message: Uint8Array; signature: Signature}[]): boolean { static verifyMultipleSignatures(sets: {publicKey: PublicKey; message: Uint8Array; signature: Signature}[]): boolean {
return multiVerify( const context = getContext();
return context.multiVerify(
sets.map((s) => s.publicKey.value), sets.map((s) => s.publicKey.value),
sets.map((s) => s.signature.value), sets.map((s) => s.signature.value),
sets.map((s) => s.message) sets.map((s) => s.message)

View File

@ -1,4 +1,4 @@
import {bls} from "./index"; import {bls} from "./index.js";
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
(function (window: any) { (function (window: any) {

View File

@ -1,27 +1,28 @@
import {IBls} from "./interface"; import {IBls, Implementation} from "./interface.js";
import {bls as blsHerumi} from "./herumi";
export type Implementation = "herumi" | "blst-native"; export {IBls, Implementation, CoordType, PointFormat} from "./interface.js";
export * from "./interface";
// TODO: Use a Proxy for example to throw an error if it's not initialized yet // TODO: Use a Proxy for example to throw an error if it's not initialized yet
export const bls: IBls = {} as IBls; export const bls: IBls = {} as IBls;
export default bls; export default bls;
// Thanks https://github.com/iliakan/detect-node/blob/master/index.esm.js
const isNode = Object.prototype.toString.call(typeof process !== "undefined" ? process : 0) === "[object process]";
async function getImplementation(impl: Implementation = "herumi"): Promise<IBls> { async function getImplementation(impl: Implementation = "herumi"): Promise<IBls> {
switch (impl) { switch (impl) {
case "herumi": case "herumi": {
const blsHerumi = (await import("./herumi/index.js")).bls;
await blsHerumi.init(); await blsHerumi.init();
return blsHerumi; return blsHerumi;
}
case "blst-native": case "blst-native":
// Lazy import native bindings to prevent automatically importing binding.node files // Lazy import native bindings to prevent automatically importing binding.node files
if (typeof require !== "function") { if (!isNode) {
throw Error("blst-native is only supported in NodeJS"); throw Error("blst-native is only supported in NodeJS");
} }
// eslint-disable-next-line @typescript-eslint/no-require-imports return (await import("./blst-native/index.js")).bls;
return require("./blst").bls;
default: default:
throw new Error(`Unsupported implementation - ${impl}`); throw new Error(`Unsupported implementation - ${impl}`);
@ -34,14 +35,4 @@ export async function init(impl: Implementation): Promise<void> {
// and the imported object is still undefined after calling init() // and the imported object is still undefined after calling init()
const blsImpl = await getImplementation(impl); const blsImpl = await getImplementation(impl);
Object.assign(bls, blsImpl); Object.assign(bls, blsImpl);
Object.assign(exports, blsImpl);
} }
// Proxy named exports, will get set by `Object.assign(exports, blsImpl)`
export declare let sign: IBls["sign"];
export declare let aggregateSignatures: IBls["aggregateSignatures"];
export declare let aggregatePublicKeys: IBls["aggregatePublicKeys"];
export declare let verify: IBls["verify"];
export declare let verifyAggregate: IBls["verifyAggregate"];
export declare let verifyMultiple: IBls["verifyMultiple"];
export declare let secretKeyToPublicKey: IBls["secretKeyToPublicKey"];

View File

@ -1,8 +1,8 @@
export interface IBls { export interface IBls {
implementation: Implementation; implementation: Implementation;
SecretKey: Omit<typeof SecretKey, "prototype">; SecretKey: typeof SecretKey;
PublicKey: Omit<typeof PublicKey, "prototype">; PublicKey: typeof PublicKey;
Signature: Omit<typeof Signature, "prototype">; Signature: typeof Signature;
sign(secretKey: Uint8Array, message: Uint8Array): Uint8Array; sign(secretKey: Uint8Array, message: Uint8Array): Uint8Array;
aggregatePublicKeys(publicKeys: Uint8Array[]): Uint8Array; aggregatePublicKeys(publicKeys: Uint8Array[]): Uint8Array;
@ -18,6 +18,8 @@ export interface IBls {
} }
export declare class SecretKey { export declare class SecretKey {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private constructor(...value: any);
static fromBytes(bytes: Uint8Array): SecretKey; static fromBytes(bytes: Uint8Array): SecretKey;
static fromHex(hex: string): SecretKey; static fromHex(hex: string): SecretKey;
static fromKeygen(entropy?: Uint8Array): SecretKey; static fromKeygen(entropy?: Uint8Array): SecretKey;
@ -28,6 +30,8 @@ export declare class SecretKey {
} }
export declare class PublicKey { export declare class PublicKey {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private constructor(...value: any);
/** @param type Only for impl `blst-native`. Defaults to `CoordType.jacobian` */ /** @param type Only for impl `blst-native`. Defaults to `CoordType.jacobian` */
static fromBytes(bytes: Uint8Array, type?: CoordType, validate?: boolean): PublicKey; static fromBytes(bytes: Uint8Array, type?: CoordType, validate?: boolean): PublicKey;
static fromHex(hex: string): PublicKey; static fromHex(hex: string): PublicKey;
@ -38,6 +42,8 @@ export declare class PublicKey {
} }
export declare class Signature { export declare class Signature {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private constructor(...value: any);
/** @param type Only for impl `blst-native`. Defaults to `CoordType.affine` /** @param type Only for impl `blst-native`. Defaults to `CoordType.affine`
* @param validate When using `herumi` implementation, signature validation is always on regardless of this flag. */ * @param validate When using `herumi` implementation, signature validation is always on regardless of this flag. */
static fromBytes(bytes: Uint8Array, type?: CoordType, validate?: boolean): Signature; static fromBytes(bytes: Uint8Array, type?: CoordType, validate?: boolean): Signature;

1
src/types.ts Normal file
View File

@ -0,0 +1 @@
export type {PublicKey, SecretKey, Signature} from "./interface.js";

View File

@ -1,5 +1,5 @@
import {downloadTests} from "@chainsafe/lodestar-spec-test-util"; import {downloadTests} from "@chainsafe/lodestar-spec-test-util";
import {SPEC_TEST_VERSION, SPEC_TESTS_DIR, SPEC_TEST_TO_DOWNLOAD} from "./params"; import {SPEC_TEST_VERSION, SPEC_TESTS_DIR, SPEC_TEST_TO_DOWNLOAD} from "./params.js";
/* eslint-disable no-console */ /* eslint-disable no-console */

View File

@ -1,5 +1,8 @@
import path from "path"; import path from "path";
import {fileURLToPath} from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export const SPEC_TEST_VERSION = "v1.0.0"; export const SPEC_TEST_VERSION = "v1.0.0";
export const SPEC_TEST_TO_DOWNLOAD = ["general" as "general"]; export const SPEC_TEST_TO_DOWNLOAD = ["general" as const];
export const SPEC_TESTS_DIR = path.join(__dirname, "spec-tests"); export const SPEC_TESTS_DIR = path.join(__dirname, "spec-tests");

View File

@ -1,9 +1,9 @@
import path from "path"; import path from "path";
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
import {bytesToHex, hexToBytes} from "../../src/helpers"; import {bytesToHex, hexToBytes} from "../../src/helpers/index.js";
import {SPEC_TESTS_DIR} from "../params"; import {SPEC_TESTS_DIR} from "../params.js";
import {describeForAllImplementations} from "../switch"; import {describeForAllImplementations} from "../switch.js";
import {EmptyAggregateError} from "../../src/errors"; import {EmptyAggregateError} from "../../src/errors.js";
interface IAggregateSigsTestCase { interface IAggregateSigsTestCase {
data: { data: {

View File

@ -1,8 +1,8 @@
import path from "path"; import path from "path";
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
import {hexToBytes} from "../../src/helpers"; import {hexToBytes} from "../../src/helpers/index.js";
import {SPEC_TESTS_DIR} from "../params"; import {SPEC_TESTS_DIR} from "../params.js";
import {describeForAllImplementations} from "../switch"; import {describeForAllImplementations} from "../switch.js";
interface IAggregateSigsVerifyTestCase { interface IAggregateSigsVerifyTestCase {
data: { data: {

View File

@ -1,8 +1,8 @@
import path from "path"; import path from "path";
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
import {hexToBytes} from "../../src/helpers"; import {hexToBytes} from "../../src/helpers/index.js";
import {SPEC_TESTS_DIR} from "../params"; import {SPEC_TESTS_DIR} from "../params.js";
import {describeForAllImplementations} from "../switch"; import {describeForAllImplementations} from "../switch.js";
import {CoordType} from "@chainsafe/blst"; import {CoordType} from "@chainsafe/blst";
interface IAggregateSigsVerifyTestCase { interface IAggregateSigsVerifyTestCase {

View File

@ -1,9 +1,9 @@
import path from "path"; import path from "path";
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
import {bytesToHex, hexToBytes} from "../../src/helpers"; import {bytesToHex, hexToBytes} from "../../src/helpers/index.js";
import {SPEC_TESTS_DIR} from "../params"; import {SPEC_TESTS_DIR} from "../params.js";
import {describeForAllImplementations} from "../switch"; import {describeForAllImplementations} from "../switch.js";
import {ZeroSecretKeyError} from "../../src/errors"; import {ZeroSecretKeyError} from "../../src/errors.js";
interface ISignMessageTestCase { interface ISignMessageTestCase {
data: { data: {

View File

@ -1,8 +1,8 @@
import path from "path"; import path from "path";
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
import {hexToBytes} from "../../src/helpers"; import {hexToBytes} from "../../src/helpers/index.js";
import {SPEC_TESTS_DIR} from "../params"; import {SPEC_TESTS_DIR} from "../params.js";
import {describeForAllImplementations} from "../switch"; import {describeForAllImplementations} from "../switch.js";
interface IVerifyTestCase { interface IVerifyTestCase {
data: { data: {

View File

@ -1,6 +1,6 @@
import blst from "../src/blst"; import blst from "../src/blst-native/index.js";
import herumi from "../src/herumi"; import herumi from "../src/herumi/index.js";
import {IBls} from "../src/interface"; import {IBls} from "../src/interface.js";
export type Implementation = "blst" | "herumi"; export type Implementation = "blst" | "herumi";

View File

@ -1,4 +1,4 @@
import herumi from "../../src/herumi"; import herumi from "../../src/herumi/index.js";
import {runSecretKeyTests} from "../unit/secretKey.test"; import {runSecretKeyTests} from "../unit/secretKey.test";
import {runPublicKeyTests} from "../unit/publicKey.test"; import {runPublicKeyTests} from "../unit/publicKey.test";
import {runIndexTests} from "../unit/index.test"; import {runIndexTests} from "../unit/index.test";

View File

@ -1,6 +1,6 @@
import {expect} from "chai"; import {expect} from "chai";
import {concatUint8Arrays, isZeroUint8Array} from "../../../src/helpers/utils"; import {concatUint8Arrays, isZeroUint8Array} from "../../../src/helpers/utils.js";
import {hexToBytesNode} from "../../util"; import {hexToBytesNode} from "../../util.js";
describe("helpers / bytes", () => { describe("helpers / bytes", () => {
describe("isZeroUint8Array", () => { describe("isZeroUint8Array", () => {

View File

@ -1,6 +1,6 @@
import {expect} from "chai"; import {expect} from "chai";
import {hexToBytes, bytesToHex} from "../../../src/helpers/hex"; import {hexToBytes, bytesToHex} from "../../../src/helpers/hex.js";
import {hexToBytesNode} from "../../util"; import {hexToBytesNode} from "../../util.js";
describe("helpers / hex", () => { describe("helpers / hex", () => {
const testCases: {id: string; hex: string}[] = [ const testCases: {id: string; hex: string}[] = [

View File

@ -1,7 +1,8 @@
import {expect} from "chai"; import {expect} from "chai";
import {SecretKey, PublicKey, Signature, init, bls} from "../../src"; import {init, bls} from "../../src/index.js";
import type {SecretKey, PublicKey, Signature} from "../../src/types.js";
describe("index named exports", () => { describe("types named exports", () => {
it("Classes and methods should be defined", async () => { it("Classes and methods should be defined", async () => {
await init("herumi"); await init("herumi");
@ -12,7 +13,7 @@ describe("index named exports", () => {
return sig.verify(pk, msg); return sig.verify(pk, msg);
} }
const sk = SecretKey.fromKeygen(); const sk = bls.SecretKey.fromKeygen();
const msg = new Uint8Array(32); const msg = new Uint8Array(32);
const sig = sk.sign(msg); const sig = sk.sign(msg);
const pk = sk.toPublicKey(); const pk = sk.toPublicKey();

View File

@ -1,8 +1,8 @@
import {expect} from "chai"; import {expect} from "chai";
import {IBls, PointFormat} from "../../src/interface"; import {IBls, PointFormat} from "../../src/interface.js";
import {getN, randomMessage, hexToBytesNode} from "../util"; import {getN, randomMessage, hexToBytesNode} from "../util.js";
import {hexToBytes} from "../../src/helpers"; import {hexToBytes} from "../../src/helpers/index.js";
import {maliciousVerifyMultipleSignaturesData} from "../data/malicious-signature-test-data"; import {maliciousVerifyMultipleSignaturesData} from "../data/malicious-signature-test-data.js";
export function runIndexTests(bls: IBls): void { export function runIndexTests(bls: IBls): void {
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type // eslint-disable-next-line @typescript-eslint/explicit-function-return-type

View File

@ -1,5 +1,5 @@
import {expect} from "chai"; import {expect} from "chai";
import {chunkify} from "./utils"; import {chunkify} from "./utils.js";
describe("chunkify", () => { describe("chunkify", () => {
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15]; const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15];

View File

@ -1,6 +1,7 @@
import {spawn, Pool, Worker, Thread} from "threads"; import {spawn, Pool, Worker, Thread} from "threads";
import {Implementation, PointFormat, PublicKey, Signature} from "../../../../src"; import {Implementation, PointFormat} from "../../../../src/index.js";
import {WorkerApi} from "./worker"; import {PublicKey, Signature} from "../../../../src/types.js";
import {WorkerApi} from "./worker.js";
type ThreadType = { type ThreadType = {
[K in keyof WorkerApi]: (...args: Parameters<WorkerApi[K]>) => Promise<ReturnType<WorkerApi[K]>>; [K in keyof WorkerApi]: (...args: Parameters<WorkerApi[K]>) => Promise<ReturnType<WorkerApi[K]>>;

View File

@ -1,6 +1,7 @@
import {expect} from "chai"; import {expect} from "chai";
import {IBls, PublicKey, Signature} from "../../../../src"; import {IBls} from "../../../../src/index.js";
import {BlsMultiThreadNaive} from "./index"; import type {PublicKey, Signature} from "../../../../src/types.js";
import {BlsMultiThreadNaive} from "./index.js";
export function runMultithreadTests(bls: IBls): void { export function runMultithreadTests(bls: IBls): void {
describe("bls pool naive", function () { describe("bls pool naive", function () {

View File

@ -1,5 +1,5 @@
import {expose} from "threads/worker"; import {expose} from "threads/worker";
import {bls, init, CoordType, Implementation} from "../../../../src"; import {bls, init, CoordType, Implementation} from "../../../../src/index.js";
export type WorkerApi = typeof workerApi; export type WorkerApi = typeof workerApi;

View File

@ -1,5 +1,5 @@
import {expect} from "chai"; import {expect} from "chai";
import {IBls} from "../../src/interface"; import {IBls} from "../../src/interface.js";
export function runPublicKeyTests(bls: IBls): void { export function runPublicKeyTests(bls: IBls): void {
describe("PublicKey", () => { describe("PublicKey", () => {

View File

@ -2,7 +2,7 @@ import {runSecretKeyTests} from "./secretKey.test";
import {runPublicKeyTests} from "./publicKey.test"; import {runPublicKeyTests} from "./publicKey.test";
import {runIndexTests} from "./index.test"; import {runIndexTests} from "./index.test";
import {runMultithreadTests} from "./multithread/naive/naive.test"; import {runMultithreadTests} from "./multithread/naive/naive.test";
import {describeForAllImplementations} from "../switch"; import {describeForAllImplementations} from "../switch.js";
// Import test's bls lib lazily to prevent breaking test with Karma // Import test's bls lib lazily to prevent breaking test with Karma
describeForAllImplementations((bls) => { describeForAllImplementations((bls) => {

View File

@ -1,5 +1,5 @@
import {expect} from "chai"; import {expect} from "chai";
import {IBls} from "../../src/interface"; import {IBls} from "../../src/interface.js";
export function runSecretKeyTests(bls: IBls): void { export function runSecretKeyTests(bls: IBls): void {
describe("SecretKey", () => { describe("SecretKey", () => {

View File

@ -1,4 +1,4 @@
import {randomBytes} from "../src/helpers"; import {randomBytes} from "../src/helpers/index.js";
export function randomMessage(): Uint8Array { export function randomMessage(): Uint8Array {
return randomBytes(32); return randomBytes(32);

View File

@ -3,7 +3,8 @@
"compilerOptions": { "compilerOptions": {
"outDir": "lib", "outDir": "lib",
"target": "es2019", "target": "es2019",
"module": "commonjs", "module": "ES2020",
"moduleResolution": "Node",
"pretty": true, "pretty": true,
"lib": ["esnext.bigint", "DOM"], "lib": ["esnext.bigint", "DOM"],
"typeRoots": ["./node_modules/@types"], "typeRoots": ["./node_modules/@types"],

View File

@ -1,3 +1,5 @@
const ResolveTypeScriptPlugin = require("resolve-typescript-plugin");
module.exports = { module.exports = {
entry: "./src/index.ts", entry: "./src/index.ts",
mode: "production", mode: "production",
@ -9,9 +11,10 @@ module.exports = {
}, },
resolve: { resolve: {
extensions: [".ts", ".js"], extensions: [".ts", ".js"],
plugins: [new ResolveTypeScriptPlugin()]
}, },
module: { module: {
rules: [{test: /\.ts$/, use: {loader: "ts-loader", options: {transpileOnly: true}}}], rules: [{test: /\.(ts|js)$/, use: {loader: "ts-loader", options: {transpileOnly: true}}}],
}, },
optimization: { optimization: {
// Disable minification for better debugging on Karma tests // Disable minification for better debugging on Karma tests

1315
yarn.lock

File diff suppressed because it is too large Load Diff