Clean interface
This commit is contained in:
parent
021e741d17
commit
49d509aca4
16
README.md
16
README.md
|
@ -11,14 +11,18 @@ Javascript library for BLS (Boneh-Lynn-Shacham) signatures and signature aggrega
|
|||
## Usage
|
||||
|
||||
```ts
|
||||
import {PrivateKey} from "@chainsafe/bls";
|
||||
import bls, {init} from "@chainsafe/bls";
|
||||
|
||||
const secretKey = PrivateKey.fromKeygen();
|
||||
const publicKey = secretKey.toPublicKey();
|
||||
const message = new Uint8Array(32);
|
||||
(async () => {
|
||||
await init("herumi");
|
||||
|
||||
const signature = secretKey.sign(message);
|
||||
console.log("Is valid: ", signature.verify(publicKey, message));
|
||||
const secretKey = bls.PrivateKey.fromKeygen();
|
||||
const publicKey = secretKey.toPublicKey();
|
||||
const message = new Uint8Array(32);
|
||||
|
||||
const signature = secretKey.sign(message);
|
||||
console.log("Is valid: ", signature.verify(publicKey, message));
|
||||
})();
|
||||
```
|
||||
|
||||
### Browser
|
||||
|
|
|
@ -7,7 +7,7 @@ import {functionalInterfaceFactory} from "../functional";
|
|||
|
||||
export {PrivateKey, PublicKey, Signature};
|
||||
|
||||
export async function initBLS(): Promise<void> {
|
||||
export async function init(): Promise<void> {
|
||||
// Native bindings require no init() call
|
||||
}
|
||||
export function destroy(): void {
|
||||
|
@ -20,7 +20,7 @@ export const bls: IBls = {
|
|||
Signature,
|
||||
|
||||
...functionalInterfaceFactory({PrivateKey, PublicKey, Signature}),
|
||||
initBLS,
|
||||
init,
|
||||
destroy,
|
||||
};
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ export class PrivateKey implements IPrivateKey {
|
|||
return new PrivateKey(sk);
|
||||
}
|
||||
|
||||
signMessage(message: Uint8Array): Signature {
|
||||
sign(message: Uint8Array): Signature {
|
||||
return new Signature(this.value.sign(message));
|
||||
}
|
||||
|
||||
|
@ -36,8 +36,8 @@ export class PrivateKey implements IPrivateKey {
|
|||
return new PublicKey(affine, jacobian);
|
||||
}
|
||||
|
||||
toBytes(): Buffer {
|
||||
return Buffer.from(this.value.toBytes());
|
||||
toBytes(): Uint8Array {
|
||||
return this.value.toBytes();
|
||||
}
|
||||
|
||||
toHex(): string {
|
||||
|
|
|
@ -32,8 +32,8 @@ export class PublicKey implements IPublicKey {
|
|||
return signature.verify(this, message);
|
||||
}
|
||||
|
||||
toBytes(): Buffer {
|
||||
return Buffer.from(this.affine.toBytes());
|
||||
toBytes(): Uint8Array {
|
||||
return this.affine.toBytes();
|
||||
}
|
||||
|
||||
toHex(): string {
|
||||
|
|
|
@ -39,8 +39,8 @@ export class Signature implements ISignature {
|
|||
);
|
||||
}
|
||||
|
||||
toBytes(): Buffer {
|
||||
return Buffer.from(this.affine.toBytes());
|
||||
toBytes(): Uint8Array {
|
||||
return this.affine.toBytes();
|
||||
}
|
||||
|
||||
toHex(): string {
|
||||
|
|
|
@ -3,5 +3,5 @@ export const SIGNATURE_LENGTH = 96;
|
|||
export const FP_POINT_LENGTH = 48;
|
||||
export const PUBLIC_KEY_LENGTH = FP_POINT_LENGTH;
|
||||
export const G2_HASH_PADDING = 16;
|
||||
export const EMPTY_PUBLIC_KEY = Buffer.alloc(PUBLIC_KEY_LENGTH);
|
||||
export const EMPTY_SIGNATURE = Buffer.alloc(SIGNATURE_LENGTH);
|
||||
export const EMPTY_PUBLIC_KEY = Uint8Array.from(Buffer.alloc(PUBLIC_KEY_LENGTH));
|
||||
export const EMPTY_SIGNATURE = Uint8Array.from(Buffer.alloc(SIGNATURE_LENGTH));
|
||||
|
|
|
@ -13,18 +13,18 @@ export function functionalInterfaceFactory({
|
|||
* @param secretKey
|
||||
* @param messageHash
|
||||
*/
|
||||
function sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer {
|
||||
function sign(secretKey: Uint8Array, messageHash: Uint8Array): Uint8Array {
|
||||
assert(secretKey, "secretKey is null or undefined");
|
||||
assert(messageHash, "messageHash is null or undefined");
|
||||
const privateKey = PrivateKey.fromBytes(secretKey);
|
||||
return privateKey.signMessage(messageHash).toBytes();
|
||||
return privateKey.sign(messageHash).toBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compines all given signature into one.
|
||||
* @param signatures
|
||||
*/
|
||||
function aggregateSignatures(signatures: Uint8Array[]): Buffer {
|
||||
function aggregateSignatures(signatures: Uint8Array[]): Uint8Array {
|
||||
const agg = Signature.aggregate(signatures.map((p) => Signature.fromBytes(p)));
|
||||
return agg.toBytes();
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ export function functionalInterfaceFactory({
|
|||
* Combines all given public keys into single one
|
||||
* @param publicKeys
|
||||
*/
|
||||
function aggregatePubkeys(publicKeys: Uint8Array[]): Buffer {
|
||||
function aggregatePubkeys(publicKeys: Uint8Array[]): Uint8Array {
|
||||
const agg = PublicKey.aggregate(publicKeys.map((p) => PublicKey.fromBytes(p)));
|
||||
return agg.toBytes();
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ export async function setupBls(): Promise<void> {
|
|||
}
|
||||
|
||||
// Cache a promise for Bls instead of Bls to make sure it is initialized only once
|
||||
export async function initBLS(): Promise<void> {
|
||||
export async function init(): Promise<void> {
|
||||
if (!blsGlobalPromise) {
|
||||
blsGlobalPromise = setupBls();
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import {PrivateKey} from "./privateKey";
|
||||
import {PublicKey} from "./publicKey";
|
||||
import {Signature} from "./signature";
|
||||
import {initBLS, destroy} from "./context";
|
||||
import {init, destroy} from "./context";
|
||||
import {IBls} from "../interface";
|
||||
import {functionalInterfaceFactory} from "../functional";
|
||||
|
||||
export {PrivateKey, PublicKey, Signature, initBLS, destroy};
|
||||
export {PrivateKey, PublicKey, Signature, init, destroy};
|
||||
|
||||
const bls: IBls = {
|
||||
PrivateKey,
|
||||
|
@ -13,7 +13,7 @@ const bls: IBls = {
|
|||
Signature,
|
||||
|
||||
...functionalInterfaceFactory({PrivateKey, PublicKey, Signature}),
|
||||
initBLS,
|
||||
init,
|
||||
destroy,
|
||||
};
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ export class PrivateKey implements IPrivateKey {
|
|||
assert(bytes.length === SECRET_KEY_LENGTH, "Private key should have 32 bytes");
|
||||
const context = getContext();
|
||||
const secretKey = new context.SecretKey();
|
||||
secretKey.deserialize(Buffer.from(bytes));
|
||||
secretKey.deserialize(bytes);
|
||||
return new PrivateKey(secretKey);
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ export class PrivateKey implements IPrivateKey {
|
|||
return this.fromBytes(sk);
|
||||
}
|
||||
|
||||
signMessage(message: Uint8Array): Signature {
|
||||
sign(message: Uint8Array): Signature {
|
||||
return new Signature(this.value.sign(message));
|
||||
}
|
||||
|
||||
|
@ -40,8 +40,8 @@ export class PrivateKey implements IPrivateKey {
|
|||
return new PublicKey(this.value.getPublicKey());
|
||||
}
|
||||
|
||||
toBytes(): Buffer {
|
||||
return Buffer.from(this.value.serialize());
|
||||
toBytes(): Uint8Array {
|
||||
return this.value.serialize();
|
||||
}
|
||||
|
||||
toHex(): string {
|
||||
|
|
|
@ -47,8 +47,8 @@ export class PublicKey implements IPublicKey {
|
|||
return this.value.verify(signature.value, messageHash);
|
||||
}
|
||||
|
||||
toBytes(): Buffer {
|
||||
return Buffer.from(this.value.serialize());
|
||||
toBytes(): Uint8Array {
|
||||
return this.value.serialize();
|
||||
}
|
||||
|
||||
toHex(): string {
|
||||
|
|
|
@ -64,8 +64,8 @@ export class Signature implements ISignature {
|
|||
);
|
||||
}
|
||||
|
||||
toBytes(): Buffer {
|
||||
return Buffer.from(this.value.serialize());
|
||||
toBytes(): Uint8Array {
|
||||
return this.value.serialize();
|
||||
}
|
||||
|
||||
toHex(): string {
|
||||
|
|
10
src/index.ts
10
src/index.ts
|
@ -3,17 +3,13 @@ import blsHerumi from "./herumi";
|
|||
|
||||
export type Implementation = "herumi" | "blst-native";
|
||||
|
||||
// This proxy makes sure a nice error is printed if BLS is used before init()
|
||||
export let bls: IBls = new Proxy({} as IBls, {
|
||||
get: function () {
|
||||
throw Error("BLS not initialized, call init() before");
|
||||
},
|
||||
});
|
||||
// TODO: Use a Proxy for example to throw an error if it's not initialized yet
|
||||
export let bls: IBls;
|
||||
|
||||
async function getImplementation(impl: Implementation) {
|
||||
switch (impl) {
|
||||
case "herumi":
|
||||
await blsHerumi.initBLS();
|
||||
await blsHerumi.init();
|
||||
return blsHerumi;
|
||||
|
||||
case "blst-native":
|
||||
|
|
|
@ -15,14 +15,14 @@ export interface IBls {
|
|||
aggregate(signatures: ISignature[]): ISignature;
|
||||
};
|
||||
|
||||
sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer;
|
||||
aggregatePubkeys(publicKeys: Uint8Array[]): Buffer;
|
||||
aggregateSignatures(signatures: Uint8Array[]): Buffer;
|
||||
sign(secretKey: Uint8Array, messageHash: Uint8Array): Uint8Array;
|
||||
aggregatePubkeys(publicKeys: Uint8Array[]): Uint8Array;
|
||||
aggregateSignatures(signatures: Uint8Array[]): Uint8Array;
|
||||
verify(publicKey: Uint8Array, messageHash: Uint8Array, signature: Uint8Array): boolean;
|
||||
verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean;
|
||||
verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean;
|
||||
|
||||
initBLS(): Promise<void>;
|
||||
init(): Promise<void>;
|
||||
destroy(): void;
|
||||
}
|
||||
|
||||
|
@ -32,12 +32,12 @@ export interface IKeypair {
|
|||
}
|
||||
|
||||
export interface IPublicKey {
|
||||
toBytes(): Buffer;
|
||||
toBytes(): Uint8Array;
|
||||
toHex(): string;
|
||||
}
|
||||
|
||||
export interface ISignature {
|
||||
toBytes(): Buffer;
|
||||
toBytes(): Uint8Array;
|
||||
toHex(): string;
|
||||
verify(publicKey: IPublicKey, message: Uint8Array): boolean;
|
||||
verifyAggregate(publicKeys: IPublicKey[], message: Uint8Array): boolean;
|
||||
|
@ -46,7 +46,7 @@ export interface ISignature {
|
|||
|
||||
export interface IPrivateKey {
|
||||
toPublicKey(): IPublicKey;
|
||||
signMessage(message: Uint8Array): ISignature;
|
||||
toBytes(): Buffer;
|
||||
sign(message: Uint8Array): ISignature;
|
||||
toBytes(): Uint8Array;
|
||||
toHex(): string;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import {runForAllImplementations} from "../switch";
|
|||
import {IPublicKey, ISignature} from "../../src/interface";
|
||||
|
||||
runForAllImplementations(async (bls, implementation) => {
|
||||
await bls.initBLS();
|
||||
await bls.init();
|
||||
|
||||
const aggCount = 30;
|
||||
|
||||
|
@ -17,7 +17,7 @@ runForAllImplementations(async (bls, implementation) => {
|
|||
const msg = randomMsg();
|
||||
const sk = bls.PrivateKey.fromKeygen();
|
||||
const pk = sk.toPublicKey();
|
||||
const sig = sk.signMessage(msg);
|
||||
const sig = sk.sign(msg);
|
||||
return {
|
||||
input: {pk, msg, sig},
|
||||
resultCheck: (valid) => valid === true,
|
||||
|
@ -38,7 +38,7 @@ runForAllImplementations(async (bls, implementation) => {
|
|||
const dataArr = range(aggCount).map(() => {
|
||||
const sk = bls.PrivateKey.fromKeygen();
|
||||
const pk = sk.toPublicKey();
|
||||
const sig = sk.signMessage(msg);
|
||||
const sig = sk.sign(msg);
|
||||
return {pk, sig};
|
||||
});
|
||||
|
||||
|
@ -79,7 +79,7 @@ runForAllImplementations(async (bls, implementation) => {
|
|||
const msg = randomMsg();
|
||||
const sigs = range(aggCount).map(() => {
|
||||
const sk = bls.PrivateKey.fromKeygen();
|
||||
return sk.signMessage(msg);
|
||||
return sk.sign(msg);
|
||||
});
|
||||
return {
|
||||
input: sigs,
|
||||
|
|
|
@ -27,7 +27,7 @@ export function describeForAllImplementations(callback: (bls: IBls) => void): vo
|
|||
runForAllImplementations((bls, implementation) => {
|
||||
describe(implementation, () => {
|
||||
before(async () => {
|
||||
await bls.initBLS();
|
||||
await bls.init();
|
||||
});
|
||||
|
||||
callback(bls);
|
||||
|
|
|
@ -8,7 +8,7 @@ export function runIndexTests(bls: IBls): void {
|
|||
const sk = bls.PrivateKey.fromKeygen();
|
||||
const pk = sk.toPublicKey();
|
||||
const msg = randomMessage();
|
||||
const sig = sk.signMessage(msg);
|
||||
const sig = sk.sign(msg);
|
||||
return {sk, pk, msg, sig};
|
||||
}
|
||||
|
||||
|
@ -51,12 +51,7 @@ export function runIndexTests(bls: IBls): void {
|
|||
const msgs = getN(2, () => randomMessage());
|
||||
const pks = sks.map((sk) => sk.toPublicKey());
|
||||
|
||||
const sigs = [
|
||||
sks[0].signMessage(msgs[0]),
|
||||
sks[1].signMessage(msgs[0]),
|
||||
sks[2].signMessage(msgs[1]),
|
||||
sks[3].signMessage(msgs[1]),
|
||||
];
|
||||
const sigs = [sks[0].sign(msgs[0]), sks[1].sign(msgs[0]), sks[2].sign(msgs[1]), sks[3].sign(msgs[1])];
|
||||
|
||||
const aggPubkeys = [
|
||||
bls.aggregatePubkeys([pks[0], pks[1]].map((pk) => pk.toBytes())),
|
||||
|
@ -74,7 +69,7 @@ export function runIndexTests(bls: IBls): void {
|
|||
const msg = randomMessage();
|
||||
const sks = getN(n, () => bls.PrivateKey.fromKeygen());
|
||||
const pks = sks.map((sk) => sk.toPublicKey());
|
||||
const sigs = sks.map((sk) => sk.signMessage(msg));
|
||||
const sigs = sks.map((sk) => sk.sign(msg));
|
||||
|
||||
const aggregateSignature = bls.aggregateSignatures(sigs.map((sig) => sig.toBytes()));
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ describe("herumi", () => {
|
|||
before(async () => {
|
||||
// For consistency with describeForAllImplementations
|
||||
// eslint-disable-next-line import/no-named-as-default-member
|
||||
await herumi.initBLS();
|
||||
await herumi.init();
|
||||
});
|
||||
|
||||
runPrivateKeyTests(herumi);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import crypto from "crypto";
|
||||
|
||||
export function fromHexString(hex: string): Buffer {
|
||||
return Buffer.from(hex.replace("0x", ""), "hex");
|
||||
export function fromHexString(hex: string): Uint8Array {
|
||||
return Uint8Array.from(Buffer.from(hex.replace("0x", ""), "hex"));
|
||||
}
|
||||
|
||||
export function toHexString(bytes: Buffer | Uint8Array): string {
|
||||
|
|
Reference in New Issue