1import { beforeEach, describe, expect, it, vi } from "vitest";2import { generateKeyPairFromSeed } from "@stablelib/x25519";34567891011121314vi.mock("@stablelib/x25519", async (importOriginal) => {15 const actual = await importOriginal<typeof import("@stablelib/x25519")>();16 return {17 ...actual,18 generateKeyPair: () => {19 const g = globalThis as { __kpCounter?: number };20 g.__kpCounter = (g.__kpCounter ?? 0) + 1;21 return actual.generateKeyPairFromSeed(new Uint8Array(32).fill(g.__kpCounter));22 },23 };24});2526function memoryPair() {27 const a: Uint8Array[] = [];28 const b: Uint8Array[] = [];29 const aR: Array<(v: Uint8Array) => void> = [];30 const bR: Array<(v: Uint8Array) => void> = [];31 const tA = {32 async send(m: Uint8Array) { const r = bR.shift(); if (r) r(m); else b.push(m); },33 receive(): Promise<Uint8Array> {34 const v = a.shift();35 if (v) return Promise.resolve(v);36 return new Promise<Uint8Array>((resolve) => aR.push(resolve));37 },38 };39 const tB = {40 async send(m: Uint8Array) { const r = aR.shift(); if (r) r(m); else a.push(m); },41 receive(): Promise<Uint8Array> {42 const v = b.shift();43 if (v) return Promise.resolve(v);44 return new Promise<Uint8Array>((resolve) => bR.push(resolve));45 },46 };47 return [tA, tB] as const;48}4950function hex(b: Uint8Array): string {51 return Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");52}5354describe("PCH-01-002 — Noise handshakes derive over BLAKE2s", () => {55 beforeEach(() => {56 (globalThis as { __kpCounter?: number }).__kpCounter = 0;57 });5859 it("noise_xx_handshake_hash_is_blake2s_derived", async () => {60 const { noiseXXInitiator, noiseXXResponder } = await import("./noise-xx");61 const alice = generateKeyPairFromSeed(new Uint8Array(32).fill(0xa1));62 const bob = generateKeyPairFromSeed(new Uint8Array(32).fill(0xb2));63 const [tA, tB] = memoryPair();6465 const [a, b] = await Promise.all([66 noiseXXInitiator(alice.secretKey, alice.publicKey, tA.send, tA.receive),67 noiseXXResponder(bob.secretKey, bob.publicKey, tB.send, tB.receive),68 ]);6970 71 expect(hex(a.handshakeHash)).toBe(hex(b.handshakeHash));72 73 expect(hex(a.handshakeHash)).toBe(74 "11c8bf7fcefad1f00ff8573c7bca66891626d053addae6d2b78b2f195a9ffd8a",75 );7677 78 const ct = a.encrypt(new TextEncoder().encode("hello"));79 expect(new TextDecoder().decode(b.decrypt(ct))).toBe("hello");80 });8182 it("noise_nk_handshake_hash_is_blake2s_derived", async () => {83 const { noiseNKInitiator, noiseNKResponder } = await import("./noise-js");84 const responder = generateKeyPairFromSeed(new Uint8Array(32).fill(0xc3));85 const [tA, tB] = memoryPair();8687 const [a, b] = await Promise.all([88 noiseNKInitiator(responder.publicKey, tA.send, tA.receive),89 noiseNKResponder(responder.secretKey, responder.publicKey, tB.send, tB.receive),90 ]);9192 expect(hex(a.handshakeHash)).toBe(hex(b.handshakeHash));93 expect(hex(a.handshakeHash)).toBe(94 "0fbab8cd1782bf4b17d69beb69f5b80b0bf24d93da4924959c76ee701c32e655",95 );9697 const ct = a.encrypt(new TextEncoder().encode("ping"));98 expect(new TextDecoder().decode(b.decrypt(ct))).toBe("ping");99 });100});