diff --git a/src/blst/index.ts b/src/blst/index.ts index 49d9bbf..83d05a4 100644 --- a/src/blst/index.ts +++ b/src/blst/index.ts @@ -4,6 +4,7 @@ import {PrivateKey} from "./privateKey"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; import {toBuffer} from "../helpers/utils"; +import {IBls} from "../interface"; export * from "../constants"; export {Keypair, PrivateKey, PublicKey, Signature}; @@ -15,23 +16,6 @@ export function destroy(): void { // Native bindings require no destroy() call } -/** - * Generates new secret and public key - */ -export function generateKeyPair(): Keypair { - return Keypair.generate(); -} - -/** - * Generates public key from given secret. - * @param {BLSSecretKey} secretKey - */ -export function generatePublicKey(secretKey: Uint8Array): Buffer { - assert(secretKey, "secretKey is null or undefined"); - const keypair = new Keypair(PrivateKey.fromBytes(toBuffer(secretKey))); - return keypair.publicKey.toBytes(); -} - /** * Signs given message using secret key. * @param secretKey @@ -127,9 +111,7 @@ export function verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Arr } } -export default { - generateKeyPair, - generatePublicKey, +const bls: IBls = { sign, aggregateSignatures, aggregatePubkeys, @@ -137,10 +119,12 @@ export default { verifyAggregate, verifyMultiple, - Keypair, + // Keypair, PrivateKey, PublicKey, Signature, initBLS, destroy, }; + +export default bls; diff --git a/src/blst/keypair.ts b/src/blst/keypair.ts index 2e34c54..db3928e 100644 --- a/src/blst/keypair.ts +++ b/src/blst/keypair.ts @@ -1,7 +1,8 @@ import {PublicKey} from "./publicKey"; import {PrivateKey} from "./privateKey"; +import {IKeypair} from "../interface"; -export class Keypair { +export class Keypair implements IKeypair { private readonly _publicKey: PublicKey; private readonly _privateKey: PrivateKey; diff --git a/src/blst/privateKey.ts b/src/blst/privateKey.ts index c375cf6..a421147 100644 --- a/src/blst/privateKey.ts +++ b/src/blst/privateKey.ts @@ -1,9 +1,10 @@ import * as blst from "@chainsafe/blst"; import {bytesToHex, getRandomBytes, hexToBytes} from "../helpers/utils"; +import {IPrivateKey} from "../interface"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; -export class PrivateKey { +export class PrivateKey implements IPrivateKey { readonly value: blst.SecretKey; constructor(value: blst.SecretKey) { @@ -25,7 +26,7 @@ export class PrivateKey { } signMessage(message: Uint8Array): Signature { - return Signature.fromValue(this.value.sign(message)); + return new Signature(this.value.sign(message)); } toPublicKey(): PublicKey { diff --git a/src/blst/publicKey.ts b/src/blst/publicKey.ts index 67f5281..ee28c5c 100644 --- a/src/blst/publicKey.ts +++ b/src/blst/publicKey.ts @@ -1,8 +1,9 @@ import * as blst from "@chainsafe/blst"; import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {IPublicKey} from "../interface"; import {Signature} from "./signature"; -export class PublicKey { +export class PublicKey implements IPublicKey { readonly affine: blst.PublicKey; readonly jacobian: blst.AggregatePublicKey; diff --git a/src/blst/signature.ts b/src/blst/signature.ts index eed4ded..5bad9d1 100644 --- a/src/blst/signature.ts +++ b/src/blst/signature.ts @@ -1,8 +1,9 @@ import * as blst from "@chainsafe/blst"; import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {ISignature} from "../interface"; import {PublicKey} from "./publicKey"; -export class Signature { +export class Signature implements ISignature { readonly affine: blst.Signature; constructor(value: blst.Signature) { @@ -17,10 +18,6 @@ export class Signature { return this.fromBytes(hexToBytes(hex)); } - static fromValue(signature: blst.Signature): Signature { - return new Signature(signature); - } - static aggregate(signatures: Signature[]): Signature { const agg = blst.AggregateSignature.fromSignatures(signatures.map((sig) => sig.affine)); return new Signature(agg.toSignature()); diff --git a/src/herumi/context.ts b/src/herumi/context.ts index 65992a4..65d5248 100644 --- a/src/herumi/context.ts +++ b/src/herumi/context.ts @@ -3,18 +3,17 @@ import bls from "@chainsafe/eth2-bls-wasm"; type Bls = typeof bls; let blsGlobal: Bls | null = null; -let blsGlobalPromise: Promise | null = null; +let blsGlobalPromise: Promise | null = null; -export async function setupBls(): Promise { +export async function setupBls(): Promise { if (!blsGlobal) { await bls.init(); blsGlobal = bls; } - return blsGlobal; } // Cache a promise for Bls instead of Bls to make sure it is initialized only once -export async function initBLS(): Promise { +export async function initBLS(): Promise { if (!blsGlobalPromise) { blsGlobalPromise = setupBls(); } diff --git a/src/herumi/index.ts b/src/herumi/index.ts index 4ee3138..6c03481 100644 --- a/src/herumi/index.ts +++ b/src/herumi/index.ts @@ -5,26 +5,10 @@ import {Signature} from "./signature"; import {initBLS, destroy} from "./context"; import assert from "assert"; import {toBuffer} from "../helpers/utils"; +import {IBls} from "../interface"; export {Keypair, PrivateKey, PublicKey, Signature, initBLS, destroy}; -/** - * Generates new secret and public key - */ -export function generateKeyPair(): Keypair { - return Keypair.generate(); -} - -/** - * Generates public key from given secret. - * @param {BLSSecretKey} secretKey - */ -export function generatePublicKey(secretKey: Uint8Array): Buffer { - assert(secretKey, "secretKey is null or undefined"); - const keypair = new Keypair(PrivateKey.fromBytes(toBuffer(secretKey))); - return keypair.publicKey.toBytes(); -} - /** * Signs given message using secret key. * @param secretKey @@ -121,9 +105,7 @@ export function verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Arr } } -export default { - generateKeyPair, - generatePublicKey, +const bls: IBls = { sign, aggregateSignatures, aggregatePubkeys, @@ -131,10 +113,12 @@ export default { verifyAggregate, verifyMultiple, - Keypair, + // Keypair, PrivateKey, PublicKey, Signature, initBLS, destroy, }; + +export default bls; diff --git a/src/herumi/keypair.ts b/src/herumi/keypair.ts index 2e34c54..db3928e 100644 --- a/src/herumi/keypair.ts +++ b/src/herumi/keypair.ts @@ -1,7 +1,8 @@ import {PublicKey} from "./publicKey"; import {PrivateKey} from "./privateKey"; +import {IKeypair} from "../interface"; -export class Keypair { +export class Keypair implements IKeypair { private readonly _publicKey: PublicKey; private readonly _privateKey: PrivateKey; diff --git a/src/herumi/privateKey.ts b/src/herumi/privateKey.ts index c791d2f..facdd59 100644 --- a/src/herumi/privateKey.ts +++ b/src/herumi/privateKey.ts @@ -6,8 +6,9 @@ import {getContext} from "./context"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {IPrivateKey} from "../interface"; -export class PrivateKey { +export class PrivateKey implements IPrivateKey { readonly value: SecretKeyType; constructor(value: SecretKeyType) { diff --git a/src/herumi/publicKey.ts b/src/herumi/publicKey.ts index f104a09..4cd01cc 100644 --- a/src/herumi/publicKey.ts +++ b/src/herumi/publicKey.ts @@ -3,8 +3,9 @@ import {getContext} from "./context"; import {EMPTY_PUBLIC_KEY} from "../constants"; import {Signature} from "./signature"; import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers/utils"; +import {IPublicKey} from "../interface"; -export class PublicKey { +export class PublicKey implements IPublicKey { readonly value: PublicKeyType; constructor(value: PublicKeyType) { diff --git a/src/herumi/signature.ts b/src/herumi/signature.ts index 4995ba1..3bf8a22 100644 --- a/src/herumi/signature.ts +++ b/src/herumi/signature.ts @@ -4,8 +4,9 @@ import {SignatureType} from "@chainsafe/eth2-bls-wasm"; import {getContext} from "./context"; import {PublicKey} from "./publicKey"; import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers/utils"; +import {ISignature} from "../interface"; -export class Signature { +export class Signature implements ISignature { readonly value: SignatureType; constructor(value: SignatureType) { diff --git a/src/interface.ts b/src/interface.ts new file mode 100644 index 0000000..756362a --- /dev/null +++ b/src/interface.ts @@ -0,0 +1,53 @@ +export interface IBls { + PrivateKey: { + fromBytes(bytes: Uint8Array): IPrivateKey; + fromHex(hex: string): IPrivateKey; + fromKeygen(): IPrivateKey; + }; + PublicKey: { + fromBytes(bytes: Uint8Array): IPublicKey; + fromHex(hex: string): IPublicKey; + aggregate(pubkeys: IPublicKey[]): IPublicKey; + }; + Signature: { + fromBytes(bytes: Uint8Array): ISignature; + fromHex(hex: string): ISignature; + aggregate(signatures: ISignature[]): ISignature; + }; + + sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer; + aggregatePubkeys(publicKeys: Uint8Array[]): Buffer; + aggregateSignatures(signatures: Uint8Array[]): Buffer; + 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; + destroy: () => void; +} + +export interface IKeypair { + publicKey: IPublicKey; + privateKey: IPrivateKey; +} + +export interface IPublicKey { + toBytes(): Buffer; + toHex(): string; +} + +export interface ISignature { + toBytes(): Buffer; + toHex(): string; + verify(publicKey: IPublicKey, message: Uint8Array): boolean; + verifyAggregate(publicKeys: IPublicKey[], message: Uint8Array): boolean; + verifyMultiple(publicKeys: IPublicKey[], messages: Uint8Array[]): boolean; +} + +export interface IPrivateKey { + value: any; + toPublicKey(): IPublicKey; + signMessage(message: Uint8Array): ISignature; + toBytes(): Buffer; + toHex(): string; +} diff --git a/test/switch.ts b/test/switch.ts index 19765bb..4fb8799 100644 --- a/test/switch.ts +++ b/test/switch.ts @@ -1,11 +1,11 @@ import blst from "../src/blst"; import herumi from "../src/herumi"; +import {IBls} from "../src/interface"; export type Implementation = "blst" | "herumi"; -export const implementations: Implementation[] = ["blst", "herumi"]; // eslint-disable-next-line @typescript-eslint/explicit-function-return-type -export function getBls(implementation: Implementation) { +export function getBls(implementation: Implementation): IBls { switch (implementation) { case "blst": return blst; @@ -15,17 +15,16 @@ export function getBls(implementation: Implementation) { } export function forEachImplementation( + implementations: Implementation[], callback: (bls: ReturnType, implementation: Implementation) => void ): void { for (const implementation of implementations) { describe(implementation, () => { const bls = getBls(implementation); - if (implementation === "herumi") { - before(async () => { - await bls.initBLS(); - }); - } + before(async () => { + await bls.initBLS(); + }); callback(bls, implementation); }); diff --git a/test/unit/index.test.ts b/test/unit/index.test.ts index 4001b82..32da4a0 100644 --- a/test/unit/index.test.ts +++ b/test/unit/index.test.ts @@ -1,8 +1,8 @@ import {expect} from "chai"; -import {forEachImplementation} from "../switch"; +import {IBls} from "../../src/interface"; import {getN, randomMessage} from "../util"; -forEachImplementation((bls) => { +export function runIndexTests(bls: IBls) { // eslint-disable-next-line @typescript-eslint/explicit-function-return-type function getRandomData() { const sk = bls.PrivateKey.fromKeygen(); @@ -95,4 +95,4 @@ forEachImplementation((bls) => { expect(isValid).to.be.false; }); }); -}); +} diff --git a/test/unit/keypair.test.ts b/test/unit/keypair.test.ts index 4884217..82b2deb 100644 --- a/test/unit/keypair.test.ts +++ b/test/unit/keypair.test.ts @@ -1,27 +1,27 @@ -import {expect} from "chai"; -import {forEachImplementation} from "../switch"; +// import {expect} from "chai"; +// import {IBls} from "../../src/interface"; -forEachImplementation((bls) => { - describe("Keypair", () => { - it("should create from private and public key", () => { - const sk = bls.PrivateKey.fromKeygen(); - const sk2 = bls.PrivateKey.fromKeygen(); - const pk = sk.toPublicKey(); +// export function runKeypairTests(bls: IBls) { +// describe("Keypair", () => { +// it("should create from private and public key", () => { +// const sk = bls.PrivateKey.fromKeygen(); +// const sk2 = bls.PrivateKey.fromKeygen(); +// const pk = sk.toPublicKey(); - const keypair = new bls.Keypair(sk as any, pk as any); +// const keypair = new bls.Keypair(sk, pk); - expect(keypair.publicKey).to.be.equal(pk); - expect(keypair.privateKey).to.be.equal(sk); - expect(keypair.privateKey).to.not.be.equal(sk2); - }); +// expect(keypair.publicKey).to.be.equal(pk); +// expect(keypair.privateKey).to.be.equal(sk); +// expect(keypair.privateKey).to.not.be.equal(sk2); +// }); - it("should create from PrivateKey", () => { - const sk = bls.PrivateKey.fromKeygen(); - const pk = sk.toPublicKey(); +// it("should create from PrivateKey", () => { +// const sk = bls.PrivateKey.fromKeygen(); +// const pk = sk.toPublicKey(); - const keypair = new bls.Keypair(sk as any); +// const keypair = new bls.Keypair(sk as any); - expect(keypair.publicKey.toHex()).to.equal(pk.toHex()); - }); - }); -}); +// expect(keypair.publicKey.toHex()).to.equal(pk.toHex()); +// }); +// }); +// } diff --git a/test/unit/privateKey.test.ts b/test/unit/privateKey.test.ts index f68cfb1..b849cf9 100644 --- a/test/unit/privateKey.test.ts +++ b/test/unit/privateKey.test.ts @@ -1,7 +1,7 @@ import {expect} from "chai"; -import {forEachImplementation} from "../switch"; +import {IBls} from "../../src/interface"; -forEachImplementation((bls) => { +export function runPrivateKeyTests(bls: IBls) { describe("PrivateKey", () => { it("should generate fromKeygen private key", () => { const privateKey1 = bls.PrivateKey.fromKeygen(); @@ -23,4 +23,4 @@ forEachImplementation((bls) => { expect(() => bls.PrivateKey.fromHex("0x2123")).to.throw(); }); }); -}); +} diff --git a/test/unit/publicKey.test.ts b/test/unit/publicKey.test.ts index 5ef7616..0c66cf1 100644 --- a/test/unit/publicKey.test.ts +++ b/test/unit/publicKey.test.ts @@ -1,7 +1,7 @@ import {expect} from "chai"; -import {forEachImplementation} from "../switch"; +import {IBls} from "../../src/interface"; -forEachImplementation((bls) => { +export function runPublicKeyTests(bls: IBls) { describe("PublicKey", () => { const publicKey = "0xb6f21199594b56d77670564bf422cb331d5281ca2c1f9a45588a56881d8287ef8619efa6456d6cd2ef61306aa5b21311"; @@ -18,4 +18,4 @@ forEachImplementation((bls) => { bls.PrivateKey.fromKeygen().toPublicKey(); }); }); -}); +} diff --git a/test/unit/run-all-implementations.test.ts b/test/unit/run-all-implementations.test.ts new file mode 100644 index 0000000..854d6e3 --- /dev/null +++ b/test/unit/run-all-implementations.test.ts @@ -0,0 +1,12 @@ +import {runPrivateKeyTests} from "./privateKey.test"; +import {runPublicKeyTests} from "./publicKey.test"; +// import {runKeypairTests} from "./keypair.test"; +import {runIndexTests} from "./index.test"; +import {forEachImplementation} from "../switch"; + +forEachImplementation(["blst", "herumi"], (bls) => { + runPrivateKeyTests(bls); + runPublicKeyTests(bls); + // runKeypairTests(bls); + runIndexTests(bls); +}); diff --git a/test/unit/run-web-implementation.test.ts b/test/unit/run-web-implementation.test.ts new file mode 100644 index 0000000..ea06044 --- /dev/null +++ b/test/unit/run-web-implementation.test.ts @@ -0,0 +1,12 @@ +import {runPrivateKeyTests} from "./privateKey.test"; +import {runPublicKeyTests} from "./publicKey.test"; +// import {runKeypairTests} from "./keypair.test"; +import {runIndexTests} from "./index.test"; +import {forEachImplementation} from "../switch"; + +forEachImplementation(["herumi"], (bls) => { + runPrivateKeyTests(bls); + runPublicKeyTests(bls); + // runKeypairTests(bls); + runIndexTests(bls); +});