commit
a112b21347
|
@ -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": [
|
||||||
{
|
{
|
|
@ -9,7 +9,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
node: [12, 14]
|
node: [14, 16]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-node@v1
|
- uses: actions/setup-node@v1
|
||||||
|
|
|
@ -1,2 +1,6 @@
|
||||||
|
extension: ["ts"]
|
||||||
colors: true
|
colors: true
|
||||||
require: ts-node/register
|
node-option:
|
||||||
|
- "experimental-specifier-resolution=node"
|
||||||
|
- "loader=ts-node/esm"
|
||||||
|
|
||||||
|
|
46
README.md
46
README.md
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
[![codecov](https://codecov.io/gh/ChainSafe/lodestar/branch/master/graph/badge.svg)](https://codecov.io/gh/ChainSafe/lodestar)
|
[![codecov](https://codecov.io/gh/ChainSafe/lodestar/branch/master/graph/badge.svg)](https://codecov.io/gh/ChainSafe/lodestar)
|
||||||
![ETH2.0_Spec_Version 1.0.0](https://img.shields.io/badge/ETH2.0_Spec_Version-1.0.0-2e86c1.svg)
|
![ETH2.0_Spec_Version 1.0.0](https://img.shields.io/badge/ETH2.0_Spec_Version-1.0.0-2e86c1.svg)
|
||||||
![ES Version](https://img.shields.io/badge/ES-2017-yellow)
|
![ES Version](https://img.shields.io/badge/ES-2022-yellow)
|
||||||
![Node Version](https://img.shields.io/badge/node-12.x-green)
|
![Node Version](https://img.shields.io/badge/node-14.8-green)
|
||||||
|
|
||||||
Javascript library for BLS (Boneh-Lynn-Shacham) signatures and signature aggregation, tailored for use in Eth2.
|
Javascript library for BLS (Boneh-Lynn-Shacham) signatures and signature aggregation, tailored for use in Eth2.
|
||||||
|
|
||||||
|
@ -19,10 +19,10 @@ To use native bindings you must install peer dependency `@chainsafe/blst`
|
||||||
yarn add @chainsafe/bls @chainsafe/blst
|
yarn add @chainsafe/bls @chainsafe/blst
|
||||||
```
|
```
|
||||||
|
|
||||||
You must initialize the library once in your application before using it. The result is cached and use across all your imports
|
By default, native bindings will be used if in NodeJS and they are installed. A WASM implementation ("herumi") is used as a fallback in case any error occurs.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import {init, SecretKey, secretKeyToPublicKey, sign, verify} from "@chainsafe/bls";
|
import {SecretKey, secretKeyToPublicKey, sign, verify} from "@chainsafe/bls";
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
await init("herumi");
|
await init("herumi");
|
||||||
|
@ -45,48 +45,52 @@ 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 explicitly import 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 explicitly import the native bindings. 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
|
### Get implementation at runtime
|
||||||
|
|
||||||
If you want to offer a fallback in NodeJS, first try to load native bindings and then fallback to WASM. Also install peer dependency `@chainsafe/blst` which has the native bindings
|
If you need to get a bls implementation at runtime, import from `/getImplementation`.
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn add @chainsafe/bls @chainsafe/blst
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import {init} from "@chainsafe/bls";
|
import {getImplementation} from "@chainsafe/bls/getImplementation";
|
||||||
|
|
||||||
try {
|
const bls = await getImplementation("herumi");
|
||||||
await init("blst-native");
|
```
|
||||||
} catch (e) {
|
|
||||||
|
### Switchable singleton
|
||||||
|
|
||||||
|
If you need a singleton that is switchable at runtime (the default behavior in <=v6), import from `/switchable`.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import bls, {init} from "@chainsafe/bls/switchable";
|
||||||
|
|
||||||
|
// here `bls` is uninitialized
|
||||||
await init("herumi");
|
await init("herumi");
|
||||||
console.warn("Using WASM");
|
// here `bls` is initialized
|
||||||
}
|
// now other modules can `import bls from "@chainsafe/bls/switchable"` and it will be initialized
|
||||||
```
|
```
|
||||||
|
|
||||||
The API is identical for all implementations.
|
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)
|
||||||
|
|
||||||
|
|
|
@ -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/types.js";
|
||||||
import {aggCount} from "./params";
|
import {aggCount} from "./params.js";
|
||||||
|
|
||||||
(async function () {
|
(async function () {
|
||||||
await runForAllImplementations(async (bls, implementation) => {
|
await runForAllImplementations(async (bls, implementation) => {
|
||||||
|
|
|
@ -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 () {
|
||||||
{
|
{
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 +0,0 @@
|
||||||
export * from "./lib/blst";
|
|
|
@ -1 +0,0 @@
|
||||||
module.exports = require("./lib/blst");
|
|
|
@ -1 +0,0 @@
|
||||||
export * from "./lib/herumi";
|
|
|
@ -1 +0,0 @@
|
||||||
export * from "./lib/herumi";
|
|
|
@ -1 +0,0 @@
|
||||||
export * from "./lib/herumi";
|
|
|
@ -1,20 +1,29 @@
|
||||||
// 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({
|
||||||
basePath: "",
|
basePath: "",
|
||||||
frameworks: ["mocha", "chai"],
|
frameworks: [
|
||||||
files: ["test/unit-web/run-web-implementation.test.ts", "test/unit/index-named-exports.test.ts"],
|
"webpack",
|
||||||
|
"mocha",
|
||||||
|
"chai",
|
||||||
|
],
|
||||||
|
files: [
|
||||||
|
"test/unit-web/run-web-implementation.test.ts",
|
||||||
|
"test/unit/index-named-exports.test.ts",
|
||||||
|
],
|
||||||
exclude: [],
|
exclude: [],
|
||||||
preprocessors: {
|
preprocessors: {
|
||||||
"test/**/*.ts": ["webpack"],
|
"test/**/*.ts": ["webpack"],
|
||||||
},
|
},
|
||||||
webpack: {
|
webpack: {
|
||||||
mode: "production",
|
mode: "production",
|
||||||
node: webpackConfig.node,
|
|
||||||
module: webpackConfig.module,
|
module: webpackConfig.module,
|
||||||
resolve: webpackConfig.resolve,
|
resolve: webpackConfig.resolve,
|
||||||
|
experiments: webpackConfig.experiments,
|
||||||
|
optimization: webpackConfig.optimization,
|
||||||
|
stats: {warnings:false},
|
||||||
},
|
},
|
||||||
reporters: ["spec"],
|
reporters: ["spec"],
|
||||||
|
|
78
package.json
78
package.json
|
@ -2,10 +2,42 @@
|
||||||
"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",
|
"engines": {
|
||||||
|
"node": ">=14.8.0"
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./lib/index.js"
|
||||||
|
},
|
||||||
|
"./types": {
|
||||||
|
"import": "./lib/types.js"
|
||||||
|
},
|
||||||
|
"./getImplementation": {
|
||||||
|
"import": "./lib/getImplementation.js"
|
||||||
|
},
|
||||||
|
"./switchable": {
|
||||||
|
"import": "./lib/switchable.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",
|
||||||
"module": "./browser",
|
"typesVersions": {
|
||||||
"browser": "./browser",
|
"*": {
|
||||||
|
"*": [
|
||||||
|
"*",
|
||||||
|
"lib/*",
|
||||||
|
"lib/*/index"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"module": "./lib/index.js",
|
||||||
|
"browser": "./lib/herumi.js",
|
||||||
"homepage": "https://github.com/chainsafe/bls",
|
"homepage": "https://github.com/chainsafe/bls",
|
||||||
"author": "ChainSafe Systems",
|
"author": "ChainSafe Systems",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
@ -24,18 +56,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,35 +78,38 @@
|
||||||
},
|
},
|
||||||
"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",
|
||||||
|
"@chainsafe/threads": "^1.9.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",
|
"buffer": "^6.0.3",
|
||||||
"eslint": "^6.8.0",
|
"chai": "^4.3.6",
|
||||||
|
"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": "^6.3.16",
|
"karma": "^6.3.18",
|
||||||
"karma-chai": "^0.1.0",
|
"karma-chai": "^0.1.0",
|
||||||
"karma-chrome-launcher": "^3.1.0",
|
"karma-chrome-launcher": "^3.1.0",
|
||||||
"karma-cli": "^2.0.0",
|
"karma-cli": "^2.0.0",
|
||||||
"karma-mocha": "^1.3.0",
|
"karma-mocha": "^2.0.1",
|
||||||
"karma-spec-reporter": "^0.0.32",
|
"karma-spec-reporter": "^0.0.32",
|
||||||
"karma-webpack": "^4.0.2",
|
"karma-webpack": "^5.0.0",
|
||||||
"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.2.0",
|
||||||
"ts-loader": "^6.2.1",
|
"ts-loader": "^9.2.8",
|
||||||
"ts-node": "^8.6.2",
|
"ts-node": "^10.7.0",
|
||||||
"typescript": "^3.7.5",
|
"typescript": "^4.6.3",
|
||||||
"webpack": "^4.30.0",
|
"webpack": "^5.72.0",
|
||||||
"webpack-cli": "^3.3.2"
|
"webpack-cli": "^4.9.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": {
|
||||||
|
|
14
register.js
14
register.js
|
@ -1,14 +0,0 @@
|
||||||
const {init} = require("./lib");
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// To be used in NodeJS testing environments
|
|
||||||
// node -r @chainsafe/bls/register
|
|
||||||
// -----------------------------------------
|
|
||||||
|
|
||||||
// blst-native initialization is syncronous
|
|
||||||
// Initialize bls here instead of in before() so it's available inside describe() blocks
|
|
||||||
init("blst-native").catch((e) => {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(e);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import {SecretKey} from "./secretKey.js";
|
||||||
|
import {PublicKey} from "./publicKey.js";
|
||||||
|
import {Signature} from "./signature.js";
|
||||||
|
import {IBls} from "../types.js";
|
||||||
|
import {functionalInterfaceFactory} from "../functional.js";
|
||||||
|
export * from "../constants.js";
|
||||||
|
|
||||||
|
export {SecretKey, PublicKey, Signature};
|
||||||
|
|
||||||
|
export const bls: IBls = {
|
||||||
|
implementation: "blst-native",
|
||||||
|
SecretKey,
|
||||||
|
PublicKey,
|
||||||
|
Signature,
|
||||||
|
|
||||||
|
...functionalInterfaceFactory({SecretKey, PublicKey, Signature}),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default bls;
|
|
@ -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 "../types.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]) {
|
|
@ -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 "../types.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;
|
|
@ -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 "../types.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]) {
|
|
@ -1,28 +0,0 @@
|
||||||
import {SecretKey} from "./secretKey";
|
|
||||||
import {PublicKey} from "./publicKey";
|
|
||||||
import {Signature} from "./signature";
|
|
||||||
import {IBls} from "../interface";
|
|
||||||
import {functionalInterfaceFactory} from "../functional";
|
|
||||||
export * from "../constants";
|
|
||||||
|
|
||||||
export {SecretKey, PublicKey, Signature};
|
|
||||||
|
|
||||||
export async function init(): Promise<void> {
|
|
||||||
// Native bindings require no init() call
|
|
||||||
}
|
|
||||||
export function destroy(): void {
|
|
||||||
// Native bindings require no destroy() call
|
|
||||||
}
|
|
||||||
|
|
||||||
export const bls: IBls = {
|
|
||||||
implementation: "blst-native",
|
|
||||||
SecretKey,
|
|
||||||
PublicKey,
|
|
||||||
Signature,
|
|
||||||
|
|
||||||
...functionalInterfaceFactory({SecretKey, PublicKey, Signature}),
|
|
||||||
init,
|
|
||||||
destroy,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default bls;
|
|
|
@ -1,9 +1,10 @@
|
||||||
import {IBls} from "./interface";
|
import {IBls} from "./types.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,
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import type {IBls, Implementation} from "./types.js";
|
||||||
|
|
||||||
|
// 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]";
|
||||||
|
|
||||||
|
export async function getImplementation(impl: Implementation = "herumi"): Promise<IBls> {
|
||||||
|
switch (impl) {
|
||||||
|
case "herumi": {
|
||||||
|
return (await import("./herumi/index.js")).bls;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "blst-native":
|
||||||
|
// Lazy import native bindings to prevent automatically importing binding.node files
|
||||||
|
if (!isNode) {
|
||||||
|
throw Error("blst-native is only supported in NodeJS");
|
||||||
|
}
|
||||||
|
return (await import("./blst-native/index.js")).bls;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported implementation - ${impl}`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,2 +1,2 @@
|
||||||
export * from "./hex";
|
export * from "./hex.js";
|
||||||
export * from "./utils";
|
export * from "./utils.js";
|
||||||
|
|
|
@ -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"];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
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 "../types.js";
|
||||||
import {functionalInterfaceFactory} from "../functional";
|
import {functionalInterfaceFactory} from "../functional.js";
|
||||||
export * from "../constants";
|
|
||||||
|
await init();
|
||||||
|
|
||||||
|
export * from "../constants.js";
|
||||||
|
|
||||||
export {SecretKey, PublicKey, Signature, init, destroy};
|
export {SecretKey, PublicKey, Signature, init, destroy};
|
||||||
|
|
||||||
|
@ -15,8 +18,6 @@ export const bls: IBls = {
|
||||||
Signature,
|
Signature,
|
||||||
|
|
||||||
...functionalInterfaceFactory({SecretKey, PublicKey, Signature}),
|
...functionalInterfaceFactory({SecretKey, PublicKey, Signature}),
|
||||||
init,
|
|
||||||
destroy,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default bls;
|
export default bls;
|
||||||
|
|
|
@ -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 "../types.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;
|
||||||
|
|
|
@ -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 "../types.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;
|
||||||
|
@ -35,7 +35,7 @@ export class SecretKey implements ISecretKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromKeygen(entropy?: Uint8Array): SecretKey {
|
static fromKeygen(entropy?: Uint8Array): SecretKey {
|
||||||
const sk = generateRandomSecretKey(entropy && Buffer.from(entropy));
|
const sk = generateRandomSecretKey(entropy);
|
||||||
return this.fromBytes(sk);
|
return this.fromBytes(sk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 "../types.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)
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
53
src/index.ts
53
src/index.ts
|
@ -1,47 +1,14 @@
|
||||||
import {IBls} from "./interface";
|
import type {IBls} from "./types.js";
|
||||||
import {bls as blsHerumi} from "./herumi";
|
import {getImplementation} from "./getImplementation.js";
|
||||||
|
|
||||||
export type Implementation = "herumi" | "blst-native";
|
// 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]";
|
||||||
|
|
||||||
export * from "./interface";
|
let bls: IBls;
|
||||||
|
try {
|
||||||
|
bls = await getImplementation(isNode ? "blst-native" : "herumi");
|
||||||
|
} catch (e) {
|
||||||
|
bls = await getImplementation("herumi");
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Use a Proxy for example to throw an error if it's not initialized yet
|
|
||||||
export const bls: IBls = {} as IBls;
|
|
||||||
export default bls;
|
export default bls;
|
||||||
|
|
||||||
async function getImplementation(impl: Implementation = "herumi"): Promise<IBls> {
|
|
||||||
switch (impl) {
|
|
||||||
case "herumi":
|
|
||||||
await blsHerumi.init();
|
|
||||||
return blsHerumi;
|
|
||||||
|
|
||||||
case "blst-native":
|
|
||||||
// Lazy import native bindings to prevent automatically importing binding.node files
|
|
||||||
if (typeof require !== "function") {
|
|
||||||
throw Error("blst-native is only supported in NodeJS");
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
||||||
return require("./blst").bls;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Error(`Unsupported implementation - ${impl}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function init(impl: Implementation): Promise<void> {
|
|
||||||
// Using Object.assign instead of just bls = getImplementation()
|
|
||||||
// because otherwise the default import breaks. The reference is lost
|
|
||||||
// and the imported object is still undefined after calling init()
|
|
||||||
const blsImpl = await getImplementation(impl);
|
|
||||||
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"];
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import type {IBls, Implementation} from "./types.js";
|
||||||
|
import {getImplementation} from "./getImplementation.js";
|
||||||
|
|
||||||
|
// TODO: Use a Proxy for example to throw an error if it's not initialized yet
|
||||||
|
const bls: IBls = {} as IBls;
|
||||||
|
export default bls;
|
||||||
|
|
||||||
|
export async function init(impl: Implementation): Promise<void> {
|
||||||
|
// Using Object.assign instead of just bls = getImplementation()
|
||||||
|
// because otherwise the default import breaks. The reference is lost
|
||||||
|
// and the imported object is still undefined after calling init()
|
||||||
|
const blsImpl = await getImplementation(impl);
|
||||||
|
Object.assign(bls, blsImpl);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
@ -12,12 +12,11 @@ export interface IBls {
|
||||||
verifyMultiple(publicKeys: Uint8Array[], messages: Uint8Array[], signature: Uint8Array): boolean;
|
verifyMultiple(publicKeys: Uint8Array[], messages: Uint8Array[], signature: Uint8Array): boolean;
|
||||||
verifyMultipleSignatures(sets: {publicKey: Uint8Array; message: Uint8Array; signature: Uint8Array}[]): boolean;
|
verifyMultipleSignatures(sets: {publicKey: Uint8Array; message: Uint8Array; signature: Uint8Array}[]): boolean;
|
||||||
secretKeyToPublicKey(secretKey: Uint8Array): Uint8Array;
|
secretKeyToPublicKey(secretKey: Uint8Array): Uint8Array;
|
||||||
|
|
||||||
init(): Promise<void>;
|
|
||||||
destroy(): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 +27,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 +39,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,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 */
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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/types.js";
|
||||||
|
|
||||||
export type Implementation = "blst" | "herumi";
|
export type Implementation = "blst" | "herumi";
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ export async function runForAllImplementations(
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
for (const implementation of ["blst", "herumi"] as Implementation[]) {
|
for (const implementation of ["blst", "herumi"] as Implementation[]) {
|
||||||
const bls = getBls(implementation);
|
const bls = getBls(implementation);
|
||||||
await bls.init();
|
|
||||||
callback(bls, implementation);
|
callback(bls, implementation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,10 +26,6 @@ export async function runForAllImplementations(
|
||||||
export function describeForAllImplementations(callback: (bls: IBls) => void): void {
|
export function describeForAllImplementations(callback: (bls: IBls) => void): void {
|
||||||
runForAllImplementations((bls, implementation) => {
|
runForAllImplementations((bls, implementation) => {
|
||||||
describe(implementation, function () {
|
describe(implementation, function () {
|
||||||
before(async () => {
|
|
||||||
await bls.init();
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
callback(bls);
|
callback(bls);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -1,18 +1,12 @@
|
||||||
import herumi from "../../src/herumi";
|
import {runSecretKeyTests} from "../unit/secretKey.test.js";
|
||||||
import {runSecretKeyTests} from "../unit/secretKey.test";
|
import {runPublicKeyTests} from "../unit/publicKey.test.js";
|
||||||
import {runPublicKeyTests} from "../unit/publicKey.test";
|
import {runIndexTests} from "../unit/index.test.js";
|
||||||
import {runIndexTests} from "../unit/index.test";
|
|
||||||
|
|
||||||
// This file is intended to be compiled and run by Karma
|
// This file is intended to be compiled and run by Karma
|
||||||
// Do not import the node.bindings or it will break with:
|
// Do not import the node.bindings or it will break with:
|
||||||
// Error: BLST bindings loader should only run in a NodeJS context: process.platform
|
// Error: BLST bindings loader should only run in a NodeJS context: process.platform
|
||||||
describe("herumi", () => {
|
describe("herumi", async () => {
|
||||||
before(async () => {
|
const herumi = (await import("../../src/herumi/index.js")).default;
|
||||||
// For consistency with describeForAllImplementations
|
|
||||||
// eslint-disable-next-line import/no-named-as-default-member
|
|
||||||
await herumi.init();
|
|
||||||
});
|
|
||||||
|
|
||||||
runSecretKeyTests(herumi);
|
runSecretKeyTests(herumi);
|
||||||
runPublicKeyTests(herumi);
|
runPublicKeyTests(herumi);
|
||||||
runIndexTests(herumi);
|
runIndexTests(herumi);
|
||||||
|
|
|
@ -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", () => {
|
||||||
|
|
|
@ -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}[] = [
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
import {expect} from "chai";
|
import {expect} from "chai";
|
||||||
import {SecretKey, PublicKey, Signature, init, bls} from "../../src";
|
import type {SecretKey, PublicKey, Signature, IBls} from "../../src/types.js";
|
||||||
|
|
||||||
|
describe("types named exports", async () => {
|
||||||
|
let bls: IBls;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
bls = (await import("../../src/index.js")).default;
|
||||||
|
});
|
||||||
|
|
||||||
describe("index named exports", () => {
|
|
||||||
it("Classes and methods should be defined", async () => {
|
it("Classes and methods should be defined", async () => {
|
||||||
await init("herumi");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sample helper to test argument typing
|
* Sample helper to test argument typing
|
||||||
*/
|
*/
|
||||||
|
@ -12,7 +16,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();
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import {expect} from "chai";
|
import {expect} from "chai";
|
||||||
import {IBls, PointFormat} from "../../src/interface";
|
import {Buffer} from "buffer";
|
||||||
import {getN, randomMessage, hexToBytesNode} from "../util";
|
import {IBls, PointFormat} from "../../src/types.js";
|
||||||
import {hexToBytes} from "../../src/helpers";
|
import {getN, randomMessage} from "../util.js";
|
||||||
import {maliciousVerifyMultipleSignaturesData} from "../data/malicious-signature-test-data";
|
import {hexToBytes} from "../../src/helpers/index.js";
|
||||||
|
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
|
||||||
|
@ -178,13 +179,13 @@ export function runIndexTests(bls: IBls): void {
|
||||||
"0x0a1a1c26055a329817a5759d877a2795f9499b97d6056edde0eea39512f24e8bc874b4471f0501127abb1ea0d9f68ac111392125a1c3750363c2c97d9650fb78696e6428db8ff9efaf0471cbfd20324916ab545746db83756d335e92f9e8c8b8";
|
"0x0a1a1c26055a329817a5759d877a2795f9499b97d6056edde0eea39512f24e8bc874b4471f0501127abb1ea0d9f68ac111392125a1c3750363c2c97d9650fb78696e6428db8ff9efaf0471cbfd20324916ab545746db83756d335e92f9e8c8b8";
|
||||||
|
|
||||||
it("Should serialize comp pubkey", () => {
|
it("Should serialize comp pubkey", () => {
|
||||||
const sk = bls.SecretKey.fromBytes(hexToBytesNode(skHex));
|
const sk = bls.SecretKey.fromBytes(hexToBytes(skHex));
|
||||||
const pkHexComp = sk.toPublicKey().toHex(PointFormat.compressed);
|
const pkHexComp = sk.toPublicKey().toHex(PointFormat.compressed);
|
||||||
expect(pkHexComp).to.equal(pkHexCompExpected, "Wrong pkHexComp");
|
expect(pkHexComp).to.equal(pkHexCompExpected, "Wrong pkHexComp");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should serialize uncomp pubkey", () => {
|
it("Should serialize uncomp pubkey", () => {
|
||||||
const sk = bls.SecretKey.fromBytes(hexToBytesNode(skHex));
|
const sk = bls.SecretKey.fromBytes(hexToBytes(skHex));
|
||||||
const pkHexUncomp = sk.toPublicKey().toHex(PointFormat.uncompressed);
|
const pkHexUncomp = sk.toPublicKey().toHex(PointFormat.uncompressed);
|
||||||
expect(pkHexUncomp).to.equal(pkHexUncompExpected, "Wrong pkHexUncomp");
|
expect(pkHexUncomp).to.equal(pkHexUncompExpected, "Wrong pkHexUncomp");
|
||||||
});
|
});
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
import {spawn, Pool, Worker, Thread} from "threads";
|
import {spawn, Pool, Worker, Thread} from "@chainsafe/threads";
|
||||||
import {Implementation, PointFormat, PublicKey, Signature} from "../../../../src";
|
import {Implementation, PointFormat, PublicKey, Signature} from "../../../../src/types.js";
|
||||||
import {WorkerApi} from "./worker";
|
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]>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
import path from "path";
|
||||||
|
import {fileURLToPath} from "url";
|
||||||
|
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
export class BlsMultiThreadNaive {
|
export class BlsMultiThreadNaive {
|
||||||
impl: Implementation;
|
impl: Implementation;
|
||||||
pool: Pool<Thread & ThreadType>;
|
pool: Pool<Thread & ThreadType>;
|
||||||
|
@ -17,7 +22,18 @@ export class BlsMultiThreadNaive {
|
||||||
// THe worker is not able to deserialize from uncompressed
|
// THe worker is not able to deserialize from uncompressed
|
||||||
// `Error: err _wrapDeserialize`
|
// `Error: err _wrapDeserialize`
|
||||||
this.format = impl === "blst-native" ? PointFormat.uncompressed : PointFormat.compressed;
|
this.format = impl === "blst-native" ? PointFormat.uncompressed : PointFormat.compressed;
|
||||||
this.pool = Pool(() => (spawn(new Worker("./worker")) as any) as Promise<Thread & ThreadType>, workerCount);
|
this.pool = Pool(
|
||||||
|
() =>
|
||||||
|
(spawn(
|
||||||
|
// There is still an annoyance dealing with ESM imports here:
|
||||||
|
// threads.js attempts to require.resolve any files passed to Worker, and
|
||||||
|
// the esm module resolver requires the .js extension, even though the .js file does not actually exist.
|
||||||
|
// The solution for now:
|
||||||
|
// Pass in the script path as an absolute path and suppress threads.js default behavior when importing
|
||||||
|
new Worker(path.join(__dirname, "./worker.js"), {suppressResolveScript: true, suppressTranspileTS: true})
|
||||||
|
) as any) as Promise<Thread & ThreadType>,
|
||||||
|
workerCount
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async destroy(): Promise<void> {
|
async destroy(): Promise<void> {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {expect} from "chai";
|
import {expect} from "chai";
|
||||||
import {IBls, PublicKey, Signature} from "../../../../src";
|
import {IBls} from "../../../../src/types.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 () {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {expose} from "threads/worker";
|
import {expose} from "@chainsafe/threads/worker";
|
||||||
import {bls, init, CoordType, Implementation} from "../../../../src";
|
import {CoordType, Implementation} from "../../../../src/types.js";
|
||||||
|
import bls, {init} from "../../../../src/switchable.js";
|
||||||
|
|
||||||
export type WorkerApi = typeof workerApi;
|
export type WorkerApi = typeof workerApi;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {expect} from "chai";
|
import {expect} from "chai";
|
||||||
import {IBls} from "../../src/interface";
|
import {IBls} from "../../src/types.js";
|
||||||
|
|
||||||
export function runPublicKeyTests(bls: IBls): void {
|
export function runPublicKeyTests(bls: IBls): void {
|
||||||
describe("PublicKey", () => {
|
describe("PublicKey", () => {
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {expect} from "chai";
|
import {expect} from "chai";
|
||||||
import {IBls} from "../../src/interface";
|
import {IBls} from "../../src/types.js";
|
||||||
|
|
||||||
export function runSecretKeyTests(bls: IBls): void {
|
export function runSecretKeyTests(bls: IBls): void {
|
||||||
describe("SecretKey", () => {
|
describe("SecretKey", () => {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "lib",
|
"outDir": "lib",
|
||||||
"target": "es2019",
|
"target": "es2019",
|
||||||
"module": "commonjs",
|
"module": "esnext",
|
||||||
|
"moduleResolution": "Node",
|
||||||
"pretty": true,
|
"pretty": true,
|
||||||
"lib": ["esnext.bigint", "DOM"],
|
"lib": ["esnext.bigint", "DOM"],
|
||||||
"typeRoots": ["./node_modules/@types"],
|
"typeRoots": ["./node_modules/@types"],
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
const ResolveTypeScriptPlugin = require("resolve-typescript-plugin");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: "./src/index.ts",
|
||||||
|
mode: "production",
|
||||||
|
output: {
|
||||||
|
filename: "dist/bundle.js",
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [{test: /\.(ts)$/, use: {loader: "ts-loader", options: {transpileOnly: true}}}],
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
// Disable minification for better debugging on Karma tests
|
||||||
|
minimize: false,
|
||||||
|
//splitChunks: false, runtimeChunk: false,
|
||||||
|
},
|
||||||
|
devtool: "source-map",
|
||||||
|
resolve: {
|
||||||
|
plugins: [new ResolveTypeScriptPlugin()],
|
||||||
|
fallback: {
|
||||||
|
crypto: false,
|
||||||
|
fs: false,
|
||||||
|
path: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
experiments: {
|
||||||
|
topLevelAwait: true,
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,21 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
entry: "./src/index.ts",
|
|
||||||
mode: "production",
|
|
||||||
node: {
|
|
||||||
fs: "empty",
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
filename: "dist/bundle.js",
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
extensions: [".ts", ".js"],
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [{test: /\.ts$/, use: {loader: "ts-loader", options: {transpileOnly: true}}}],
|
|
||||||
},
|
|
||||||
optimization: {
|
|
||||||
// Disable minification for better debugging on Karma tests
|
|
||||||
minimize: false,
|
|
||||||
},
|
|
||||||
devtool: "source-map",
|
|
||||||
};
|
|
Reference in New Issue