npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

bls-testing

v1.1.94

Published

This library provides tools to facilitate testing BLS signatures on the BN254 curve within a foundry testing environment for smart contracts. Built upon [Kevin Charm's BLS BN254 implementation](https://github.com/kevincharm/bls-bn254).

Downloads

185

Readme

A BN254 Testing Library for the rest of us

This library provides tools to facilitate testing BLS signatures on the BN254 curve within a foundry testing environment for smart contracts. Built upon Kevin Charm's BLS BN254 implementation.

What is this?

This library helps you test BLS signature operations in Solidity smart contracts. It provides a simple interface by wrapping a TypeScript CLI that handles the complex cryptographic operations.

Key Features

  • Generate BLS public keys from private keys
  • Sign messages and verify signatures (single and aggregated)
  • Hash messages to curve points with domain separation
  • Full testing utilities for BLS operations on BN254 curve

How it Works

The library uses Foundry's FFI (Foreign Function Interface) to bridge Solidity contract interactions with the TypeScript CLI.

Install dependencies

npm install

Compile typescript

tsc

Test contracts

forge test

Solidity API

Library Overview

Struct BLSWallet

A struct that represents a BLS wallet containing a private key and public key.

struct BLSWallet {
   uint256 privateKey;
   uint256[4] publicKey;
}

Functions

Generates a BLS wallet with a public key and private key from seed.

function createWallet(string memory seed) returns (BLSWallet memory)

Generates a BLS public key from a private key.

function getPublicKey(uint256 privateKey) returns (uint256[4])

Generates an aggregated BLS public key from multiple private keys.

function getPublicKey(uint256[] privateKeys) returns (uint256[4])

Signs a message with a private key using domain separation.

function sign(uint256 privateKey, string domain, string message) returns (uint256[2])

Signs a bytes32 message with a private key using domain separation.

function sign(uint256 privateKey, string domain, bytes32 message) returns (uint256[2])

Creates an aggregated signature from multiple private keys using domain separation.

function sign(uint256[] privateKeys, string domain, string message) returns (uint256[2])

Creates an aggregated signature from multiple private keys for a bytes32 message using domain separation.

function sign(uint256[] privateKeys, string domain, bytes32 message) returns (uint256[2])

Hashes a message to a curve point using domain separation.

function hashToPoint(string domain, string message) returns (uint256[2])

Hashes a bytes32 message to a curve point using domain separation.

function hashToPoint(string domain, bytes32 message) returns (uint256[2])

BLS

Verifies a single BLS signature.

function verifySingle(uint256[2] signature, uint256[4] pubkey, uint256[2] message) returns (bool, bool)

Verifies multiple BLS signatures.

function verifyMultiple(uint256[2][] signatures, uint256[4][] pubKeys, uint256[2][] messages) returns (bool, bool)

Typescript CLI Commands

The library provides the following CLI commands:

  • get-pubkey: Generate a BLS public key from a private key
  • get-agg-pubkey: Generate an aggregated public key
  • hash: Hash a message to a curve point
  • sign: Sign a message with a private key
  • sign-agg: Create an aggregated signature

Solidity usage examples

Basic Usage Examples

Generating a Public Key

uint256 privateKey = uint256(0x1234);
uint256[4] memory pubKey = BLSTestingLib.getPublicKey(privateKey);

Generating an Aggregated Public Key

uint256[] memory privateKeys = new uint256[](2);
privateKeys[0] = uint256(0x1234);
privateKeys[1] = uint256(0x5678);
uint256[4] memory aggregatedPubKey = BLSTestingLib.getPublicKey(privateKeys);

Signing a Message

uint256 privateKey = uint256(0x1234);
string memory domain = "domain-message";
string memory message = "message";
uint256[2] memory sig = BLSTestingLib.sign(privateKey, domain, message);

Signing a Bytes32 Message

uint256 privateKey = uint256(0x1234);
string memory domain = "domain-message";
bytes32 message = bytes32(uint256(0x1234567890));
uint256[2] memory sig = BLSTestingLib.sign(privateKey, domain, message);

Creating an Aggregated Signature

uint256[] memory privateKeys = new uint256[](2);
privateKeys[0] = uint256(0x1234);
privateKeys[1] = uint256(0x5678);
string memory domain = "domain-message";
string memory message = "message";
uint256[2] memory aggregatedSig = BLSTestingLib.sign(privateKeys, domain, message);

Hashing a Message to a Curve Point

string memory domain = "domain-message";
string memory message = "message";
uint256[2] memory messagePoint = BLSTestingLib.hashToPoint(domain, message);

End to End Usage Examples verifying with the pairing check precompile

Verifying a Single Signature

uint256 privateKey = uint256(0x1234);
string memory domain = "domain-message";
string memory message = "message";
uint256[4] memory pubKey = BLSTestingLib.getPublicKey(privateKey);
uint256[2] memory sig = BLSTestingLib.sign(privateKey, domain, message);
uint256[2] memory messagePoint = BLSTestingLib.hashToPoint(domain, message);
(bool pairingSuccess, bool callSuccess) = bls.verifySingle(sig, pubKey, messagePoint);
require(callSuccess, "Precompile call failed");
require(pairingSuccess, "Pairing check failed");

Verifying an Aggregated Signature

uint256[] memory privateKeys = new uint256[](2);
privateKeys[0] = uint256(0x1234);
privateKeys[1] = uint256(0x5678);
string memory domain = "domain-message";
string memory message = "message";

uint256[4] memory aggregatedPubKey = BLSTestingLib.getPublicKey(privateKeys);
uint256[2] memory aggregatedSig = BLSTestingLib.sign(privateKeys, domain, message);
uint256[2] memory messagePoint = BLSTestingLib.hashToPoint(domain, message);

(bool pairingSuccess, bool callSuccess) = bls.verifySingle(aggregatedSig, aggregatedPubKey, messagePoint);
require(callSuccess, "Precompile call failed");
require(pairingSuccess, "Pairing check failed");

Verifying Multiple Signatures for unique messages

uint256[] memory privateKeys = new uint256[](2);
privateKeys[0] = uint256(0x1234);
privateKeys[1] = uint256(0x5678);
string[] memory messages = new string[](2);
messages[0] = "message-1";
messages[1] = "message-2";
uint256[2][] memory sigs = new uint256[2][](2);
uint256[4][] memory pubKeys = new uint256[4][](2);
uint256[2][] memory messagePoints = new uint256[2][](2);
for (uint256 i = 0; i < privateKeys.length; i++) {
    pubKeys[i] = BLSTestingLib.getPublicKey(privateKeys[i]);
    sigs[i] = BLSTestingLib.sign(privateKeys[i], domain, messages[i]);
    messagePoints[i] = BLSTestingLib.hashToPoint(domain, messages[i]);
}
(bool pairingSuccess, bool callSuccess) = bls.verifyBatch(sigs, pubKeys, messagePoints);
require(callSuccess, "Precompile call failed");
require(pairingSuccess, "Batch pairing check failed");

Verify Multiple Signatures for unique messages with mixed aggregation

BLSWallet memory wallet1 = BLSTestingLib.createWallet("wallet-1");
BLSWallet memory wallet2 = BLSTestingLib.createWallet("wallet-2"); 
BLSWallet memory wallet3 = BLSTestingLib.createWallet("wallet-3");
BLSWallet memory wallet4 = BLSTestingLib.createWallet("wallet-4");

string memory domain = "test-domain";
string[] memory messages = new string[](3);
messages[0] = "message-for-aggregate";
messages[1] = "message-for-wallet3";
messages[2] = "message-for-wallet4";

uint256[] memory aggPrivateKeys = new uint256[](2);
aggPrivateKeys[0] = wallet1.privateKey;
aggPrivateKeys[1] = wallet2.privateKey;

uint256[2][] memory signatures = new uint256[2][](3);
uint256[4][] memory pubKeys = new uint256[4][](3);
uint256[2][] memory messagePoints = new uint256[2][](3);

signatures[0] = BLSTestingLib.sign(aggPrivateKeys, domain, messages[0]);
pubKeys[0] = BLSTestingLib.getPublicKey(aggPrivateKeys);
messagePoints[0] = BLSTestingLib.hashToPoint(domain, messages[0]);

signatures[1] = BLSTestingLib.sign(wallet3.privateKey, domain, messages[1]);
pubKeys[1] = wallet3.publicKey;
messagePoints[1] = BLSTestingLib.hashToPoint(domain, messages[1]);

signatures[2] = BLSTestingLib.sign(wallet4.privateKey, domain, messages[2]);
pubKeys[2] = wallet4.publicKey;
messagePoints[2] = BLSTestingLib.hashToPoint(domain, messages[2]);

(bool pairingSuccess, bool callSuccess) = bls.verifyBatch(signatures, pubKeys, messagePoints);

require(callSuccess, "Precompile call failed");
require(pairingSuccess, "Batch verification failed");