1import { describe, expect, it } from "vitest";23import { deriveKey, deriveKeyRaw, generateSalt } from "./argon2";45678const CAFE_BASE = "café";9const CAFE_NFD = CAFE_BASE.normalize("NFD");10const CAFE_NFC = CAFE_BASE.normalize("NFC");1112describe("crypto argon2", () => {13 it("deriveKey is deterministic for the same password and salt", async () => {14 const salt = generateSalt();1516 const first = await deriveKey("correct-pass-12345", salt);17 const second = await deriveKey("correct-pass-12345", salt);1819 expect(first).toEqual(second);20 });2122 it("deriveKey changes when the salt changes", async () => {23 const first = await deriveKey("correct-pass-12345", generateSalt());24 const second = await deriveKey("correct-pass-12345", generateSalt());2526 expect(first).not.toEqual(second);27 });2829 it("deriveKey changes when the password changes", async () => {30 const salt = generateSalt();3132 const first = await deriveKey("correct-pass-12345", salt);33 const second = await deriveKey("wrong-pass-67890", salt);3435 expect(first).not.toEqual(second);36 });3738 it("LV-1: deriveKey NFC-normalizes so composed and decomposed forms match", async () => {39 const salt = generateSalt();40 expect(CAFE_NFC).not.toBe(CAFE_NFD);41 expect(await deriveKey(CAFE_NFC, salt)).toEqual(await deriveKey(CAFE_NFD, salt));42 });4344 it("LV-1: deriveKeyRaw does NOT normalize (composed vs decomposed differ)", async () => {45 const salt = generateSalt();46 expect(await deriveKeyRaw(CAFE_NFC, salt)).not.toEqual(47 await deriveKeyRaw(CAFE_NFD, salt),48 );49 });5051 it("LV-1: ASCII passwords are unaffected — deriveKey equals deriveKeyRaw", async () => {52 const salt = generateSalt();53 expect(await deriveKey("correct-pass-12345", salt)).toEqual(54 await deriveKeyRaw("correct-pass-12345", salt),55 );56 });5758 it("generateSalt returns 16 bytes", () => {59 expect(generateSalt()).toHaveLength(16);60 });6162 it("generateSalt returns different values across calls", () => {63 expect(generateSalt()).not.toEqual(generateSalt());64 });65});