Skip to content

Commit

Permalink
🖲 Benchmark cryptographic signing and verifying
Browse files Browse the repository at this point in the history
  • Loading branch information
ferdodo committed Dec 13, 2024
1 parent 57e37bf commit a1ef45f
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 4 deletions.
3 changes: 2 additions & 1 deletion back/benchmark/benchmark-data-mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export async function benchMarkDataMapper(dataMapper: DataMapper) {
createdAt: new Date().toISOString(),
};

const bench = new Bench({ name: "simple benchmark" });
const bench = new Bench({ name: "simple benchmark", iterations: 1000 });

bench.add("Create queuer", () => dataMapper.createQueuer(queuer), {
beforeEach() {
Expand All @@ -26,6 +26,7 @@ export async function benchMarkDataMapper(dataMapper: DataMapper) {
bench.tasks.map(({ name, result }) => ({
"Task Name": name,
"Average (ms)": Math.floor(result?.mean ?? 0),
"p99 (ms)": Math.floor(result?.p99 ?? 0),
"Longest (ms)": Math.floor(result?.max ?? 0),
"Ops/Sec": Math.floor(result?.hz ?? 0),
})),
Expand Down
40 changes: 40 additions & 0 deletions back/benchmark/benchmark-sign-verify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Bench } from "tinybench";
import type { DataMapper } from "core/types/data-mapper";
import { createKeyPair } from "../utils/create-key-pair.js";
import { sign } from "../utils/sign.js";
import { verify } from "../utils/verify.js";

export async function benchmarkSignVerify() {
let [publicKey, privateKey] = await createKeyPair();
let signed = await sign(publicKey, privateKey, { data: Math.random() });

let data = { data: Math.random() };

const bench = new Bench({ name: "simple benchmark", iterations: 2 });

bench.add("sign", () => sign(publicKey, privateKey, data), {
async beforeEach() {
[publicKey, privateKey] = await createKeyPair();
data = { data: Math.random() };
},
});

bench.add("verify", () => verify(signed), {
async beforeEach() {
[publicKey, privateKey] = await createKeyPair();
signed = await sign(publicKey, privateKey, data);
},
});

await bench.run();

console.table(
bench.tasks.map(({ name, result }) => ({
"Task Name": name,
"Average (ms)": Math.floor(result?.mean ?? 0),
"p99 (ms)": Math.floor(result?.p99 ?? 0),
"Longest (ms)": Math.floor(result?.max ?? 0),
"Ops/Sec": Math.floor(result?.hz ?? 0),
})),
);
}
2 changes: 2 additions & 0 deletions back/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { withServerStarted } from "core/fixtures/with-server-started";
import { createBackContext } from "./utils/create-back-context.js";
import { asNewPlayerConnect } from "core/automations/as-new-player-connect";
import { benchMarkDataMapper } from "./benchmark/benchmark-data-mapper.js";
import { benchmarkSignVerify } from "./benchmark/benchmark-sign-verify.js";
//import { asPlayerInitiateGame } from "core/automations/as-player-initiate-game";

console.log("Starting...");
Expand All @@ -17,6 +18,7 @@ Promise.resolve().then(async () => {
const dataMapper = createDataMapper(orm, db);

await benchMarkDataMapper(dataMapper);
await benchmarkSignVerify();

console.log("Success !");
});
2 changes: 1 addition & 1 deletion back/utils/create-back-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function createBackContext(orm: MikroORM, db: Db): BackContext {
connections$: createWsServer(),
isValidSignature: () => Promise.resolve(true),
serverPublicKey,
signMessage: (message) => sign(serverPublicKey, message),
signMessage: (message) => sign(serverPublicKey, "privateKey", message),
lateMatchmakingTimer: (source) => source.pipe(debounceTime(10000)),
roundTimer: createRoundTimer(),
dataMapper: createDataMapper(orm, db),
Expand Down
30 changes: 30 additions & 0 deletions back/utils/create-key-pair.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { webcrypto } from "node:crypto";

export async function createKeyPair(): Promise<[string, string]> {
const keyPair: CryptoKeyPair = await webcrypto.subtle.generateKey(
{ name: "ECDSA", namedCurve: "P-384" },
true,
["verify", "sign"],
);

const publicKeyBuffer: ArrayBuffer = await webcrypto.subtle.exportKey(
"spki",
keyPair.publicKey,
);

const privateKeyBuffer: ArrayBuffer = await webcrypto.subtle.exportKey(
"pkcs8",
keyPair.privateKey,
);

const publicKey: string = buf2hex(publicKeyBuffer);
const privateKey: string = buf2hex(privateKeyBuffer);
return [publicKey, privateKey];
}

function buf2hex(buffer: ArrayBuffer): string {
return [...new Uint8Array(buffer)]
.map((x) => x.toString(16))
.map((x) => x.padStart(2, "0"))
.join("");
}
4 changes: 2 additions & 2 deletions back/utils/sign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { webcrypto } from "node:crypto";

export async function sign<T>(
publicKey: string,
privateKeyStr: string,
payload: T,
): Promise<T & Signed> {
const privateKeyStr: string = process.env.SIGNING_PRIVATE_KEY;
const privateKeyBuffer: ArrayBuffer = Buffer.from(privateKeyStr, "base64");
const privateKeyBuffer: ArrayBuffer = Buffer.from(privateKeyStr, "hex");

const ecKeyImportParams: EcKeyImportParams = {
name: "ECDSA",
Expand Down

0 comments on commit a1ef45f

Please sign in to comment.