Giter VIP home page Giter VIP logo

bls's Introduction

bls

codecov 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.

Usage

yarn add @chainsafe/bls

To use native bindings you must install peer dependency @chainsafe/blst

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.

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));
})();

Browser

If you are in the browser, import from /herumi to explicitly import the WASM version

import bls from "@chainsafe/bls/herumi";

Native bindings only

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

yarn add @chainsafe/bls @chainsafe/blst
import bls from "@chainsafe/bls/blst-native";

Get implementation at runtime

If you need to get a bls implementation at runtime, import from /getImplementation.

import {getImplementation} from "@chainsafe/bls/getImplementation";

const bls = await getImplementation("herumi");

Switchable singleton

If you need a singleton that is switchable at runtime (the default behavior in <=v6), import from /switchable.

import bls, {init} from "@chainsafe/bls/switchable";

// here `bls` is uninitialized
await init("herumi");
// 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.

Benchmarks

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 https://github.com/ChainSafe/bls/runs/1513710175?check_suite_focus=true#step:12:13

Spec versioning

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

test vectors

License

Apache-2.0

bls's People

Contributors

3xtr4t3rr3str14l avatar aunyks avatar austinabell avatar ayushkaul avatar dadepo avatar dapplion avatar dependabot[bot] avatar g11tech avatar jeluard avatar matthewkeil avatar mpetrunic avatar nazarhussain avatar paulmillr avatar petarkirov avatar philknows avatar wemeetagain avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bls's Issues

Support Signature.isInfinity method

I vaguely remember we had that. It's somewhat easy to implement by checking serialized bytes. But it's more user friendly if it's in bls.

verify should throw if initBLS is not called

Running a synchronous NodeJS script that does not call initBLS first, and calling verify on a valid signature returns false. It should throw instead of returning a false value.

Implement generateRandomSecretKey locally

Consider implementing generateRandomSecretKey() which is just

function generateRandomSecretKey() {
  let sk = 0;
  while (sk === 0) {
    sk = randomBytes() % CURVE_ORDER
  }
  return sk;
}

and remove the @chainsafe/bls-keygen which depends on bcrypto and then you have fun unnecessary node-gyp compilation. @wemeetagain what do you think?

Not runnable on Mac ARM64

When I try to install @chainsafe/blst on my arm64 arch, this error returned:

Retrieving BLST native bindings /Users/jasperli/work/etherfi-app/node_modules/@chainsafe/blst/prebuild/darwin-arm64-115-binding.node ...
Error: Error importing BLST native bindings: 404 Not Found

May I suggest that arm64 development is not supported now?

Improve implementation selection strategy

Usage of bls is problematic under some alternative JS environment for the following reasons:

  • usage of top-level-wait in a lib
  • automatic detection of the proper implementation (i.e. use native when node env is detected)

Ideally there would be a way to allow bls users to select the implementation used at runtime. Users should not be able to specify their chosen implementation after the initialization has been done (thus ignoring their choice).

First idea

Single global implementation

BLS_IMPLEMENTATION=herumi node ...
import bls, {init} from "@chainsafe/bls";

// Make sure the initialization has been done
// Can be called several times, initialization is done only once
await init();

const secretKey = bls.SecretKey.fromKeygen();
const message = new Uint8Array(32);
const signature = secretKey.sign(message);

No automatic init would be done, users explicitly have to do it. Essentially it's a modified version (with env variable) of the existing switchable singleton. This would be the only way to use the lib.

Second idea

Explicitly pass around a bls object tied to an implementation.

const bls = await BLS.init("herumi");
const secretKey = bls.SecretKey.fromKeygen();
const message = new Uint8Array(32);
const signature = secretKey.sign(message);

Fails to build on M1 mac

The npm install fails on M1 mac with this error:

npm ERR! ../src/secp256k1/src/scalar_8x32_impl.h:741:5: error: implicitly declaring library function 'memcpy' with type 'void *(void *, const void *, unsigned long)' [-Werror,-Wimplicit-function-declaration]
npm ERR!     memcpy((void *) seed32, (const void *) seed, 32);
npm ERR!     ^
npm ERR! ../src/secp256k1/src/scalar_8x32_impl.h:741:5: note: include the header <string.h> or explicitly provide a declaration for 'memcpy'
npm ERR! 1 error generated.
npm ERR! make: *** [Release/obj.target/bcrypto/src/secp256k1/src/secp256k1.o] Error 1

BTW, secp256k1 C module builds fine from git source.

Can this library generate 160 bits (20 bytes) signature?

according to the original paper, BLS seems to support shortest signature size like 160bits, but i cant find any lib that can support that size directly. i know 160bits is less secure, but produce more user friendly signature for keyboard typing, which can be used in some cases.

Setup CI release un package.json version bump

Consider following CI to automate npm publish, tag, release(with changelog)

name: Release

on:
  push:
    branches:
      - 'master'

jobs:
  tag:
    name: Check and Tag
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
      - name: Create tag
        id: tag
        uses: butlerlogic/[email protected]
        with:
          GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
          strategy: package # Optional, since "package" is the default strategy
          tag_prefix: "v"
    outputs:
      tag: ${{ steps.tag.outputs.tagname }}
      version: ${{ steps.tag.outputs.version }}

  release:
    name: Release
    runs-on: ubuntu-latest
    needs: tag
    if: needs.tag.outputs.tag != ''
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
      - name: Install dependencies
        run: yarn install --non-interactive --frozen-lockfile
      - name: Build
        run: yarn run build
      - name: Create npmrc with npm token:
        run: TODO
      - name: Publish to npm registry
        run: yarn publish --ignore-scripts --no-git-tag-version --no-commit-hooks --non-interactive
      - name: Create Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ needs.tag.outputs.tag }}
          release_name: Release ${{ needs.tag.outputs.tag }}
      #in case of failure
      - name: Rollback on failure
        if: failure()
        uses: author/action-rollback@9ec72a6af74774e00343c6de3e946b0901c23013
        with:
          id: ${{ steps.create_release.outputs.id }}
          tag: ${{ needs.tag.outputs.tag }}
          delete_orphan_tag: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Support/Examples for API for k-of-n threshold signature

This library relies on https://github.com/herumi/bls-eth-wasm which in turn relies on https://github.com/herumi/bls which has support for threshold signatures via https://github.com/herumi/bls#api-for-k-of-n-threshold-signature.

I guess right now you would rely on https://github.com/herumi/bls-eth-wasm exposing those methods so you could access them or are there any plans on adding support/examples for threshold signatures in any another way? Maybe it is already possible to verify an aggregated signature against a subset of public keys and I overlooked it. The use-case would be an M-of-N MuSig implementation where any M signatures being valid according to a set of N public keys results in the verification of an aggregated signature passing.

Change aggregatePublicKeys and aggregateSignatures benchmarks

How is aggregating 30 keys useful?

eth2 would be around 32k validators very soon, and probably 320k after some time. And each slot is voted by around 1k voters

I think it would make sense to benchmark 32, 1024, 32768 and 131072 public keys / signatures.

Allow switchable bls to detect the right implementation

Is your feature request related to a problem? Please describe.
Found out during the testing that on some environment top-level-await are not properly supported. Which are used to initialize the BLS object if the package is imported directly.

Describe the solution you'd like

The best approach to fit in all cases is to import the BLS from the switchable. And when is appropriate use the init to initialize the object.

import bls, {init} from "@chainsafe/bls/switchable";

That init does accept one parameter and it's redundant to identify and pass the parameter for the right implementation. This logic of detecting is already part of the package so we can reuse here. We can provide third option here auto which could be the default value as well. So user don't need to write custom logic and switchable will detect the right implementation.

Describe alternatives you've considered
The alternative safe approach is to use the await import. But that can't be done with correct user experience as code outside that block will not access to the bls object.

Additional context
ChainSafe/lodestar#2723

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.