import { describe, expect, it } from "vitest"; import { deriveKey, generateSalt } from "./argon2"; // Same glyph "café" decomposed (e + U+0301) and composed (U+00E9). Both are // derived from one base literal via normalize(), so the stored byte form of the // literal is irrelevant — the two forms are guaranteed distinct. const CAFE_BASE = "café"; const CAFE_NFD = CAFE_BASE.normalize("NFD"); const CAFE_NFC = CAFE_BASE.normalize("NFC"); describe("crypto argon2", () => { it("deriveKey is deterministic for the same password and salt", async () => { const salt = generateSalt(); const first = await deriveKey("correct-pass-12345", salt); const second = await deriveKey("correct-pass-12345", salt); expect(first).toEqual(second); }); it("deriveKey changes when the salt changes", async () => { const first = await deriveKey("correct-pass-12345", generateSalt()); const second = await deriveKey("correct-pass-12345", generateSalt()); expect(first).not.toEqual(second); }); it("deriveKey changes when the password changes", async () => { const salt = generateSalt(); const first = await deriveKey("correct-pass-12345", salt); const second = await deriveKey("wrong-pass-67890", salt); expect(first).not.toEqual(second); }); it("LV-1: deriveKey NFC-normalizes so composed and decomposed forms match", async () => { const salt = generateSalt(); expect(CAFE_NFC).not.toBe(CAFE_NFD); expect(await deriveKey(CAFE_NFC, salt)).toEqual(await deriveKey(CAFE_NFD, salt)); }); it("generateSalt returns 16 bytes", () => { expect(generateSalt()).toHaveLength(16); }); it("generateSalt returns different values across calls", () => { expect(generateSalt()).not.toEqual(generateSalt()); }); });