diff --git a/src/interface.ts b/src/interface.ts index 756362a..0b4aebf 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -22,8 +22,8 @@ export interface IBls { verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean; verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean; - initBLS: () => Promise; - destroy: () => void; + initBLS(): Promise; + destroy(): void; } export interface IKeypair { @@ -45,7 +45,6 @@ export interface ISignature { } export interface IPrivateKey { - value: any; toPublicKey(): IPublicKey; signMessage(message: Uint8Array): ISignature; toBytes(): Buffer; diff --git a/test/benchmark/index.ts b/test/benchmark/index.ts index b726098..18dc9ed 100644 --- a/test/benchmark/index.ts +++ b/test/benchmark/index.ts @@ -1,95 +1,49 @@ import crypto from "crypto"; -import * as blst from "@chainsafe/blst"; -import * as herumi from "../../src"; import {runBenchmark} from "./runner"; +import {runForAllImplementations} from "../switch"; +import {IPublicKey, ISignature} from "../../src/interface"; -(async function () { - await herumi.initBLS(); +runForAllImplementations(async (bls, implementation) => { + await bls.initBLS(); const aggCount = 30; // verify - runBenchmark<{pk: blst.PublicKey; msg: Uint8Array; sig: blst.Signature}, boolean>({ - id: "BLST verify", + runBenchmark<{pk: IPublicKey; msg: Uint8Array; sig: ISignature}, boolean>({ + id: `${implementation} verify`, prepareTest: () => { const msg = randomMsg(); - const sk = blst.SecretKey.fromKeygen(crypto.randomBytes(32)); + const sk = bls.PrivateKey.fromKeygen(); const pk = sk.toPublicKey(); - const sig = sk.sign(msg); + const sig = sk.signMessage(msg); return { input: {pk, msg, sig}, resultCheck: (valid) => valid === true, }; }, testRunner: ({pk, msg, sig}) => { - return blst.verify(msg, pk, sig); - }, - }); - - runBenchmark<{pk: herumi.PublicKey; msg: Uint8Array; sig: herumi.Signature}, boolean>({ - id: "HERUMI verify", - - prepareTest: () => { - const msg = randomMsg(); - const keypair = herumi.generateKeyPair(); - const pk = keypair.publicKey; - const sig = keypair.privateKey.signMessage(msg); - return { - input: {pk, msg, sig}, - resultCheck: (valid) => valid === true, - }; - }, - testRunner: ({pk, msg, sig}) => { - return pk.verifyMessage(sig, msg); + return sig.verify(pk, msg); }, }); // Fast aggregate - runBenchmark<{pks: blst.AggregatePublicKey[]; msg: Uint8Array; sig: blst.Signature}, boolean>({ - id: "BLST fastAggregateVerify", + runBenchmark<{pks: IPublicKey[]; msg: Uint8Array; sig: ISignature}, boolean>({ + id: `${implementation} verifyAggregate`, prepareTest: () => { const msg = randomMsg(); - const dataArr = range(aggCount).map(() => { - const sk = blst.SecretKey.fromKeygen(crypto.randomBytes(32)); - const pk = sk.toAggregatePublicKey(); - const sig = sk.sign(msg); + const sk = bls.PrivateKey.fromKeygen(); + const pk = sk.toPublicKey(); + const sig = sk.signMessage(msg); return {pk, sig}; }); const pks = dataArr.map((data) => data.pk); - const aggSig = blst.AggregateSignature.fromSignatures(dataArr.map((data) => data.sig)); - const sig = aggSig.toSignature(); - - return { - input: {pks, msg, sig}, - resultCheck: (valid) => valid === true, - }; - }, - testRunner: ({pks, msg, sig}) => { - return blst.fastAggregateVerify(msg, pks, sig); - }, - }); - - runBenchmark<{pks: herumi.PublicKey[]; msg: Uint8Array; sig: herumi.Signature}, boolean>({ - id: "HERUMI fastAggregateVerify", - - prepareTest: () => { - const msg = randomMsg(); - - const dataArr = range(aggCount).map(() => { - const keypair = herumi.generateKeyPair(); - const pk = keypair.publicKey; - const sig = keypair.privateKey.signMessage(msg); - return {pk, sig}; - }); - - const pks = dataArr.map((data) => data.pk); - const sig = herumi.Signature.aggregate(dataArr.map((data) => data.sig)); + const sig = bls.Signature.aggregate(dataArr.map((data) => data.sig)); return { input: {pks, msg, sig}, @@ -101,50 +55,41 @@ import {runBenchmark} from "./runner"; }, }); + // Aggregate pubkeys + + runBenchmark({ + id: `${implementation} aggregate pubkeys (${aggCount})`, + + prepareTest: () => { + return { + input: range(aggCount).map(() => bls.PrivateKey.fromKeygen().toPublicKey()), + }; + }, + testRunner: (pks) => { + bls.PublicKey.aggregate(pks); + }, + }); + // Aggregate sigs - runBenchmark({ - id: `BLST aggregatePubkeys (${aggCount})`, + runBenchmark({ + id: `${implementation} aggregate signatures (${aggCount})`, prepareTest: () => { + const msg = randomMsg(); + const sigs = range(aggCount).map(() => { + const sk = bls.PrivateKey.fromKeygen(); + return sk.signMessage(msg); + }); return { - input: range(aggCount).map(() => blst.SecretKey.fromKeygen(crypto.randomBytes(32)).toPublicKey()), + input: sigs, }; }, - testRunner: (pks) => { - blst.AggregatePublicKey.fromPublicKeys(pks); + testRunner: (sigs) => { + bls.Signature.aggregate(sigs); }, }); - - runBenchmark({ - id: `BLST aggregatePubkeys as jacobian (${aggCount})`, - - prepareTest: () => { - return { - input: range(aggCount).map(() => { - const pk = blst.SecretKey.fromKeygen(crypto.randomBytes(32)).toPublicKey(); - return blst.AggregatePublicKey.fromPublicKey(pk); - }), - }; - }, - testRunner: (pks) => { - blst.aggregatePubkeys(pks); - }, - }); - - runBenchmark({ - id: `HERUMI aggregatePubkeys (${aggCount})`, - - prepareTest: () => { - return { - input: range(aggCount).map(() => herumi.generateKeyPair().publicKey), - }; - }, - testRunner: (pks) => { - herumi.PublicKey.aggregate(pks); - }, - }); -})(); +}); function range(n: number): number[] { const nums: number[] = []; diff --git a/test/spec/aggregate_sigs.test.ts b/test/spec/aggregate_sigs.test.ts index c2a0e9c..50af3fa 100644 --- a/test/spec/aggregate_sigs.test.ts +++ b/test/spec/aggregate_sigs.test.ts @@ -2,7 +2,7 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {bytesToHex, hexToBytes} from "../../src/helpers/utils"; import {SPEC_TESTS_DIR} from "../params"; -import {forEachImplementation} from "../switch"; +import {describeForAllImplementations} from "../switch"; interface IAggregateSigsTestCase { data: { @@ -11,7 +11,7 @@ interface IAggregateSigsTestCase { }; } -forEachImplementation((bls) => { +describeForAllImplementations((bls) => { describeDirectorySpecTest( "bls/aggregate/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/aggregate/small"), diff --git a/test/spec/aggregate_sigs_verify.test.ts b/test/spec/aggregate_sigs_verify.test.ts index 5757ab7..a2f0676 100644 --- a/test/spec/aggregate_sigs_verify.test.ts +++ b/test/spec/aggregate_sigs_verify.test.ts @@ -2,7 +2,7 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {hexToBytes} from "../../src/helpers/utils"; import {SPEC_TESTS_DIR} from "../params"; -import {forEachImplementation} from "../switch"; +import {describeForAllImplementations} from "../switch"; interface IAggregateSigsVerifyTestCase { data: { @@ -15,7 +15,7 @@ interface IAggregateSigsVerifyTestCase { }; } -forEachImplementation((bls) => { +describeForAllImplementations((bls) => { describeDirectorySpecTest( "bls/aggregate_verify/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/aggregate_verify/small"), diff --git a/test/spec/fast_aggregate_verify.test.ts b/test/spec/fast_aggregate_verify.test.ts index 53f036c..6cf9906 100644 --- a/test/spec/fast_aggregate_verify.test.ts +++ b/test/spec/fast_aggregate_verify.test.ts @@ -2,7 +2,7 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {hexToBytes} from "../../src/helpers/utils"; import {SPEC_TESTS_DIR} from "../params"; -import {forEachImplementation} from "../switch"; +import {describeForAllImplementations} from "../switch"; interface IAggregateSigsVerifyTestCase { data: { @@ -15,7 +15,7 @@ interface IAggregateSigsVerifyTestCase { }; } -forEachImplementation((bls) => { +describeForAllImplementations((bls) => { describeDirectorySpecTest( "bls/fast_aggregate_verify/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/fast_aggregate_verify/small"), diff --git a/test/spec/sign.test.ts b/test/spec/sign.test.ts index 1e488f0..f525e5d 100644 --- a/test/spec/sign.test.ts +++ b/test/spec/sign.test.ts @@ -2,7 +2,7 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {bytesToHex, hexToBytes} from "../../src/helpers/utils"; import {SPEC_TESTS_DIR} from "../params"; -import {forEachImplementation} from "../switch"; +import {describeForAllImplementations} from "../switch"; interface ISignMessageTestCase { data: { @@ -14,7 +14,7 @@ interface ISignMessageTestCase { }; } -forEachImplementation((bls) => { +describeForAllImplementations((bls) => { describeDirectorySpecTest( "bls/sign/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/sign/small"), diff --git a/test/spec/verify.test.ts b/test/spec/verify.test.ts index 7e2e779..59e65f8 100644 --- a/test/spec/verify.test.ts +++ b/test/spec/verify.test.ts @@ -2,7 +2,7 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {hexToBytes} from "../../src/helpers/utils"; import {SPEC_TESTS_DIR} from "../params"; -import {forEachImplementation} from "../switch"; +import {describeForAllImplementations} from "../switch"; interface IVerifyTestCase { data: { @@ -15,7 +15,7 @@ interface IVerifyTestCase { }; } -forEachImplementation((bls) => { +describeForAllImplementations((bls) => { describeDirectorySpecTest( "bls/verify/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/verify/small"), diff --git a/test/switch.ts b/test/switch.ts index 4fb8799..66a6f45 100644 --- a/test/switch.ts +++ b/test/switch.ts @@ -14,19 +14,23 @@ export function getBls(implementation: Implementation): IBls { } } -export function forEachImplementation( - implementations: Implementation[], - callback: (bls: ReturnType, implementation: Implementation) => void -): void { - for (const implementation of implementations) { - describe(implementation, () => { - const bls = getBls(implementation); +export async function runForAllImplementations( + callback: (bls: IBls, implementation: Implementation) => Promise | void +): Promise { + for (const implementation of ["blst", "herumi"] as Implementation[]) { + const bls = getBls(implementation); + await callback(bls, implementation); + } +} +export function describeForAllImplementations(callback: (bls: IBls) => void): void { + runForAllImplementations((bls, implementation) => { + describe(implementation, () => { before(async () => { await bls.initBLS(); }); - callback(bls, implementation); + callback(bls); }); - } + }); } diff --git a/test/unit/index.test.ts b/test/unit/index.test.ts index 32da4a0..b7ef13b 100644 --- a/test/unit/index.test.ts +++ b/test/unit/index.test.ts @@ -2,7 +2,7 @@ import {expect} from "chai"; import {IBls} from "../../src/interface"; import {getN, randomMessage} from "../util"; -export function runIndexTests(bls: IBls) { +export function runIndexTests(bls: IBls): void { // eslint-disable-next-line @typescript-eslint/explicit-function-return-type function getRandomData() { const sk = bls.PrivateKey.fromKeygen(); diff --git a/test/unit/privateKey.test.ts b/test/unit/privateKey.test.ts index b849cf9..75aad31 100644 --- a/test/unit/privateKey.test.ts +++ b/test/unit/privateKey.test.ts @@ -1,7 +1,7 @@ import {expect} from "chai"; import {IBls} from "../../src/interface"; -export function runPrivateKeyTests(bls: IBls) { +export function runPrivateKeyTests(bls: IBls): void { describe("PrivateKey", () => { it("should generate fromKeygen private key", () => { const privateKey1 = bls.PrivateKey.fromKeygen(); diff --git a/test/unit/publicKey.test.ts b/test/unit/publicKey.test.ts index 0c66cf1..cb139c1 100644 --- a/test/unit/publicKey.test.ts +++ b/test/unit/publicKey.test.ts @@ -1,7 +1,7 @@ import {expect} from "chai"; import {IBls} from "../../src/interface"; -export function runPublicKeyTests(bls: IBls) { +export function runPublicKeyTests(bls: IBls): void { describe("PublicKey", () => { const publicKey = "0xb6f21199594b56d77670564bf422cb331d5281ca2c1f9a45588a56881d8287ef8619efa6456d6cd2ef61306aa5b21311"; diff --git a/test/unit/run-all-implementations.test.ts b/test/unit/run-all-implementations.test.ts index ea90530..f42a3f1 100644 --- a/test/unit/run-all-implementations.test.ts +++ b/test/unit/run-all-implementations.test.ts @@ -2,10 +2,10 @@ import {runPrivateKeyTests} from "./privateKey.test"; import {runPublicKeyTests} from "./publicKey.test"; // import {runKeypairTests} from "./keypair.test"; import {runIndexTests} from "./index.test"; -import {forEachImplementation} from "../switch"; +import {describeForAllImplementations} from "../switch"; // Import test's bls lib lazily to prevent breaking test with Karma -forEachImplementation(["blst", "herumi"], (bls) => { +describeForAllImplementations((bls) => { runPrivateKeyTests(bls); runPublicKeyTests(bls); // runKeypairTests(bls); diff --git a/test/unit/run-web-implementation.test.ts b/test/unit/run-web-implementation.test.ts index 31d18e0..b70e9bd 100644 --- a/test/unit/run-web-implementation.test.ts +++ b/test/unit/run-web-implementation.test.ts @@ -9,6 +9,8 @@ import {runIndexTests} from "./index.test"; // Error: BLST bindings loader should only run in a NodeJS context: process.platform describe("herumi", () => { before(async () => { + // For consistency with describeForAllImplementations + // eslint-disable-next-line import/no-named-as-default-member await herumi.initBLS(); });