diff --git a/benchmark/index.ts b/benchmark/index.ts index 3f787be..bc4a92c 100644 --- a/benchmark/index.ts +++ b/benchmark/index.ts @@ -1,166 +1,84 @@ import {runBenchmark} from "./runner"; import {runForAllImplementations} from "../test/switch"; -import {PublicKey, Signature, SecretKey} from "../src/interface"; -import {range, randomMessage} from "../test/util"; -import {aggCount, runs} from "./params"; +import {PublicKey, Signature} from "../src/interface"; +import {aggCount} from "./params"; (async function () { await runForAllImplementations(async (bls, implementation) => { + const msgSame = Buffer.alloc(32, 255); + const sameMessage: {pk: PublicKey; msg: Uint8Array; sig: Signature}[] = []; + const diffMessage: {pk: PublicKey; msg: Uint8Array; sig: Signature}[] = []; + + for (let i = 0; i < aggCount; i++) { + const msg = Buffer.alloc(32, i + 1); + const sk = bls.SecretKey.fromBytes(Buffer.alloc(32, i + 1)); + const pk = sk.toPublicKey(); + sameMessage.push({pk, msg: msgSame, sig: sk.sign(msgSame)}); + diffMessage.push({pk, msg, sig: sk.sign(msg)}); + } + const {pk, msg, sig} = diffMessage[0]; + const sameMessageSig = bls.Signature.aggregate(sameMessage.map((s) => s.sig)); + const diffMessageSig = bls.Signature.aggregate(diffMessage.map((s) => s.sig)); + // verify - await runBenchmark<{pk: PublicKey; msg: Uint8Array; sig: Signature}, boolean>({ + await runBenchmark({ id: `${implementation} verify`, - - prepareTest: () => { - const msg = randomMessage(); - const sk = bls.SecretKey.fromKeygen(); - const pk = sk.toPublicKey(); - const sig = sk.sign(msg); - return { - input: {pk, msg, sig}, - resultCheck: (valid) => valid === true, - }; - }, - testRunner: ({pk, msg, sig}) => { - return sig.verify(pk, msg); - }, - runs, + prepareTest: () => ({pk, msg, sig}), + testRunner: ({pk, msg, sig}) => sig.verify(pk, msg), }); // Fast aggregate - await runBenchmark<{pks: PublicKey[]; msg: Uint8Array; sig: Signature}, boolean>({ + await runBenchmark({ id: `${implementation} verifyAggregate (${aggCount})`, - - prepareTest: () => { - const msg = randomMessage(); - const dataArr = range(aggCount).map(() => { - const sk = bls.SecretKey.fromKeygen(); - const pk = sk.toPublicKey(); - const sig = sk.sign(msg); - return {pk, sig}; - }); - - const pks = dataArr.map((data) => data.pk); - const sig = bls.Signature.aggregate(dataArr.map((data) => data.sig)); - - return { - input: {pks, msg, sig}, - resultCheck: (valid) => valid === true, - }; - }, - testRunner: ({pks, msg, sig}) => { - return sig.verifyAggregate(pks, msg); - }, - runs, + prepareTest: () => ({pks: sameMessage.map((s) => s.pk), msg: msgSame, sig: sameMessageSig}), + testRunner: ({pks, msg, sig}) => sig.verifyAggregate(pks, msg), }); // Verify multiple - await runBenchmark<{pks: PublicKey[]; msgs: Uint8Array[]; sig: Signature}, boolean>({ + await runBenchmark({ id: `${implementation} verifyMultiple (${aggCount})`, - - prepareTest: () => { - const dataArr = range(aggCount).map(() => { - const sk = bls.SecretKey.fromKeygen(); - const pk = sk.toPublicKey(); - const msg = randomMessage(); - const sig = sk.sign(msg); - return {pk, msg, sig}; - }); - - const pks = dataArr.map((data) => data.pk); - const msgs = dataArr.map((data) => data.msg); - const sig = bls.Signature.aggregate(dataArr.map((data) => data.sig)); - - return { - input: {pks, msgs, sig}, - resultCheck: (valid) => valid === true, - }; - }, - testRunner: ({pks, msgs, sig}) => { - return sig.verifyMultiple(pks, msgs); - }, - runs, + prepareTest: () => ({ + pks: diffMessage.map((s) => s.pk), + msgs: diffMessage.map((s) => s.msg), + sig: diffMessageSig, + }), + testRunner: ({pks, msgs, sig}) => sig.verifyMultiple(pks, msgs), }); // Verify multiple signatures await runBenchmark({ id: `${implementation} verifyMultipleSignatures (${aggCount})`, - - prepareTest: () => { - const sets = range(aggCount).map(() => { - const sk = bls.SecretKey.fromKeygen(); - const pk = sk.toPublicKey(); - const msg = randomMessage(); - const sig = sk.sign(msg); - return {publicKey: pk, message: msg, signature: sig}; - }); - - return { - input: sets, - resultCheck: (valid) => valid === true, - }; - }, - testRunner: (sets) => { - return bls.Signature.verifyMultipleSignatures(sets); - }, - runs, + prepareTest: () => diffMessage, + testRunner: (sets) => + bls.Signature.verifyMultipleSignatures(sets.map((s) => ({publicKey: s.pk, message: s.msg, signature: s.sig}))), }); // Aggregate pubkeys - await runBenchmark({ + await runBenchmark({ id: `${implementation} aggregate pubkeys (${aggCount})`, - - prepareTest: () => { - return { - input: range(aggCount).map(() => bls.SecretKey.fromKeygen().toPublicKey()), - }; - }, - testRunner: (pks) => { - bls.PublicKey.aggregate(pks); - }, - runs, + prepareTest: () => diffMessage.map((s) => s.pk), + testRunner: (pks) => bls.PublicKey.aggregate(pks), }); // Aggregate sigs - await runBenchmark({ + await runBenchmark({ id: `${implementation} aggregate signatures (${aggCount})`, - - prepareTest: () => { - const msg = randomMessage(); - const sigs = range(aggCount).map(() => { - const sk = bls.SecretKey.fromKeygen(); - return sk.sign(msg); - }); - return { - input: sigs, - }; - }, - testRunner: (sigs) => { - bls.Signature.aggregate(sigs); - }, - runs, + prepareTest: () => diffMessage.map((s) => s.sig), + testRunner: (sigs) => bls.Signature.aggregate(sigs), }); // Sign - await runBenchmark<{sk: SecretKey; msg: Uint8Array}, void>({ + await runBenchmark({ id: `${implementation} sign`, - - prepareTest: () => ({ - input: { - sk: bls.SecretKey.fromKeygen(), - msg: randomMessage(), - }, - }), - testRunner: ({sk, msg}) => { - sk.sign(msg); - }, - runs, + prepareTest: () => ({sk: bls.SecretKey.fromKeygen(), msg: msgSame}), + testRunner: ({sk, msg}) => sk.sign(msg), }); }); })(); diff --git a/benchmark/noble.ts b/benchmark/noble.ts index f7912e2..22b9876 100644 --- a/benchmark/noble.ts +++ b/benchmark/noble.ts @@ -5,133 +5,105 @@ import * as noble from "noble-bls12-381"; import {aggCount, runsNoble} from "./params"; (async function () { - // verify + { + // verify - await runBenchmark<{pk: noble.PointG1; msg: noble.PointG2; sig: noble.PointG2}, boolean>({ - id: `noble verify`, + const priv = generateRandomSecretKey(); + const msg = randomMessage(); + const pk = noble.PointG1.fromPrivateKey(priv); + const sig = noble.PointG2.fromSignature(await noble.sign(msg, priv)); - prepareTest: async () => { - const priv = generateRandomSecretKey(); - const msg = randomMessage(); - const pk = noble.PointG1.fromPrivateKey(priv); - const sig = noble.PointG2.fromSignature(await noble.sign(msg, priv)); + await runBenchmark<{pk: noble.PointG1; msg: noble.PointG2; sig: noble.PointG2}, boolean>({ + id: `noble verify`, + prepareTest: async () => ({pk, msg: await noble.PointG2.hashToCurve(msg), sig}), + testRunner: async ({pk, msg, sig}) => await noble.verify(sig, msg, pk), + runs: runsNoble, + }); + } - return { - input: {pk, msg: await noble.PointG2.hashToCurve(msg), sig}, - resultCheck: (valid: boolean) => valid === true, - }; - }, - testRunner: async ({pk, msg, sig}) => { - return await noble.verify(sig, msg, pk); - }, - runs: runsNoble, - }); + { + // Fast aggregate - // Fast aggregate + const msg = randomMessage(); + const dataArr = await Promise.all( + range(aggCount).map(async () => { + const sk = generateRandomSecretKey(); + const pk = noble.PointG1.fromPrivateKey(sk); + const sig = noble.PointG2.fromSignature(await noble.sign(msg, sk)); + return {pk, sig}; + }) + ); - await runBenchmark<{pks: noble.PointG1[]; msg: noble.PointG2; sig: noble.PointG2}, boolean>({ - id: `noble verifyAggregate (${aggCount})`, + const pks = dataArr.map((data) => data.pk); + const sig = (noble.aggregateSignatures(dataArr.map((data) => data.sig)) as any) as noble.PointG2; - prepareTest: async () => { - const msg = randomMessage(); - const dataArr = await Promise.all( - range(aggCount).map(async () => { - const sk = generateRandomSecretKey(); - const pk = noble.PointG1.fromPrivateKey(sk); - const sig = noble.PointG2.fromSignature(await noble.sign(msg, sk)); - return {pk, sig}; - }) - ); + await runBenchmark({ + id: `noble verifyAggregate (${aggCount})`, + prepareTest: async () => ({pks, msg: await noble.PointG2.hashToCurve(msg), sig}), + testRunner: async ({pks, msg, sig}) => + await noble.verify(sig, msg, (noble.aggregatePublicKeys(pks) as any) as noble.PointG1), + runs: runsNoble, + }); + } - const pks = dataArr.map((data) => data.pk); - const sig = noble.aggregateSignatures(dataArr.map((data) => data.sig)) as any as noble.PointG2; + { + // Verify multiple - return { - input: {pks, msg: await noble.PointG2.hashToCurve(msg), sig}, - resultCheck: (valid: boolean) => valid === true, - }; - }, - testRunner: async ({pks, msg, sig}) => { - const pk = noble.aggregatePublicKeys(pks) as any as noble.PointG1; - return await noble.verify(sig, msg, pk); - }, - runs: runsNoble, - }); + const dataArr = await Promise.all( + range(aggCount).map(async () => { + const sk = generateRandomSecretKey(); + const pk = noble.PointG1.fromPrivateKey(sk); + const msg = randomMessage(); + const sig = noble.PointG2.fromSignature(await noble.sign(msg, sk)); + return {pk, msg: await noble.PointG2.hashToCurve(msg), sig}; + }) + ); - // // Verify multiple + const pks = dataArr.map((data) => data.pk); + const msgs = dataArr.map((data) => data.msg); + const sig = (noble.aggregateSignatures(dataArr.map((data) => data.sig)) as any) as noble.PointG2; - await runBenchmark<{pks: noble.PointG1[]; msgs: noble.PointG2[]; sig: noble.PointG2}, boolean>({ - id: `noble verifyMultiple (${aggCount})`, + await runBenchmark({ + id: `noble verifyMultiple (${aggCount})`, + prepareTest: async () => ({pks, msgs, sig}), + testRunner: async ({pks, msgs, sig}) => await noble.verifyBatch(msgs, pks, sig), + runs: runsNoble, + }); + } - prepareTest: async () => { - const dataArr = await Promise.all( - range(aggCount).map(async () => { - const sk = generateRandomSecretKey(); - const pk = noble.PointG1.fromPrivateKey(sk); - const msg = randomMessage(); - const sig = noble.PointG2.fromSignature(await noble.sign(msg, sk)); - return {pk, msg: await noble.PointG2.hashToCurve(msg), sig}; - }) - ); + { + // Aggregate pubkeys - const pks = dataArr.map((data) => data.pk); - const msgs = dataArr.map((data) => data.msg); - const sig = noble.aggregateSignatures(dataArr.map((data) => data.sig)) as any as noble.PointG2; + const pubkeys = range(aggCount).map(() => noble.PointG1.fromPrivateKey(generateRandomSecretKey())); - return { - input: {pks, msgs, sig}, - resultCheck: (valid: boolean) => valid === true, - }; - }, - testRunner: async ({pks, msgs, sig}) => { - return await noble.verifyBatch(msgs, pks, sig); - }, - runs: runsNoble, - }); + await runBenchmark({ + id: `noble aggregate pubkeys (${aggCount})`, + prepareTest: () => pubkeys, + testRunner: async (pks) => noble.aggregatePublicKeys(pks), + runs: runsNoble, + }); + } - // Aggregate pubkeys + const hashes = await Promise.all( + range(aggCount) + .map(() => generateRandomSecretKey()) + .map(noble.PointG2.hashToCurve) + ); - await runBenchmark({ - id: `noble aggregate pubkeys (${aggCount})`, - - prepareTest: () => { - return { - input: range(aggCount).map(() => noble.PointG1.fromPrivateKey(generateRandomSecretKey())), - }; - }, - testRunner: async (pks) => { - noble.aggregatePublicKeys(pks); - }, - runs: runsNoble, - }); - - await runBenchmark({ + await runBenchmark({ id: `noble aggregate signatures (${aggCount})`, - - prepareTest: async () => { - const hashes = range(aggCount).map(() => generateRandomSecretKey()).map(noble.PointG2.hashToCurve); - return { - input: await Promise.all(hashes), - }; - }, - testRunner: async (sigs) => { - noble.aggregateSignatures(sigs); - }, + prepareTest: () => hashes, + testRunner: async (sigs) => noble.aggregateSignatures(sigs), runs: runsNoble, }); - await runBenchmark<{sk: Uint8Array; msg: noble.PointG2}, void>({ - id: `noble sign`, + const sk = generateRandomSecretKey(); + const msg = await noble.PointG2.hashToCurve(randomMessage()); - prepareTest: async () => ({ - input: { - sk: generateRandomSecretKey(), - msg: await noble.PointG2.hashToCurve(randomMessage()), - }, - }), - testRunner: async ({sk, msg}) => { - await noble.sign(msg, sk); - }, + await runBenchmark({ + id: `noble sign`, + prepareTest: () => ({sk, msg}), + testRunner: async ({sk, msg}) => await noble.sign(msg, sk), runs: runsNoble, }); })(); diff --git a/benchmark/runner.ts b/benchmark/runner.ts index 90bdaeb..86a153d 100644 --- a/benchmark/runner.ts +++ b/benchmark/runner.ts @@ -6,7 +6,7 @@ export async function runBenchmark({ runs = 100, id, }: { - prepareTest: (i: number) => PromiseOptional<{input: T; resultCheck?: (result: R) => boolean}>; + prepareTest: (i: number) => PromiseOptional; testRunner: (input: T) => PromiseOptional; runs?: number; id: string; @@ -14,13 +14,12 @@ export async function runBenchmark({ const diffsNanoSec: bigint[] = []; for (let i = 0; i < runs; i++) { - const {input, resultCheck} = await prepareTest(i); + const input = await prepareTest(i); const start = process.hrtime.bigint(); const result = await testRunner(input); const end = process.hrtime.bigint(); - if (resultCheck && !resultCheck(result)) throw Error("Result fails check test"); diffsNanoSec.push(end - start); }