Implementation of bls signature verification for ethereum 2.0

!ETH2.0_Spec_Version 1.0.0
!ES Version
!Node Version
Javascript library for BLS (Boneh-Lynn-Shacham) signatures and signature aggregation, tailored for use in Eth2.
``bash`
yarn add @chainsafe/bls
To use native bindings you must install peer dependency @chainsafe/blst
`bash`
yarn add @chainsafe/bls @chainsafe/blst
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.
The blst-native implementation offers a multi-threaded approach to verification and utilizes the libuv worker pool to verification. It is a more performant options synchronously and FAR better when utilized asynchronously. All verification functions provide sync and async versions. Both the blst-native and herumi implementations offer verification functions with async prefixes as free functions and also on their respective classes. This was done to preserve the isomorphic architecture of this library. In reality however, only the blst-native bindings have the ability to implement a promise based approach. In the herumi version the async version just proxies to the sync version under the hood.
`ts
import bls from "@chainsafe/bls";
(async () => {
// class-based interface
const secretKey = bls.SecretKey.fromKeygen();
const publicKey = secretKey.toPublicKey();
const message = new Uint8Array(32);
const signature = secretKey.sign(message);
console.log("Is valid: ", signature.verify(publicKey, message));
// functional interface
const sk = secretKey.toBytes();
const pk = bls.secretKeyToPublicKey(sk);
const sig = bls.sign(sk, message);
console.log("Is valid: ", bls.verify(pk, message, sig));
})();
`
If you are in the browser, import from /herumi to explicitly import the WASM version
`ts`
import bls from "@chainsafe/bls/herumi";
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`
yarn add @chainsafe/bls @chainsafe/blst
`ts`
import bls from "@chainsafe/bls/blst-native";
If you need to get a bls implementation at runtime, import from /getImplementation.
`ts
import {getImplementation} from "@chainsafe/bls/getImplementation";
const bls = await getImplementation("herumi");
`
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 uninitializedbls
await init("herumi");
// here is initializedimport bls from "@chainsafe/bls/switchable"
// now other modules can and it will be initialized`
The API is identical for all implementations.
- blst: src/blst-native (node.js-only, bindings to C via node-gyp)herumi
- : src/herumi (node.js & browser, wasm)noble
- : noble-bls12-381 (node.js & browser, pure JS)
Results are in ops/sec (x times slower), where x times slower = times slower than fastest implementation (blst).
| Function - ops/sec | blst | herumi | noble |verify
| -------------------------------- | :----: | :----------: | :-----------: |
| | 326.38 | 47.674 (x7) | 17.906 (x18) |verifyAggregate
| (30) | 453.29 | 51.151 (x9) | 18.372 (x25) |verifyMultiple
| (30) | 34.497 | 3.5233 (x10) | 2.0286 (x17) |verifyMultipleSignatures
| (30) | 26.381 | 3.1633 (x8) | - |aggregate
| (pubkeys, 30) | 15686 | 2898.9 (x5) | 1875.0 (x8) |aggregate
| (sigs, 30) | 6373.4 | 1033.0 (x6) | 526.25 (x12) |sign
| | 925.49 | 108.81 (x9) | 10.246 (x90) |
\* blst and herumi performed 100 runs each, noble` 10 runs.
Results from CI run
| Version | Bls spec hash-to-curve version |
| ------- | :----------------------------: |
| 5.x.x | draft #9 |
| 2.x.x | draft #7 |
| 1.x.x | draft #6 |
| 0.3.x | initial version |
> spec
Apache-2.0