From fbf4d86b060d565b37ed289a3316b05ba669b831 Mon Sep 17 00:00:00 2001 From: Jori Lethinen Date: Fri, 17 Apr 2026 17:34:54 +0300 Subject: [PATCH 1/2] chore: general updates before feature implementation --- AGENTS.md | 427 +++++++++++++++++++++++++++++ package-lock.json | 665 +++++++++++++++++++++++----------------------- package.json | 12 +- tsup.config.ts | 21 ++ 4 files changed, 793 insertions(+), 332 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 2d6762a..41c3823 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -239,6 +239,431 @@ Use ReSpec: --- +## NON-SPEC Web page styling guid + +Must not be used with respec documents. + +Something like this! + +Always ensure mobile-optimization! + +css``` + + + +```` + +--- + +## Seo guide + +```html + + + + + + + + + + + + + + + + + + + + + + + + + + + +```` + +--- + # Cloudflare Workers Discipline Your knowledge of Cloudflare Workers MAY be outdated. @@ -271,7 +696,9 @@ Always consult official limits pages before reasoning about quotas. After modifying bindings in `wrangler.toml` or `wrangler.jsonc`, run: ``` + npx wrangler types + ``` --- diff --git a/package-lock.json b/package-lock.json index 712f468..88799cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,24 +9,24 @@ "version": "2.0.5", "license": "Apache-2.0", "dependencies": { - "@noble/post-quantum": "^0.5.4", + "@noble/post-quantum": "^0.6.1", "@sovereignbase/bytecodec": "^1.5.1" }, "devDependencies": { "@commitlint/cli": "^20.5.0", "@commitlint/config-conventional": "^20.5.0", - "@playwright/test": "^1.58.2", - "@types/node": "^25.5.0", + "@playwright/test": "^1.59.1", + "@types/node": "^25.6.0", "c8": "^11.0.0", "edge-runtime": "^4.0.1", "fast-glob": "^3.3.3", "husky": "^9.1.7", - "playwright": "^1.58.2", - "prettier": "^3.8.1", + "playwright": "^1.59.1", + "prettier": "^3.8.3", "tsup": "^8.5.1", "tsx": "^4.21.0", "typescript": "^5.9.3", - "wrangler": "^4.78.0" + "wrangler": "^4.83.0" }, "engines": { "node": ">=20" @@ -94,9 +94,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20260317.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260317.1.tgz", - "integrity": "sha512-8hjh3sPMwY8M/zedq3/sXoA2Q4BedlGufn3KOOleIG+5a4ReQKLlUah140D7J6zlKmYZAFMJ4tWC7hCuI/s79g==", + "version": "1.20260415.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260415.1.tgz", + "integrity": "sha512-dsxaKsQm3LnPGNPEdsRv09QN3Y4DqCw7kX5j6noKqbAtro2jTr95sVlYM1jUxZ5FkOl1f7SXgaKKB9t5H5Nkbg==", "cpu": [ "x64" ], @@ -111,9 +111,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20260317.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260317.1.tgz", - "integrity": "sha512-M/MnNyvO5HMgoIdr3QHjdCj2T1ki9gt0vIUnxYxBu9ISXS/jgtMl6chUVPJ7zHYBn9MyYr8ByeN6frjYxj0MGg==", + "version": "1.20260415.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260415.1.tgz", + "integrity": "sha512-+JgSgVA49KyKteHRA1SnonE4Zn5Ei5zdAp5FQMxFmXI8qulZw4Hl7safXxRyK4i9sTO8gl7TFOKO5Q64VPvSDQ==", "cpu": [ "arm64" ], @@ -128,9 +128,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20260317.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260317.1.tgz", - "integrity": "sha512-1ltuEjkRcS3fsVF7CxsKlWiRmzq2ZqMfqDN0qUOgbUwkpXsLVJsXmoblaLf5OP00ELlcgF0QsN0p2xPEua4Uug==", + "version": "1.20260415.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260415.1.tgz", + "integrity": "sha512-tU+9pwsqCy8afOVlGtiWrWQc/fedQK4SRm4KPIAt+zOiQWDxWASm6YGBUJis5c648WN80yz47qnmdDi8DQNOcA==", "cpu": [ "x64" ], @@ -145,9 +145,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20260317.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260317.1.tgz", - "integrity": "sha512-3QrNnPF1xlaNwkHpasvRvAMidOvQs2NhXQmALJrEfpIJ/IDL2la8g499yXp3eqhG3hVMCB07XVY149GTs42Xtw==", + "version": "1.20260415.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260415.1.tgz", + "integrity": "sha512-bR9uITnV19r5NQ14xnypi2xHXu2iQvfYV8cVgx0JouFUmWwTEEAwFVojDdssGq93VHX9hr/pi2IRUZeegbYBog==", "cpu": [ "arm64" ], @@ -162,9 +162,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20260317.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260317.1.tgz", - "integrity": "sha512-MfZTz+7LfuIpMGTa3RLXHX8Z/pnycZLItn94WRdHr8LPVet+C5/1Nzei399w/jr3+kzT4pDKk26JF/tlI5elpQ==", + "version": "1.20260415.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260415.1.tgz", + "integrity": "sha512-4NuMLlerI0Ijua3Ir8HXQ+qyNvCUDEG5gDco5Om+sAiK6rnWiz+aGoSlbB8W16yW9QAgzCstbmXLiVknUBflfQ==", "cpu": [ "x64" ], @@ -435,9 +435,9 @@ } }, "node_modules/@conventional-changelog/git-client": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.6.0.tgz", - "integrity": "sha512-T+uPDciKf0/ioNNDpMGc8FDsehJClZP0yR3Q5MN6wE/Y/1QZ7F+80OgznnTCOlMEG4AV0LvH2UJi3C/nBnaBUg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.7.0.tgz", + "integrity": "sha512-j7A8/LBEQ+3rugMzPXoKYzyUPpw/0CBQCyvtTR7Lmu4olG4yRC/Tfkq79Mr3yuPs0SUitlO2HwGP3gitMJnRFw==", "dev": true, "license": "MIT", "dependencies": { @@ -450,7 +450,7 @@ }, "peerDependencies": { "conventional-commits-filter": "^5.0.0", - "conventional-commits-parser": "^6.3.0" + "conventional-commits-parser": "^6.4.0" }, "peerDependenciesMeta": { "conventional-commits-filter": { @@ -529,9 +529,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", - "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, "license": "MIT", "optional": true, @@ -540,9 +540,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", - "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", "cpu": [ "ppc64" ], @@ -557,9 +557,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", - "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", "cpu": [ "arm" ], @@ -574,9 +574,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", - "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", "cpu": [ "arm64" ], @@ -591,9 +591,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", - "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", "cpu": [ "x64" ], @@ -608,9 +608,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", - "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", "cpu": [ "arm64" ], @@ -625,9 +625,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", - "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", "cpu": [ "x64" ], @@ -642,9 +642,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", - "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", "cpu": [ "arm64" ], @@ -659,9 +659,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", - "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", "cpu": [ "x64" ], @@ -676,9 +676,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", - "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", "cpu": [ "arm" ], @@ -693,9 +693,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", - "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", "cpu": [ "arm64" ], @@ -710,9 +710,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", - "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", "cpu": [ "ia32" ], @@ -727,9 +727,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", - "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", "cpu": [ "loong64" ], @@ -744,9 +744,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", - "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", "cpu": [ "mips64el" ], @@ -761,9 +761,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", - "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", "cpu": [ "ppc64" ], @@ -778,9 +778,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", - "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", "cpu": [ "riscv64" ], @@ -795,9 +795,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", - "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", "cpu": [ "s390x" ], @@ -812,9 +812,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", - "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", "cpu": [ "x64" ], @@ -829,9 +829,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", - "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", "cpu": [ "arm64" ], @@ -846,9 +846,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", - "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", "cpu": [ "x64" ], @@ -863,9 +863,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", - "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", "cpu": [ "arm64" ], @@ -880,9 +880,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", - "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", "cpu": [ "x64" ], @@ -897,9 +897,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", - "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", "cpu": [ "arm64" ], @@ -914,9 +914,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", - "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", "cpu": [ "x64" ], @@ -931,9 +931,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", - "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", "cpu": [ "arm64" ], @@ -948,9 +948,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", - "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", "cpu": [ "ia32" ], @@ -965,9 +965,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", - "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", "cpu": [ "x64" ], @@ -1520,9 +1520,9 @@ } }, "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", "dev": true, "license": "MIT", "engines": { @@ -1568,13 +1568,25 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@noble/ciphers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.2.0.tgz", + "integrity": "sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@noble/curves": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz", - "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.2.0.tgz", + "integrity": "sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==", "license": "MIT", "dependencies": { - "@noble/hashes": "2.0.1" + "@noble/hashes": "2.2.0" }, "engines": { "node": ">= 20.19.0" @@ -1584,9 +1596,9 @@ } }, "node_modules/@noble/hashes": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", - "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", + "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", "license": "MIT", "engines": { "node": ">= 20.19.0" @@ -1596,13 +1608,14 @@ } }, "node_modules/@noble/post-quantum": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@noble/post-quantum/-/post-quantum-0.5.4.tgz", - "integrity": "sha512-leww0zzIirrvwaYMPI9fj6aRIlA/c6Y0/lifQQ1YOOyHEr0MNH3yYpjXeiVG+tWdPps4XxGclFWX2INPO3Yo5w==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@noble/post-quantum/-/post-quantum-0.6.1.tgz", + "integrity": "sha512-+pormrDZwjRw05U8ADK4JpHejo87+gBd+muRBB/ozztH5yhDLMDF4jHQWN3NQQAsu1zBNPWTG0ZwVI0CR29H0A==", "license": "MIT", "dependencies": { - "@noble/curves": "~2.0.0", - "@noble/hashes": "~2.0.0" + "@noble/ciphers": "~2.2.0", + "@noble/curves": "~2.2.0", + "@noble/hashes": "~2.2.0" }, "engines": { "node": ">= 20.19.0" @@ -1650,13 +1663,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.58.2", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz", - "integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==", + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.1.tgz", + "integrity": "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.58.2" + "playwright": "1.59.1" }, "bin": { "playwright": "cli.js" @@ -1708,9 +1721,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.0.tgz", - "integrity": "sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz", + "integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==", "cpu": [ "arm" ], @@ -1722,9 +1735,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.0.tgz", - "integrity": "sha512-u6JHLll5QKRvjciE78bQXDmqRqNs5M/3GVqZeMwvmjaNODJih/WIrJlFVEihvV0MiYFmd+ZyPr9wxOVbPAG2Iw==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz", + "integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==", "cpu": [ "arm64" ], @@ -1736,9 +1749,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.0.tgz", - "integrity": "sha512-qEF7CsKKzSRc20Ciu2Zw1wRrBz4g56F7r/vRwY430UPp/nt1x21Q/fpJ9N5l47WWvJlkNCPJz3QRVw008fi7yA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz", + "integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==", "cpu": [ "arm64" ], @@ -1750,9 +1763,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.0.tgz", - "integrity": "sha512-WADYozJ4QCnXCH4wPB+3FuGmDPoFseVCUrANmA5LWwGmC6FL14BWC7pcq+FstOZv3baGX65tZ378uT6WG8ynTw==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz", + "integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==", "cpu": [ "x64" ], @@ -1764,9 +1777,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.0.tgz", - "integrity": "sha512-6b8wGHJlDrGeSE3aH5mGNHBjA0TTkxdoNHik5EkvPHCt351XnigA4pS7Wsj/Eo9Y8RBU6f35cjN9SYmCFBtzxw==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz", + "integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==", "cpu": [ "arm64" ], @@ -1778,9 +1791,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.0.tgz", - "integrity": "sha512-h25Ga0t4jaylMB8M/JKAyrvvfxGRjnPQIR8lnCayyzEjEOx2EJIlIiMbhpWxDRKGKF8jbNH01NnN663dH638mA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz", + "integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==", "cpu": [ "x64" ], @@ -1792,9 +1805,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.0.tgz", - "integrity": "sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz", + "integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==", "cpu": [ "arm" ], @@ -1809,9 +1822,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.0.tgz", - "integrity": "sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz", + "integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==", "cpu": [ "arm" ], @@ -1826,9 +1839,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.0.tgz", - "integrity": "sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz", + "integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==", "cpu": [ "arm64" ], @@ -1843,9 +1856,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.0.tgz", - "integrity": "sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz", + "integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==", "cpu": [ "arm64" ], @@ -1860,9 +1873,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.0.tgz", - "integrity": "sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz", + "integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==", "cpu": [ "loong64" ], @@ -1877,9 +1890,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.0.tgz", - "integrity": "sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz", + "integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==", "cpu": [ "loong64" ], @@ -1894,9 +1907,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.0.tgz", - "integrity": "sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz", + "integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==", "cpu": [ "ppc64" ], @@ -1911,9 +1924,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.0.tgz", - "integrity": "sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz", + "integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==", "cpu": [ "ppc64" ], @@ -1928,9 +1941,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.0.tgz", - "integrity": "sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz", + "integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==", "cpu": [ "riscv64" ], @@ -1945,9 +1958,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.0.tgz", - "integrity": "sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz", + "integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==", "cpu": [ "riscv64" ], @@ -1962,9 +1975,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.0.tgz", - "integrity": "sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz", + "integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==", "cpu": [ "s390x" ], @@ -1979,9 +1992,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.0.tgz", - "integrity": "sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz", + "integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==", "cpu": [ "x64" ], @@ -1996,9 +2009,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.0.tgz", - "integrity": "sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz", + "integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==", "cpu": [ "x64" ], @@ -2013,9 +2026,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.0.tgz", - "integrity": "sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz", + "integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==", "cpu": [ "x64" ], @@ -2027,9 +2040,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.0.tgz", - "integrity": "sha512-pESDkos/PDzYwtyzB5p/UoNU/8fJo68vcXM9ZW2V0kjYayj1KaaUfi1NmTUTUpMn4UhU4gTuK8gIaFO4UGuMbA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz", + "integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==", "cpu": [ "arm64" ], @@ -2041,9 +2054,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.0.tgz", - "integrity": "sha512-hj1wFStD7B1YBeYmvY+lWXZ7ey73YGPcViMShYikqKT1GtstIKQAtfUI6yrzPjAy/O7pO0VLXGmUVWXQMaYgTQ==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz", + "integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==", "cpu": [ "arm64" ], @@ -2055,9 +2068,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.0.tgz", - "integrity": "sha512-SyaIPFoxmUPlNDq5EHkTbiKzmSEmq/gOYFI/3HHJ8iS/v1mbugVa7dXUzcJGQfoytp9DJFLhHH4U3/eTy2Bq4w==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz", + "integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==", "cpu": [ "ia32" ], @@ -2069,9 +2082,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.0.tgz", - "integrity": "sha512-RdcryEfzZr+lAr5kRm2ucN9aVlCCa2QNq4hXelZxb8GG0NJSazq44Z3PCCc8wISRuCVnGs0lQJVX5Vp6fKA+IA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz", + "integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==", "cpu": [ "x64" ], @@ -2083,9 +2096,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.0.tgz", - "integrity": "sha512-PrsWNQ8BuE00O3Xsx3ALh2Df8fAj9+cvvX9AIA6o4KpATR98c9mud4XtDWVvsEuyia5U4tVSTKygawyJkjm60w==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz", + "integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==", "cpu": [ "x64" ], @@ -2169,13 +2182,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", - "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.18.0" + "undici-types": "~7.19.0" } }, "node_modules/acorn": { @@ -2468,9 +2481,9 @@ } }, "node_modules/conventional-changelog-angular": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.3.0.tgz", - "integrity": "sha512-DOuBwYSqWzfwuRByY9O4oOIvDlkUCTDzfbOgcSbkY+imXXj+4tmrEFao3K+FxemClYfYnZzsvudbwrhje9VHDA==", + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.3.1.tgz", + "integrity": "sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==", "dev": true, "license": "ISC", "dependencies": { @@ -2481,9 +2494,9 @@ } }, "node_modules/conventional-changelog-conventionalcommits": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.3.0.tgz", - "integrity": "sha512-kYFx6gAyjSIMwNtASkI3ZE99U1fuVDJr0yTYgVy+I2QG46zNZfl2her+0+eoviG82c5WQvW1jMt1eOQTeJLodA==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.3.1.tgz", + "integrity": "sha512-dTYtpIacRpcZgrvBYvBfArMmK2xvIpv2TaxM0/ZI5CBtNUzvF2x0t15HsbRABWprS6UPmvj+PzHVjSx4qAVKyw==", "dev": true, "license": "ISC", "dependencies": { @@ -2494,9 +2507,9 @@ } }, "node_modules/conventional-commits-parser": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.3.0.tgz", - "integrity": "sha512-RfOq/Cqy9xV9bOA8N+ZH6DlrDR+5S3Mi0B5kACEjESpE+AviIpAptx9a9cFpWCCvgRtWT+0BbUw+e1BZfts9jg==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.4.0.tgz", + "integrity": "sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw==", "dev": true, "license": "MIT", "dependencies": { @@ -2569,13 +2582,13 @@ } }, "node_modules/cosmiconfig-typescript-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.2.0.tgz", - "integrity": "sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.3.0.tgz", + "integrity": "sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==", "dev": true, "license": "MIT", "dependencies": { - "jiti": "^2.6.1" + "jiti": "2.6.1" }, "engines": { "node": ">=v18" @@ -2704,9 +2717,9 @@ } }, "node_modules/esbuild": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", - "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2717,32 +2730,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.4", - "@esbuild/android-arm": "0.27.4", - "@esbuild/android-arm64": "0.27.4", - "@esbuild/android-x64": "0.27.4", - "@esbuild/darwin-arm64": "0.27.4", - "@esbuild/darwin-x64": "0.27.4", - "@esbuild/freebsd-arm64": "0.27.4", - "@esbuild/freebsd-x64": "0.27.4", - "@esbuild/linux-arm": "0.27.4", - "@esbuild/linux-arm64": "0.27.4", - "@esbuild/linux-ia32": "0.27.4", - "@esbuild/linux-loong64": "0.27.4", - "@esbuild/linux-mips64el": "0.27.4", - "@esbuild/linux-ppc64": "0.27.4", - "@esbuild/linux-riscv64": "0.27.4", - "@esbuild/linux-s390x": "0.27.4", - "@esbuild/linux-x64": "0.27.4", - "@esbuild/netbsd-arm64": "0.27.4", - "@esbuild/netbsd-x64": "0.27.4", - "@esbuild/openbsd-arm64": "0.27.4", - "@esbuild/openbsd-x64": "0.27.4", - "@esbuild/openharmony-arm64": "0.27.4", - "@esbuild/sunos-x64": "0.27.4", - "@esbuild/win32-arm64": "0.27.4", - "@esbuild/win32-ia32": "0.27.4", - "@esbuild/win32-x64": "0.27.4" + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" } }, "node_modules/escalade": { @@ -2891,9 +2904,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.13.7", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", - "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", "dev": true, "license": "MIT", "dependencies": { @@ -3320,9 +3333,9 @@ "license": "MIT" }, "node_modules/lru-cache": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -3393,16 +3406,16 @@ } }, "node_modules/miniflare": { - "version": "4.20260317.3", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260317.3.tgz", - "integrity": "sha512-tK78D3X4q30/SXqVwMhWrUfH+ffRou9dJLC+jkhNy5zh1I7i7T4JH6xihOvYxdCSBavJ5fQXaaxDJz6orh09BA==", + "version": "4.20260415.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260415.0.tgz", + "integrity": "sha512-JoExRWN4YBI2luA5BoSMFEgi8rQWXUGzo3mtE+58VXCLV3jj/Xnk5Yeqs/IXWz8Es5GJIaq6BtsixDvAxXSIng==", "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "^0.34.5", - "undici": "7.24.4", - "workerd": "1.20260317.1", + "undici": "7.24.8", + "workerd": "1.20260415.1", "ws": "8.18.0", "youch": "4.1.0-beta.10" }, @@ -3414,13 +3427,13 @@ } }, "node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -3669,13 +3682,13 @@ } }, "node_modules/playwright": { - "version": "1.58.2", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", - "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz", + "integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.58.2" + "playwright-core": "1.59.1" }, "bin": { "playwright": "cli.js" @@ -3688,9 +3701,9 @@ } }, "node_modules/playwright-core": { - "version": "1.58.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", - "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz", + "integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3744,9 +3757,9 @@ } }, "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", "dev": true, "license": "MIT", "bin": { @@ -3862,9 +3875,9 @@ } }, "node_modules/rollup": { - "version": "4.60.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.0.tgz", - "integrity": "sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", + "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", "dev": true, "license": "MIT", "dependencies": { @@ -3878,31 +3891,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.60.0", - "@rollup/rollup-android-arm64": "4.60.0", - "@rollup/rollup-darwin-arm64": "4.60.0", - "@rollup/rollup-darwin-x64": "4.60.0", - "@rollup/rollup-freebsd-arm64": "4.60.0", - "@rollup/rollup-freebsd-x64": "4.60.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.60.0", - "@rollup/rollup-linux-arm-musleabihf": "4.60.0", - "@rollup/rollup-linux-arm64-gnu": "4.60.0", - "@rollup/rollup-linux-arm64-musl": "4.60.0", - "@rollup/rollup-linux-loong64-gnu": "4.60.0", - "@rollup/rollup-linux-loong64-musl": "4.60.0", - "@rollup/rollup-linux-ppc64-gnu": "4.60.0", - "@rollup/rollup-linux-ppc64-musl": "4.60.0", - "@rollup/rollup-linux-riscv64-gnu": "4.60.0", - "@rollup/rollup-linux-riscv64-musl": "4.60.0", - "@rollup/rollup-linux-s390x-gnu": "4.60.0", - "@rollup/rollup-linux-x64-gnu": "4.60.0", - "@rollup/rollup-linux-x64-musl": "4.60.0", - "@rollup/rollup-openbsd-x64": "4.60.0", - "@rollup/rollup-openharmony-arm64": "4.60.0", - "@rollup/rollup-win32-arm64-msvc": "4.60.0", - "@rollup/rollup-win32-ia32-msvc": "4.60.0", - "@rollup/rollup-win32-x64-gnu": "4.60.0", - "@rollup/rollup-win32-x64-msvc": "4.60.0", + "@rollup/rollup-android-arm-eabi": "4.60.1", + "@rollup/rollup-android-arm64": "4.60.1", + "@rollup/rollup-darwin-arm64": "4.60.1", + "@rollup/rollup-darwin-x64": "4.60.1", + "@rollup/rollup-freebsd-arm64": "4.60.1", + "@rollup/rollup-freebsd-x64": "4.60.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", + "@rollup/rollup-linux-arm-musleabihf": "4.60.1", + "@rollup/rollup-linux-arm64-gnu": "4.60.1", + "@rollup/rollup-linux-arm64-musl": "4.60.1", + "@rollup/rollup-linux-loong64-gnu": "4.60.1", + "@rollup/rollup-linux-loong64-musl": "4.60.1", + "@rollup/rollup-linux-ppc64-gnu": "4.60.1", + "@rollup/rollup-linux-ppc64-musl": "4.60.1", + "@rollup/rollup-linux-riscv64-gnu": "4.60.1", + "@rollup/rollup-linux-riscv64-musl": "4.60.1", + "@rollup/rollup-linux-s390x-gnu": "4.60.1", + "@rollup/rollup-linux-x64-gnu": "4.60.1", + "@rollup/rollup-linux-x64-musl": "4.60.1", + "@rollup/rollup-openbsd-x64": "4.60.1", + "@rollup/rollup-openharmony-arm64": "4.60.1", + "@rollup/rollup-win32-arm64-msvc": "4.60.1", + "@rollup/rollup-win32-ia32-msvc": "4.60.1", + "@rollup/rollup-win32-x64-gnu": "4.60.1", + "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" } }, @@ -4153,9 +4166,9 @@ } }, "node_modules/tinyexec": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz", - "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", + "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", "dev": true, "license": "MIT", "engines": { @@ -4163,14 +4176,14 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -4365,9 +4378,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.4.tgz", - "integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.8.tgz", + "integrity": "sha512-6KQ/+QxK49Z/p3HO6E5ZCZWNnCasyZLa5ExaVYyvPxUwKtbCPMKELJOqh7EqOle0t9cH/7d2TaaTRRa6Nhs4YQ==", "dev": true, "license": "MIT", "engines": { @@ -4375,9 +4388,9 @@ } }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "dev": true, "license": "MIT" }, @@ -4423,9 +4436,9 @@ } }, "node_modules/workerd": { - "version": "1.20260317.1", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260317.1.tgz", - "integrity": "sha512-ZuEq1OdrJBS+NV+L5HMYPCzVn49a2O60slQiiLpG44jqtlOo+S167fWC76kEXteXLLLydeuRrluRel7WdOUa4g==", + "version": "1.20260415.1", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260415.1.tgz", + "integrity": "sha512-phyPjRnx+mQDfkhN9ENPioL1L0SdhYs4S0YmJK/xF9Oga+ykNfdSy1MHnsOj8yqnOV96zcVQMx32dJ0r3pq0jQ==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -4436,17 +4449,17 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20260317.1", - "@cloudflare/workerd-darwin-arm64": "1.20260317.1", - "@cloudflare/workerd-linux-64": "1.20260317.1", - "@cloudflare/workerd-linux-arm64": "1.20260317.1", - "@cloudflare/workerd-windows-64": "1.20260317.1" + "@cloudflare/workerd-darwin-64": "1.20260415.1", + "@cloudflare/workerd-darwin-arm64": "1.20260415.1", + "@cloudflare/workerd-linux-64": "1.20260415.1", + "@cloudflare/workerd-linux-arm64": "1.20260415.1", + "@cloudflare/workerd-windows-64": "1.20260415.1" } }, "node_modules/wrangler": { - "version": "4.78.0", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.78.0.tgz", - "integrity": "sha512-He/vUhk4ih0D0eFmtNnlbT6Od8j+BEokaSR+oYjbVsH0SWIrIch+eHqfLRSBjBQaOoh6HCNxcafcIkBm2u0Hag==", + "version": "4.83.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.83.0.tgz", + "integrity": "sha512-gw5g3LCiuAqVWxaoKY6+quE0HzAUEFb/FV3oAlNkE1ttd4XP3FiV91XDkkzUCcdqxS4WjhQvPhIDBNdhEi8P0A==", "dev": true, "license": "MIT OR Apache-2.0", "dependencies": { @@ -4454,10 +4467,10 @@ "@cloudflare/unenv-preset": "2.16.0", "blake3-wasm": "2.1.5", "esbuild": "0.27.3", - "miniflare": "4.20260317.3", + "miniflare": "4.20260415.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", - "workerd": "1.20260317.1" + "workerd": "1.20260415.1" }, "bin": { "wrangler": "bin/wrangler.js", @@ -4470,7 +4483,7 @@ "fsevents": "~2.3.2" }, "peerDependencies": { - "@cloudflare/workers-types": "^4.20260317.1" + "@cloudflare/workers-types": "^4.20260415.1" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { diff --git a/package.json b/package.json index 9eb9d47..eaccc0a 100644 --- a/package.json +++ b/package.json @@ -84,24 +84,24 @@ }, "homepage": "https://github.com/sovereignbase/cryptosuite#readme", "dependencies": { - "@noble/post-quantum": "^0.5.4", + "@noble/post-quantum": "^0.6.1", "@sovereignbase/bytecodec": "^1.5.1" }, "devDependencies": { "@commitlint/cli": "^20.5.0", "@commitlint/config-conventional": "^20.5.0", - "@playwright/test": "^1.58.2", - "@types/node": "^25.5.0", + "@playwright/test": "^1.59.1", + "@types/node": "^25.6.0", "c8": "^11.0.0", "edge-runtime": "^4.0.1", "fast-glob": "^3.3.3", "husky": "^9.1.7", - "playwright": "^1.58.2", - "prettier": "^3.8.1", + "playwright": "^1.59.1", + "prettier": "^3.8.3", "tsup": "^8.5.1", "tsx": "^4.21.0", "typescript": "^5.9.3", - "wrangler": "^4.78.0" + "wrangler": "^4.83.0" }, "engines": { "node": ">=20" diff --git a/tsup.config.ts b/tsup.config.ts index 1dc320a..aa3e3ca 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -1,5 +1,23 @@ import { defineConfig } from 'tsup' +const apache2Banner = [ + '/*', + ` * Copyright ${new Date().getUTCFullYear()} Sovereignbase`, + ' *', + ' * Licensed under the Apache License, Version 2.0 (the "License");', + ' * you may not use this file except in compliance with the License.', + ' * You may obtain a copy of the License at', + ' *', + ' * http://www.apache.org/licenses/LICENSE-2.0', + ' *', + ' * Unless required by applicable law or agreed to in writing, software', + ' * distributed under the License is distributed on an "AS IS" BASIS,', + ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.', + ' * See the License for the specific language governing permissions and', + ' * limitations under the License.', + ' */', +].join('\n') + export default defineConfig({ entry: ['src/index.ts'], format: ['esm', 'cjs'], @@ -10,6 +28,9 @@ export default defineConfig({ sourcemap: true, clean: true, splitting: true, + banner: { + js: `${apache2Banner}\n`, + }, external: [], outExtension({ format }) { return { js: format === 'cjs' ? '.cjs' : '.js' } From feb61af099cc640dbbab966fa843ffa156008974 Mon Sep 17 00:00:00 2001 From: Jori Lethinen Date: Fri, 17 Apr 2026 18:07:02 +0300 Subject: [PATCH 2/2] feat: add hybrid Ed25519-ML-DSA-65 signatures and X25519-ML-KEM-768 key agreement --- README.md | 67 ++--- benchmark/bench.js | 251 +++++++++++------- .../.core/SignKeyHarness/class.ts | 2 +- .../.core/VerifyKeyHarness/class.ts | 2 +- .../index.ts | 16 +- .../.core/helpers/getParamsByAlgCode/index.ts | 1 + .../helpers/validateKeyByAlgCode/index.ts | 16 +- src/DigitalSignature/.core/types/index.ts | 34 ++- src/DigitalSignature/README.md | 2 +- .../deriveDigitalSignatureKeypair/index.ts | 13 +- .../generateDigitalSignatureKeypair/index.ts | 9 +- .../index.ts | 6 +- .../.core/helpers/getParamsByAlgCode/index.ts | 1 + .../helpers/validateKeyByAlgCode/index.ts | 16 +- src/KeyAgreement/.core/types/index.ts | 42 +-- src/KeyAgreement/README.md | 5 +- .../deriveKeyAgreementKeypair/index.ts | 13 +- .../generateKeyAgreementKeypair/index.ts | 9 +- test/e2e/runtime-suite.mjs | 16 +- test/integration/integration.test.mjs | 6 +- test/support/fixtures.mjs | 59 +++- test/unit/digitalSignature.test.mjs | 42 +-- test/unit/keyAgreement.test.mjs | 2 +- test/unit/source-digitalSignature.test.mjs | 101 +++++-- test/unit/source-keyAgreement.test.mjs | 102 ++++++- 25 files changed, 539 insertions(+), 294 deletions(-) diff --git a/README.md b/README.md index fb2be74..adea7e0 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,8 @@ JS/TS runtime-agnostic, quantum-safe, and agile cryptography toolkit with a decl - Identifier: `SHA-384` or 48 random bytes, encoded as a fixed-length base64url string - Cipher messaging: `AES-CTR-256` - Message authentication: `HMAC-SHA-256` -- Key agreement: `ML-KEM-1024` -- Digital signatures: `ML-DSA-87` +- Key agreement: `X25519-ML-KEM-768` +- Digital signatures: `Ed25519-ML-DSA-65` ## Installation @@ -126,7 +126,7 @@ const verified = await Cryptographic.messageAuthentication.verify( import { Cryptographic } from '@sovereignbase/cryptosuite' import { Bytes } from '@sovereignbase/bytecodec' -const sourceKeyMaterial = Bytes.fromString('k'.repeat(64)) // Uint8Array, exactly 64 bytes +const sourceKeyMaterial = Bytes.fromString('k'.repeat(32)) // Uint8Array, exactly 32 bytes const { encapsulateKey, decapsulateKey } = await Cryptographic.keyAgreement.generateKeypair() // {encapsulateKey: JsonWebKey, decapsulateKey: JsonWebKey} @@ -147,7 +147,7 @@ const { cipherKey: receiverCipherKey } = import { Cryptographic } from '@sovereignbase/cryptosuite' import { Bytes } from '@sovereignbase/bytecodec' -const sourceKeyMaterial = Bytes.fromString('s'.repeat(32)) // Uint8Array, exactly 32 bytes +const sourceKeyMaterial = Bytes.fromString('s'.repeat(64)) // Uint8Array, exactly 64 bytes const bytes = Bytes.fromString('signed payload') // Uint8Array const { signKey, verifyKey } = await Cryptographic.digitalSignature.generateKeypair() // {signKey: JsonWebKey, verifyKey: JsonWebKey} @@ -167,7 +167,7 @@ const verified = await Cryptographic.digitalSignature.verify( - `identifier.generate()` requires `crypto.getRandomValues` - symmetric operations use WebCrypto -- key agreement and digital signatures use `@noble/post-quantum` +- key agreement and digital signatures use `noble` hybrid primitives - unsupported crypto primitives throw typed `CryptosuiteError` codes ## Security notes @@ -180,15 +180,18 @@ const verified = await Cryptographic.digitalSignature.verify( ## Tests -- Unit + integration tests run against the built artifact -- Coverage targets `dist/index.cjs` and is enforced at `100%` -- E2E runtime suites currently run in: +Latest local `npm run test` run on `2026-04-17` with Node `v22.14.0 (win32 x64)`: + +- `63/63` tests passed +- Coverage passed at `100%` for statements, branches, functions, and lines +- End-to-end runtime suites all passed in: - Node ESM - Node CJS - Bun ESM - Bun CJS - Deno ESM - Edge Runtime ESM + - Cloudflare Workers ESM - Chromium - Firefox - WebKit @@ -200,31 +203,29 @@ const verified = await Cryptographic.digitalSignature.verify( ## Benchmarks -Latest local `npm run bench` run on 2026-03-24 with Node `v22.14.0 (win32 x64)`: - -| Benchmark | Result | -| ----------------------------------- | --------------------------- | -| `identifier.generate` | `3.50ms (57206.6 ops/sec)` | -| `identifier.derive` | `13.94ms (14349.8 ops/sec)` | -| `identifier.validate` | `0.33ms (609942.1 ops/sec)` | -| `cipherMessage.generateKey` | `23.03ms (8682.6 ops/sec)` | -| `cipherMessage.deriveKey` | `49.73ms (4021.6 ops/sec)` | -| `cipherMessage.encrypt` | `20.91ms (9566.5 ops/sec)` | -| `cipherMessage.decrypt` | `19.18ms (10425.0 ops/sec)` | -| `messageAuthentication.generateKey` | `24.58ms (8135.2 ops/sec)` | -| `messageAuthentication.deriveKey` | `12.51ms (15987.5 ops/sec)` | -| `messageAuthentication.sign` | `12.94ms (15460.4 ops/sec)` | -| `messageAuthentication.verify` | `14.96ms (13365.2 ops/sec)` | -| `keyAgreement.generateKeypair` | `43.89ms (455.7 ops/sec)` | -| `keyAgreement.deriveKeypair` | `35.21ms (568.1 ops/sec)` | -| `keyAgreement.encapsulate` | `43.76ms (457.0 ops/sec)` | -| `keyAgreement.decapsulate` | `45.16ms (442.9 ops/sec)` | -| `digitalSignature.generateKeypair` | `165.49ms (120.8 ops/sec)` | -| `digitalSignature.deriveKeypair` | `153.20ms (130.6 ops/sec)` | -| `digitalSignature.sign` | `431.41ms (46.4 ops/sec)` | -| `digitalSignature.verify` | `155.20ms (128.9 ops/sec)` | - -Command: `npm run bench` +Latest local `npm run bench` run on `2026-04-17` with Node `v22.14.0 (win32 x64)`. + +| Benchmark | ops | ms | ms/op | ops/sec | +| ----------------------------------- | --: | ------: | ------: | --------: | +| `identifier.generate` | 100 | 3.76 | 0.0376 | 26617.69 | +| `identifier.derive` | 100 | 32.60 | 0.3260 | 3067.77 | +| `identifier.validate` | 100 | 0.43 | 0.0043 | 232883.09 | +| `cipherMessage.generateKey` | 100 | 43.36 | 0.4336 | 2306.01 | +| `cipherMessage.deriveKey` | 100 | 75.53 | 0.7553 | 1324.01 | +| `cipherMessage.encrypt` | 100 | 38.18 | 0.3818 | 2619.10 | +| `cipherMessage.decrypt` | 100 | 30.86 | 0.3086 | 3240.51 | +| `messageAuthentication.generateKey` | 100 | 42.06 | 0.4206 | 2377.45 | +| `messageAuthentication.deriveKey` | 100 | 67.14 | 0.6714 | 1489.35 | +| `messageAuthentication.sign` | 100 | 26.91 | 0.2691 | 3716.46 | +| `messageAuthentication.verify` | 100 | 28.26 | 0.2826 | 3538.58 | +| `keyAgreement.generateKeypair` | 100 | 877.66 | 8.7766 | 113.94 | +| `keyAgreement.deriveKeypair` | 100 | 728.01 | 7.2801 | 137.36 | +| `keyAgreement.encapsulate` | 100 | 1649.16 | 16.4916 | 60.64 | +| `keyAgreement.decapsulate` | 100 | 1093.07 | 10.9307 | 91.49 | +| `digitalSignature.generateKeypair` | 100 | 849.80 | 8.4980 | 117.67 | +| `digitalSignature.deriveKeypair` | 100 | 714.64 | 7.1464 | 139.93 | +| `digitalSignature.sign` | 100 | 3293.13 | 32.9313 | 30.37 | +| `digitalSignature.verify` | 100 | 1195.09 | 11.9509 | 83.68 | Results vary by machine and Node version. diff --git a/benchmark/bench.js b/benchmark/bench.js index f6e6440..0ffbf7c 100644 --- a/benchmark/bench.js +++ b/benchmark/bench.js @@ -1,22 +1,29 @@ import { performance } from 'node:perf_hooks' -import { ml_dsa87 } from '@noble/post-quantum/ml-dsa.js' -import { ml_kem1024 } from '@noble/post-quantum/ml-kem.js' +import { ed25519 } from '@noble/curves/ed25519.js' +import { + combineSigners, + ecSigner, + ml_kem768_x25519, +} from '@noble/post-quantum/hybrid.js' +import { ml_dsa65 } from '@noble/post-quantum/ml-dsa.js' import { Cryptographic } from '../dist/index.js' const encoder = new TextEncoder() -const fastIterationsArg = process.argv.find((arg) => +const iterationsArg = process.argv.find((arg) => arg.startsWith('--iterations=') ) -const slowIterationsArg = process.argv.find((arg) => - arg.startsWith('--slow-iterations=') -) +const iterations = iterationsArg ? Number(iterationsArg.split('=')[1]) : 100 + +if (!Number.isInteger(iterations) || iterations <= 0) { + throw new Error('benchmark iterations must be a positive integer.') +} -const fastIterations = fastIterationsArg - ? Number(fastIterationsArg.split('=')[1]) - : 200 -const slowIterations = slowIterationsArg - ? Number(slowIterationsArg.split('=')[1]) - : Math.max(10, Math.floor(fastIterations / 10)) +const ed25519MlDsa65 = combineSigners( + undefined, + (seed) => seed, + ecSigner(ed25519), + ml_dsa65 +) function createBytes(length, offset = 0) { const bytes = new Uint8Array(length) @@ -26,21 +33,39 @@ function createBytes(length, offset = 0) { return bytes } -function formatOps(durationMs, count) { - const opsPerSec = count / (durationMs / 1000) - return `${durationMs.toFixed(2)}ms (${opsPerSec.toFixed(1)} ops/sec)` +function formatNumber(value, fractionDigits) { + return value.toFixed(fractionDigits) } -async function runBenchmark(label, count, fn) { +async function measure(label, ops, fn) { await fn() const startedAt = performance.now() - for (let index = 0; index < count; index += 1) { + for (let index = 0; index < ops; index += 1) { await fn() } const durationMs = performance.now() - startedAt - console.log(`${label}: ${formatOps(durationMs, count)}`) + return { + label, + ops, + ms: durationMs, + msPerOp: durationMs / ops, + opsPerSec: ops / (durationMs / 1000), + } +} + +function printTable(results) { + console.log(`Iterations: ${iterations}`) + console.log('') + console.log('| Benchmark | ops | ms | ms/op | ops/sec |') + console.log('| --- | ---: | ---: | ---: | ---: |') + + for (const result of results) { + console.log( + `| \`${result.label}\` | ${result.ops} | ${formatNumber(result.ms, 2)} | ${formatNumber(result.msPerOp, 4)} | ${formatNumber(result.opsPerSec, 2)} |` + ) + } } const identifierBytes = encoder.encode('cryptosuite benchmark identifier') @@ -57,37 +82,49 @@ const messageAuthenticationSalt = createBytes(16, 19) const messageAuthenticationBytes = encoder.encode( 'cryptosuite benchmark authentication payload' ) -const keyAgreementSeed = createBytes(ml_kem1024.lengths.seed, 29) -const digitalSignatureSeed = createBytes(ml_dsa87.lengths.seed, 43) +const keyAgreementSeed = createBytes(ml_kem768_x25519.lengths.seed, 29) +const digitalSignatureSeed = createBytes(ed25519MlDsa65.lengths.seed, 43) const digitalSignatureBytes = encoder.encode( 'cryptosuite benchmark signature payload' ) -console.log(`Iterations: fast=${fastIterations}, slow=${slowIterations}`) +const results = [] -await runBenchmark('identifier.generate', fastIterations, async () => { - await Cryptographic.identifier.generate() -}) +results.push( + await measure('identifier.generate', iterations, async () => { + await Cryptographic.identifier.generate() + }) +) -await runBenchmark('identifier.derive', fastIterations, async () => { - await Cryptographic.identifier.derive(identifierBytes) -}) +results.push( + await measure('identifier.derive', iterations, async () => { + await Cryptographic.identifier.derive(identifierBytes) + }) +) -await runBenchmark('identifier.validate', fastIterations, () => { - if (Cryptographic.identifier.validate(validIdentifier) !== validIdentifier) { - throw new Error('identifier.validate failed its benchmark invariant.') - } -}) +results.push( + await measure('identifier.validate', iterations, () => { + if ( + Cryptographic.identifier.validate(validIdentifier) !== validIdentifier + ) { + throw new Error('identifier.validate failed its benchmark invariant.') + } + }) +) -await runBenchmark('cipherMessage.generateKey', fastIterations, async () => { - await Cryptographic.cipherMessage.generateKey() -}) +results.push( + await measure('cipherMessage.generateKey', iterations, async () => { + await Cryptographic.cipherMessage.generateKey() + }) +) -await runBenchmark('cipherMessage.deriveKey', fastIterations, async () => { - await Cryptographic.cipherMessage.deriveKey(cipherDerivationSource, { - salt: cipherDerivationSalt, +results.push( + await measure('cipherMessage.deriveKey', iterations, async () => { + await Cryptographic.cipherMessage.deriveKey(cipherDerivationSource, { + salt: cipherDerivationSalt, + }) }) -}) +) { const cipherKey = await Cryptographic.cipherMessage.generateKey() @@ -96,32 +133,32 @@ await runBenchmark('cipherMessage.deriveKey', fastIterations, async () => { cipherPlaintext ) - await runBenchmark('cipherMessage.encrypt', fastIterations, async () => { - await Cryptographic.cipherMessage.encrypt(cipherKey, cipherPlaintext) - }) + results.push( + await measure('cipherMessage.encrypt', iterations, async () => { + await Cryptographic.cipherMessage.encrypt(cipherKey, cipherPlaintext) + }) + ) - await runBenchmark('cipherMessage.decrypt', fastIterations, async () => { - await Cryptographic.cipherMessage.decrypt(cipherKey, cipherMessage) - }) + results.push( + await measure('cipherMessage.decrypt', iterations, async () => { + await Cryptographic.cipherMessage.decrypt(cipherKey, cipherMessage) + }) + ) } -await runBenchmark( - 'messageAuthentication.generateKey', - fastIterations, - async () => { +results.push( + await measure('messageAuthentication.generateKey', iterations, async () => { await Cryptographic.messageAuthentication.generateKey() - } + }) ) -await runBenchmark( - 'messageAuthentication.deriveKey', - fastIterations, - async () => { +results.push( + await measure('messageAuthentication.deriveKey', iterations, async () => { await Cryptographic.messageAuthentication.deriveKey( messageAuthenticationSource, { salt: messageAuthenticationSalt } ) - } + }) ) { @@ -133,17 +170,17 @@ await runBenchmark( messageAuthenticationBytes ) - await runBenchmark('messageAuthentication.sign', fastIterations, async () => { - await Cryptographic.messageAuthentication.sign( - messageAuthenticationKey, - messageAuthenticationBytes - ) - }) + results.push( + await measure('messageAuthentication.sign', iterations, async () => { + await Cryptographic.messageAuthentication.sign( + messageAuthenticationKey, + messageAuthenticationBytes + ) + }) + ) - await runBenchmark( - 'messageAuthentication.verify', - fastIterations, - async () => { + results.push( + await measure('messageAuthentication.verify', iterations, async () => { const verified = await Cryptographic.messageAuthentication.verify( messageAuthenticationKey, messageAuthenticationBytes, @@ -154,17 +191,21 @@ await runBenchmark( 'messageAuthentication.verify failed its benchmark invariant.' ) } - } + }) ) } -await runBenchmark('keyAgreement.generateKeypair', slowIterations, async () => { - await Cryptographic.keyAgreement.generateKeypair() -}) +results.push( + await measure('keyAgreement.generateKeypair', iterations, async () => { + await Cryptographic.keyAgreement.generateKeypair() + }) +) -await runBenchmark('keyAgreement.deriveKeypair', slowIterations, async () => { - await Cryptographic.keyAgreement.deriveKeypair(keyAgreementSeed) -}) +results.push( + await measure('keyAgreement.deriveKeypair', iterations, async () => { + await Cryptographic.keyAgreement.deriveKeypair(keyAgreementSeed) + }) +) { const { encapsulateKey, decapsulateKey } = @@ -172,29 +213,29 @@ await runBenchmark('keyAgreement.deriveKeypair', slowIterations, async () => { const { keyOffer } = await Cryptographic.keyAgreement.encapsulate(encapsulateKey) - await runBenchmark('keyAgreement.encapsulate', slowIterations, async () => { - await Cryptographic.keyAgreement.encapsulate(encapsulateKey) - }) + results.push( + await measure('keyAgreement.encapsulate', iterations, async () => { + await Cryptographic.keyAgreement.encapsulate(encapsulateKey) + }) + ) - await runBenchmark('keyAgreement.decapsulate', slowIterations, async () => { - await Cryptographic.keyAgreement.decapsulate(keyOffer, decapsulateKey) - }) + results.push( + await measure('keyAgreement.decapsulate', iterations, async () => { + await Cryptographic.keyAgreement.decapsulate(keyOffer, decapsulateKey) + }) + ) } -await runBenchmark( - 'digitalSignature.generateKeypair', - slowIterations, - async () => { +results.push( + await measure('digitalSignature.generateKeypair', iterations, async () => { await Cryptographic.digitalSignature.generateKeypair() - } + }) ) -await runBenchmark( - 'digitalSignature.deriveKeypair', - slowIterations, - async () => { +results.push( + await measure('digitalSignature.deriveKeypair', iterations, async () => { await Cryptographic.digitalSignature.deriveKeypair(digitalSignatureSeed) - } + }) ) { @@ -205,18 +246,26 @@ await runBenchmark( digitalSignatureBytes ) - await runBenchmark('digitalSignature.sign', slowIterations, async () => { - await Cryptographic.digitalSignature.sign(signKey, digitalSignatureBytes) - }) + results.push( + await measure('digitalSignature.sign', iterations, async () => { + await Cryptographic.digitalSignature.sign(signKey, digitalSignatureBytes) + }) + ) - await runBenchmark('digitalSignature.verify', slowIterations, async () => { - const verified = await Cryptographic.digitalSignature.verify( - verifyKey, - digitalSignatureBytes, - signature - ) - if (verified !== true) { - throw new Error('digitalSignature.verify failed its benchmark invariant.') - } - }) + results.push( + await measure('digitalSignature.verify', iterations, async () => { + const verified = await Cryptographic.digitalSignature.verify( + verifyKey, + digitalSignatureBytes, + signature + ) + if (verified !== true) { + throw new Error( + 'digitalSignature.verify failed its benchmark invariant.' + ) + } + }) + ) } + +printTable(results) diff --git a/src/DigitalSignature/.core/SignKeyHarness/class.ts b/src/DigitalSignature/.core/SignKeyHarness/class.ts index dd982fa..2a34aa6 100644 --- a/src/DigitalSignature/.core/SignKeyHarness/class.ts +++ b/src/DigitalSignature/.core/SignKeyHarness/class.ts @@ -57,7 +57,7 @@ export class SignKeyHarness { } catch { throw new CryptosuiteError( 'ALGORITHM_UNSUPPORTED', - 'SignKeyHarness.sign: failed to sign with ML-DSA-87.' + `SignKeyHarness.sign: failed to sign with ${this.algCode}.` ) } } diff --git a/src/DigitalSignature/.core/VerifyKeyHarness/class.ts b/src/DigitalSignature/.core/VerifyKeyHarness/class.ts index 466ad8b..af42dce 100644 --- a/src/DigitalSignature/.core/VerifyKeyHarness/class.ts +++ b/src/DigitalSignature/.core/VerifyKeyHarness/class.ts @@ -59,7 +59,7 @@ export class VerifyKeyHarness { } catch { throw new CryptosuiteError( 'ALGORITHM_UNSUPPORTED', - 'VerifyKeyHarness.verify: failed to verify with ML-DSA-87.' + `VerifyKeyHarness.verify: failed to verify with ${this.algCode}.` ) } } diff --git a/src/DigitalSignature/.core/helpers/createImportKeyAlgorithmByAlgCode/index.ts b/src/DigitalSignature/.core/helpers/createImportKeyAlgorithmByAlgCode/index.ts index 1572545..f035aa3 100644 --- a/src/DigitalSignature/.core/helpers/createImportKeyAlgorithmByAlgCode/index.ts +++ b/src/DigitalSignature/.core/helpers/createImportKeyAlgorithmByAlgCode/index.ts @@ -13,16 +13,28 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import { ml_dsa87 } from '@noble/post-quantum/ml-dsa.js' +import { ed25519 } from '@noble/curves/ed25519.js' +import { combineSigners, ecSigner } from '@noble/post-quantum/hybrid.js' +import { ml_dsa65, ml_dsa87 } from '@noble/post-quantum/ml-dsa.js' +import type { Signer } from '@noble/post-quantum/utils.js' import { CryptosuiteError } from '../../../../.errors/class.js' import type { SignKey, VerifyKey } from '../../types/index.js' +const ed25519MlDsa65 = combineSigners( + undefined, + (seed) => seed, + ecSigner(ed25519), + ml_dsa65 +) + export function createImportKeyAlgorithmByAlgCode( algCode: SignKey['alg'] | VerifyKey['alg'] -): typeof ml_dsa87 { +): typeof ml_dsa87 | Signer { switch (algCode) { case 'ML-DSA-87': return ml_dsa87 + case 'Ed25519-ML-DSA-65': + return ed25519MlDsa65 } throw new CryptosuiteError( diff --git a/src/DigitalSignature/.core/helpers/getParamsByAlgCode/index.ts b/src/DigitalSignature/.core/helpers/getParamsByAlgCode/index.ts index aa0bf3f..2e94da8 100644 --- a/src/DigitalSignature/.core/helpers/getParamsByAlgCode/index.ts +++ b/src/DigitalSignature/.core/helpers/getParamsByAlgCode/index.ts @@ -26,6 +26,7 @@ export function getParamsByAlgCode( ): DigitalSignatureParams { switch (algCode) { case 'ML-DSA-87': + case 'Ed25519-ML-DSA-65': return params } diff --git a/src/DigitalSignature/.core/helpers/validateKeyByAlgCode/index.ts b/src/DigitalSignature/.core/helpers/validateKeyByAlgCode/index.ts index 9a49306..a73d087 100644 --- a/src/DigitalSignature/.core/helpers/validateKeyByAlgCode/index.ts +++ b/src/DigitalSignature/.core/helpers/validateKeyByAlgCode/index.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ import { fromBase64UrlString } from '@sovereignbase/bytecodec' -import { ml_dsa87 } from '@noble/post-quantum/ml-dsa.js' import { CryptosuiteError } from '../../../../.errors/class.js' +import { createImportKeyAlgorithmByAlgCode } from '../createImportKeyAlgorithmByAlgCode/index.js' import type { SignKey, VerifyKey } from '../../types/index.js' export function validateKeyByAlgCode(key: JsonWebKey): SignKey | VerifyKey { @@ -29,11 +29,13 @@ export function validateKeyByAlgCode(key: JsonWebKey): SignKey | VerifyKey { } switch (candidate.alg) { - case 'ML-DSA-87': { + case 'ML-DSA-87': + case 'Ed25519-ML-DSA-65': { + const algorithm = createImportKeyAlgorithmByAlgCode(candidate.alg) if (candidate.kty !== 'AKP') { throw new CryptosuiteError( 'SIGN_JWK_INVALID', - 'validateKeyByAlgCode: expected an ML-DSA-87 digital signature JWK.' + `validateKeyByAlgCode: expected an ${candidate.alg} digital signature JWK.` ) } @@ -67,7 +69,7 @@ export function validateKeyByAlgCode(key: JsonWebKey): SignKey | VerifyKey { ) } - if (secretKey.byteLength !== ml_dsa87.lengths.secretKey) { + if (secretKey.byteLength !== algorithm.lengths.secretKey) { throw new CryptosuiteError( 'SIGN_JWK_INVALID', 'validateKeyByAlgCode: private key material has invalid length.' @@ -91,7 +93,7 @@ export function validateKeyByAlgCode(key: JsonWebKey): SignKey | VerifyKey { return { ...rest, kty: 'AKP', - alg: 'ML-DSA-87', + alg: candidate.alg, d: candidate.d, use: 'sig', key_ops: ['sign'] as const, @@ -121,7 +123,7 @@ export function validateKeyByAlgCode(key: JsonWebKey): SignKey | VerifyKey { ) } - if (publicKey.byteLength !== ml_dsa87.lengths.publicKey) { + if (publicKey.byteLength !== algorithm.lengths.publicKey) { throw new CryptosuiteError( 'VERIFY_JWK_INVALID', 'validateKeyByAlgCode: public key material has invalid length.' @@ -145,7 +147,7 @@ export function validateKeyByAlgCode(key: JsonWebKey): SignKey | VerifyKey { return { ...rest, kty: 'AKP', - alg: 'ML-DSA-87', + alg: candidate.alg, x: candidate.x, use: 'sig', key_ops: ['verify'] as const, diff --git a/src/DigitalSignature/.core/types/index.ts b/src/DigitalSignature/.core/types/index.ts index e2dc67f..673d447 100644 --- a/src/DigitalSignature/.core/types/index.ts +++ b/src/DigitalSignature/.core/types/index.ts @@ -23,10 +23,12 @@ type NoPrivate = { k?: never } -type MLDSA87VerifyKey = JsonWebKey & +type DigitalSignatureAlg = 'ML-DSA-87' | 'Ed25519-ML-DSA-65' + +type VerifyKeyByAlg = JsonWebKey & NoPrivate & { kty: 'AKP' - alg: 'ML-DSA-87' + alg: Alg x: string use: 'sig' key_ops: readonly 'verify'[] @@ -40,36 +42,40 @@ type HasPrivate = { d: string } -type MLDSA87SignKey = JsonWebKey & +type SignKeyByAlg = JsonWebKey & NoSymmetric & HasPrivate & { kty: 'AKP' - alg: 'ML-DSA-87' + alg: Alg use: 'sig' key_ops: readonly 'sign'[] } -type MLDSA87VerifyParams = { - /** The raw ML-DSA-87 public key bytes. */ +type VerifyParams = { + /** The raw supported digital signature public key bytes. */ publicKey: Uint8Array } -type MLDSA87SignParams = { - /** The raw ML-DSA-87 secret key bytes. */ +type SignParams = { + /** The raw supported digital signature private key bytes. */ secretKey: Uint8Array } /** - * Public ML-DSA-87 JWK used to verify signatures. + * Public supported digital signature JWK used to verify signatures. */ -export type VerifyKey = MLDSA87VerifyKey +export type VerifyKey = + | VerifyKeyByAlg<'ML-DSA-87'> + | VerifyKeyByAlg<'Ed25519-ML-DSA-65'> /** - * Private ML-DSA-87 JWK used to produce signatures. + * Private supported digital signature JWK used to produce signatures. */ -export type SignKey = MLDSA87SignKey +export type SignKey = + | SignKeyByAlg<'ML-DSA-87'> + | SignKeyByAlg<'Ed25519-ML-DSA-65'> /** - * Runtime ML-DSA-87 key material used internally by signing and verification harnesses. + * Runtime key material used internally by signing and verification harnesses. */ -export type DigitalSignatureParams = MLDSA87VerifyParams | MLDSA87SignParams +export type DigitalSignatureParams = VerifyParams | SignParams diff --git a/src/DigitalSignature/README.md b/src/DigitalSignature/README.md index 71df5ef..c887d29 100644 --- a/src/DigitalSignature/README.md +++ b/src/DigitalSignature/README.md @@ -17,7 +17,7 @@ after the default algorithm changes. ## Current default -Current default generation and derivation target `ML-DSA-87`. +Current default generation and derivation target `Ed25519-ML-DSA-65`. ## Responsibilities diff --git a/src/DigitalSignature/deriveDigitalSignatureKeypair/index.ts b/src/DigitalSignature/deriveDigitalSignatureKeypair/index.ts index ad09734..d4bb704 100644 --- a/src/DigitalSignature/deriveDigitalSignatureKeypair/index.ts +++ b/src/DigitalSignature/deriveDigitalSignatureKeypair/index.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ import { toBase64UrlString } from '@sovereignbase/bytecodec' -import { ml_dsa87 } from '@noble/post-quantum/ml-dsa.js' import { CryptosuiteError } from '../../.errors/class.js' import { getBufferSourceLength } from '../../.helpers/getBufferSourceLength.js' +import { createImportKeyAlgorithmByAlgCode } from '../.core/helpers/createImportKeyAlgorithmByAlgCode/index.js' import { validateKeyByAlgCode } from '../.core/helpers/validateKeyByAlgCode/index.js' import type { SignKey, VerifyKey } from '../.core/types/index.js' @@ -32,29 +32,30 @@ export async function deriveDigitalSignatureKeypair( signKey: SignKey verifyKey: VerifyKey }> { + const algorithm = createImportKeyAlgorithmByAlgCode('Ed25519-ML-DSA-65') if ( getBufferSourceLength( sourceKeyMaterial, 'deriveDigitalSignatureKeypair' - ) !== ml_dsa87.lengths.seed + ) !== algorithm.lengths.seed ) { throw new CryptosuiteError( 'SIGN_JWK_INVALID', - `deriveDigitalSignatureKeypair: source key material must be exactly ${ml_dsa87.lengths.seed} bytes.` + `deriveDigitalSignatureKeypair: source key material must be exactly ${algorithm.lengths.seed} bytes.` ) } - const { publicKey, secretKey } = ml_dsa87.keygen(sourceKeyMaterial) + const { publicKey, secretKey } = algorithm.keygen(sourceKeyMaterial) const signKey = validateKeyByAlgCode({ kty: 'AKP', - alg: 'ML-DSA-87', + alg: 'Ed25519-ML-DSA-65', d: toBase64UrlString(secretKey), use: 'sig', key_ops: ['sign'], }) const verifyKey = validateKeyByAlgCode({ kty: 'AKP', - alg: 'ML-DSA-87', + alg: 'Ed25519-ML-DSA-65', x: toBase64UrlString(publicKey), use: 'sig', key_ops: ['verify'], diff --git a/src/DigitalSignature/generateDigitalSignatureKeypair/index.ts b/src/DigitalSignature/generateDigitalSignatureKeypair/index.ts index 2e20cbc..ef0d706 100644 --- a/src/DigitalSignature/generateDigitalSignatureKeypair/index.ts +++ b/src/DigitalSignature/generateDigitalSignatureKeypair/index.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ import { toBase64UrlString } from '@sovereignbase/bytecodec' -import { ml_dsa87 } from '@noble/post-quantum/ml-dsa.js' +import { createImportKeyAlgorithmByAlgCode } from '../.core/helpers/createImportKeyAlgorithmByAlgCode/index.js' import { validateKeyByAlgCode } from '../.core/helpers/validateKeyByAlgCode/index.js' import type { SignKey, VerifyKey } from '../.core/types/index.js' @@ -27,17 +27,18 @@ export async function generateDigitalSignatureKeypair(): Promise<{ signKey: SignKey verifyKey: VerifyKey }> { - const { publicKey, secretKey } = ml_dsa87.keygen() + const { publicKey, secretKey } = + createImportKeyAlgorithmByAlgCode('Ed25519-ML-DSA-65').keygen() const signKey = validateKeyByAlgCode({ kty: 'AKP', - alg: 'ML-DSA-87', + alg: 'Ed25519-ML-DSA-65', d: toBase64UrlString(secretKey), use: 'sig', key_ops: ['sign'], }) const verifyKey = validateKeyByAlgCode({ kty: 'AKP', - alg: 'ML-DSA-87', + alg: 'Ed25519-ML-DSA-65', x: toBase64UrlString(publicKey), use: 'sig', key_ops: ['verify'], diff --git a/src/KeyAgreement/.core/helpers/createImportKeyAlgorithmByAlgCode/index.ts b/src/KeyAgreement/.core/helpers/createImportKeyAlgorithmByAlgCode/index.ts index ba64ca3..1047786 100644 --- a/src/KeyAgreement/.core/helpers/createImportKeyAlgorithmByAlgCode/index.ts +++ b/src/KeyAgreement/.core/helpers/createImportKeyAlgorithmByAlgCode/index.ts @@ -13,16 +13,20 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ +import { ml_kem768_x25519 } from '@noble/post-quantum/hybrid.js' import { ml_kem1024 } from '@noble/post-quantum/ml-kem.js' +import type { KEM } from '@noble/post-quantum/utils.js' import { CryptosuiteError } from '../../../../.errors/class.js' import type { DecapsulateKey, EncapsulateKey } from '../../types/index.js' export function createImportKeyAlgorithmByAlgCode( algCode: EncapsulateKey['alg'] | DecapsulateKey['alg'] -): typeof ml_kem1024 { +): typeof ml_kem1024 | KEM { switch (algCode) { case 'ML-KEM-1024': return ml_kem1024 + case 'X25519-ML-KEM-768': + return ml_kem768_x25519 } throw new CryptosuiteError( diff --git a/src/KeyAgreement/.core/helpers/getParamsByAlgCode/index.ts b/src/KeyAgreement/.core/helpers/getParamsByAlgCode/index.ts index 4ed5bbe..788b754 100644 --- a/src/KeyAgreement/.core/helpers/getParamsByAlgCode/index.ts +++ b/src/KeyAgreement/.core/helpers/getParamsByAlgCode/index.ts @@ -26,6 +26,7 @@ export function getParamsByAlgCode( ): KeyAgreementParams { switch (algCode) { case 'ML-KEM-1024': + case 'X25519-ML-KEM-768': return params } diff --git a/src/KeyAgreement/.core/helpers/validateKeyByAlgCode/index.ts b/src/KeyAgreement/.core/helpers/validateKeyByAlgCode/index.ts index a522f88..1dcea56 100644 --- a/src/KeyAgreement/.core/helpers/validateKeyByAlgCode/index.ts +++ b/src/KeyAgreement/.core/helpers/validateKeyByAlgCode/index.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ import { fromBase64UrlString } from '@sovereignbase/bytecodec' -import { ml_kem1024 } from '@noble/post-quantum/ml-kem.js' import { CryptosuiteError } from '../../../../.errors/class.js' +import { createImportKeyAlgorithmByAlgCode } from '../createImportKeyAlgorithmByAlgCode/index.js' import type { DecapsulateKey, EncapsulateKey } from '../../types/index.js' export function validateKeyByAlgCode( @@ -31,11 +31,13 @@ export function validateKeyByAlgCode( } switch (candidate.alg) { - case 'ML-KEM-1024': { + case 'ML-KEM-1024': + case 'X25519-ML-KEM-768': { + const algorithm = createImportKeyAlgorithmByAlgCode(candidate.alg) if (candidate.kty !== 'AKP') { throw new CryptosuiteError( 'KEY_AGREEMENT_KEY_INVALID', - 'validateKeyByAlgCode: expected an ML-KEM-1024 key agreement JWK.' + `validateKeyByAlgCode: expected an ${candidate.alg} key agreement JWK.` ) } @@ -70,7 +72,7 @@ export function validateKeyByAlgCode( ) } - if (secretKey.byteLength !== ml_kem1024.lengths.secretKey) { + if (secretKey.byteLength !== algorithm.lengths.secretKey) { throw new CryptosuiteError( 'KEY_AGREEMENT_KEY_INVALID', 'validateKeyByAlgCode: private key material has invalid length.' @@ -95,7 +97,7 @@ export function validateKeyByAlgCode( return { ...rest, kty: 'AKP', - alg: 'ML-KEM-1024', + alg: candidate.alg, d: candidate.d, use: 'enc', key_ops: @@ -126,7 +128,7 @@ export function validateKeyByAlgCode( ) } - if (publicKey.byteLength !== ml_kem1024.lengths.publicKey) { + if (publicKey.byteLength !== algorithm.lengths.publicKey) { throw new CryptosuiteError( 'KEY_AGREEMENT_KEY_INVALID', 'validateKeyByAlgCode: public key material has invalid length.' @@ -151,7 +153,7 @@ export function validateKeyByAlgCode( return { ...rest, kty: 'AKP', - alg: 'ML-KEM-1024', + alg: candidate.alg, x: candidate.x, use: 'enc', key_ops: [] as const, diff --git a/src/KeyAgreement/.core/types/index.ts b/src/KeyAgreement/.core/types/index.ts index c10508b..dd2b73e 100644 --- a/src/KeyAgreement/.core/types/index.ts +++ b/src/KeyAgreement/.core/types/index.ts @@ -27,58 +27,62 @@ type NoPrivate = { oth?: never } -type MLKEM1024EncapsulateKey = JsonWebKey & +type KeyAgreementAlg = 'ML-KEM-1024' | 'X25519-ML-KEM-768' + +type EncapsulateKeyByAlg = JsonWebKey & NoSymmetric & NoPrivate & { kty: 'AKP' - alg: 'ML-KEM-1024' + alg: Alg x: string use: 'enc' key_ops: readonly [] } -type MLKEM1024DecapsulateKey = JsonWebKey & +type DecapsulateKeyByAlg = JsonWebKey & NoSymmetric & { kty: 'AKP' - alg: 'ML-KEM-1024' + alg: Alg d: string use: 'enc' key_ops: readonly ('deriveKey' | 'deriveBits')[] } -type MLKEM1024KeyOffer = { - /** The encapsulated shared-secret artifact emitted by ML-KEM-1024. */ +type KeyAgreementOffer = { + /** The encapsulated shared-secret artifact emitted by a supported key agreement algorithm. */ ciphertext: ArrayBuffer } -type MLKEM1024EncapsulateParams = { - /** The raw ML-KEM-1024 public key bytes. */ +type EncapsulateParams = { + /** The raw supported key agreement public key bytes. */ publicKey: Uint8Array } -type MLKEM1024DecapsulateParams = { - /** The raw ML-KEM-1024 secret key bytes. */ +type DecapsulateParams = { + /** The raw supported key agreement private key bytes. */ secretKey: Uint8Array } /** - * Public ML-KEM-1024 JWK used to encapsulate a shared cipher key. + * Public supported key agreement JWK used to encapsulate a shared cipher key. */ -export type EncapsulateKey = MLKEM1024EncapsulateKey +export type EncapsulateKey = + | EncapsulateKeyByAlg<'ML-KEM-1024'> + | EncapsulateKeyByAlg<'X25519-ML-KEM-768'> /** - * Private ML-KEM-1024 JWK used to decapsulate a shared cipher key. + * Private supported key agreement JWK used to decapsulate a shared cipher key. */ -export type DecapsulateKey = MLKEM1024DecapsulateKey +export type DecapsulateKey = + | DecapsulateKeyByAlg<'ML-KEM-1024'> + | DecapsulateKeyByAlg<'X25519-ML-KEM-768'> /** * Encapsulated key agreement artifact exchanged with the counterparty. */ -export type KeyOffer = MLKEM1024KeyOffer +export type KeyOffer = KeyAgreementOffer /** - * Runtime ML-KEM-1024 parameters used internally by key agreement harnesses. + * Runtime key agreement parameters used internally by key agreement harnesses. */ -export type KeyAgreementParams = - | MLKEM1024EncapsulateParams - | MLKEM1024DecapsulateParams +export type KeyAgreementParams = EncapsulateParams | DecapsulateParams diff --git a/src/KeyAgreement/README.md b/src/KeyAgreement/README.md index ed688fd..a4b8bd6 100644 --- a/src/KeyAgreement/README.md +++ b/src/KeyAgreement/README.md @@ -17,7 +17,7 @@ after the default algorithm changes. ## Current default -Current default generation and derivation target `ML-KEM-1024`. +Current default generation and derivation target `X25519-ML-KEM-768`. Encapsulation returns a `KeyOffer` and a symmetric `CipherKey`. @@ -71,7 +71,8 @@ When upgrading the default algorithm: ## Naming rule -Inside `.core`, JWK `alg` values such as `ML-KEM-1024` are the external key +Inside `.core`, JWK `alg` values such as `ML-KEM-1024` or +`X25519-ML-KEM-768` are the external key identifiers and the routing source of truth. Do not add extra algorithm-name translation layers unless the runtime actually diff --git a/src/KeyAgreement/deriveKeyAgreementKeypair/index.ts b/src/KeyAgreement/deriveKeyAgreementKeypair/index.ts index 85f2fa0..1ca1990 100644 --- a/src/KeyAgreement/deriveKeyAgreementKeypair/index.ts +++ b/src/KeyAgreement/deriveKeyAgreementKeypair/index.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ import { toBase64UrlString } from '@sovereignbase/bytecodec' -import { ml_kem1024 } from '@noble/post-quantum/ml-kem.js' import { CryptosuiteError } from '../../.errors/class.js' import { getBufferSourceLength } from '../../.helpers/getBufferSourceLength.js' +import { createImportKeyAlgorithmByAlgCode } from '../.core/helpers/createImportKeyAlgorithmByAlgCode/index.js' import { validateKeyByAlgCode } from '../.core/helpers/validateKeyByAlgCode/index.js' import type { DecapsulateKey } from '../.core/types/index.js' import type { EncapsulateKey } from '../.core/types/index.js' @@ -33,27 +33,28 @@ export async function deriveKeyAgreementKeypair( encapsulateKey: EncapsulateKey decapsulateKey: DecapsulateKey }> { + const algorithm = createImportKeyAlgorithmByAlgCode('X25519-ML-KEM-768') if ( getBufferSourceLength(sourceKeyMaterial, 'deriveKeyAgreementKeypair') !== - ml_kem1024.lengths.seed + algorithm.lengths.seed ) { throw new CryptosuiteError( 'KEY_AGREEMENT_KEY_INVALID', - `deriveKeyAgreementKeypair: source key material must be exactly ${ml_kem1024.lengths.seed} bytes.` + `deriveKeyAgreementKeypair: source key material must be exactly ${algorithm.lengths.seed} bytes.` ) } - const { publicKey, secretKey } = ml_kem1024.keygen(sourceKeyMaterial) + const { publicKey, secretKey } = algorithm.keygen(sourceKeyMaterial) const encapsulateKey = validateKeyByAlgCode({ kty: 'AKP', - alg: 'ML-KEM-1024', + alg: 'X25519-ML-KEM-768', x: toBase64UrlString(publicKey), use: 'enc', key_ops: [], }) const decapsulateKey = validateKeyByAlgCode({ kty: 'AKP', - alg: 'ML-KEM-1024', + alg: 'X25519-ML-KEM-768', d: toBase64UrlString(secretKey), use: 'enc', key_ops: ['deriveKey', 'deriveBits'], diff --git a/src/KeyAgreement/generateKeyAgreementKeypair/index.ts b/src/KeyAgreement/generateKeyAgreementKeypair/index.ts index 3417ec9..c57423b 100644 --- a/src/KeyAgreement/generateKeyAgreementKeypair/index.ts +++ b/src/KeyAgreement/generateKeyAgreementKeypair/index.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ import { toBase64UrlString } from '@sovereignbase/bytecodec' -import { ml_kem1024 } from '@noble/post-quantum/ml-kem.js' +import { createImportKeyAlgorithmByAlgCode } from '../.core/helpers/createImportKeyAlgorithmByAlgCode/index.js' import { validateKeyByAlgCode } from '../.core/helpers/validateKeyByAlgCode/index.js' import type { EncapsulateKey, DecapsulateKey } from '../.core/types/index.js' @@ -27,17 +27,18 @@ export async function generateKeyAgreementKeypair(): Promise<{ encapsulateKey: EncapsulateKey decapsulateKey: DecapsulateKey }> { - const { publicKey, secretKey } = ml_kem1024.keygen() + const { publicKey, secretKey } = + createImportKeyAlgorithmByAlgCode('X25519-ML-KEM-768').keygen() const encapsulateKey = validateKeyByAlgCode({ kty: 'AKP', - alg: 'ML-KEM-1024', + alg: 'X25519-ML-KEM-768', x: toBase64UrlString(publicKey), use: 'enc', key_ops: [], }) const decapsulateKey = validateKeyByAlgCode({ kty: 'AKP', - alg: 'ML-KEM-1024', + alg: 'X25519-ML-KEM-768', d: toBase64UrlString(secretKey), use: 'enc', key_ops: ['deriveKey', 'deriveBits'], diff --git a/test/e2e/runtime-suite.mjs b/test/e2e/runtime-suite.mjs index 457c99b..9706c94 100644 --- a/test/e2e/runtime-suite.mjs +++ b/test/e2e/runtime-suite.mjs @@ -44,10 +44,10 @@ export async function runCryptosuiteRuntimeSuite(Cryptographic) { const plaintext = new TextEncoder().encode('cryptosuite runtime') const cipherSalt = new Uint8Array(16).fill(9) const messageAuthenticationSalt = new Uint8Array(16).fill(7) - const keyAgreementSeed = Uint8Array.from({ length: 64 }, (_, index) => { + const keyAgreementSeed = Uint8Array.from({ length: 32 }, (_, index) => { return (index + 11) % 256 }) - const digitalSignatureSeed = Uint8Array.from({ length: 32 }, (_, index) => { + const digitalSignatureSeed = Uint8Array.from({ length: 64 }, (_, index) => { return (index + 17) % 256 }) @@ -315,14 +315,14 @@ export async function runCryptosuiteRuntimeSuite(Cryptographic) { ) await run( - 'keyAgreement.generateKeypair returns ML-KEM-1024 keys', + 'keyAgreement.generateKeypair returns X25519-ML-KEM-768 keys', async () => { const { encapsulateKey, decapsulateKey } = await Cryptographic.keyAgreement.generateKeypair() assertEqual(encapsulateKey.kty, 'AKP', 'encapsulate key must be AKP') assertEqual( encapsulateKey.alg, - 'ML-KEM-1024', + 'X25519-ML-KEM-768', 'encapsulate key alg mismatch' ) assert( @@ -332,7 +332,7 @@ export async function runCryptosuiteRuntimeSuite(Cryptographic) { assertEqual(decapsulateKey.kty, 'AKP', 'decapsulate key must be AKP') assertEqual( decapsulateKey.alg, - 'ML-KEM-1024', + 'X25519-ML-KEM-768', 'decapsulate key alg mismatch' ) assert( @@ -409,15 +409,15 @@ export async function runCryptosuiteRuntimeSuite(Cryptographic) { ) await run( - 'digitalSignature.generateKeypair returns ML-DSA-87 keys', + 'digitalSignature.generateKeypair returns Ed25519-ML-DSA-65 keys', async () => { const { signKey, verifyKey } = await Cryptographic.digitalSignature.generateKeypair() assertEqual(signKey.kty, 'AKP', 'sign key must be AKP') - assertEqual(signKey.alg, 'ML-DSA-87', 'sign key alg mismatch') + assertEqual(signKey.alg, 'Ed25519-ML-DSA-65', 'sign key alg mismatch') assert(typeof signKey.d === 'string', 'sign key d must exist') assertEqual(verifyKey.kty, 'AKP', 'verify key must be AKP') - assertEqual(verifyKey.alg, 'ML-DSA-87', 'verify key alg mismatch') + assertEqual(verifyKey.alg, 'Ed25519-ML-DSA-65', 'verify key alg mismatch') assert(typeof verifyKey.x === 'string', 'verify key x must exist') } ) diff --git a/test/integration/integration.test.mjs b/test/integration/integration.test.mjs index 7586edb..1c727be 100644 --- a/test/integration/integration.test.mjs +++ b/test/integration/integration.test.mjs @@ -1,7 +1,7 @@ import assert from 'node:assert/strict' import test from 'node:test' import { webcrypto } from 'node:crypto' -import { ml_kem1024 } from '@noble/post-quantum/ml-kem.js' +import { ml_kem768_x25519 } from '@noble/post-quantum/hybrid.js' import { Cryptographic } from '../../dist/index.js' import { bytes } from '../support/fixtures.mjs' @@ -100,7 +100,7 @@ test('integration: key agreement encapsulate/decapsulate reconstructs the same c }) test('integration: key agreement derivation is deterministic', async () => { - const seed = new Uint8Array(ml_kem1024.lengths.seed).fill(11) + const seed = new Uint8Array(ml_kem768_x25519.lengths.seed).fill(11) const one = await Cryptographic.keyAgreement.deriveKeypair(seed) const two = await Cryptographic.keyAgreement.deriveKeypair(seed) assert.equal(one.encapsulateKey.x, two.encapsulateKey.x) @@ -130,7 +130,7 @@ test('integration: digital signature sign/verify roundtrip', async () => { }) test('integration: digital signature derivation is deterministic', async () => { - const seed = new Uint8Array(32).fill(12) + const seed = new Uint8Array(64).fill(12) const one = await Cryptographic.digitalSignature.deriveKeypair(seed) const two = await Cryptographic.digitalSignature.deriveKeypair(seed) assert.equal(one.signKey.d, two.signKey.d) diff --git a/test/support/fixtures.mjs b/test/support/fixtures.mjs index 312da6a..bdf8f20 100644 --- a/test/support/fixtures.mjs +++ b/test/support/fixtures.mjs @@ -1,7 +1,20 @@ -import { ml_dsa87 } from '@noble/post-quantum/ml-dsa.js' +import { ed25519 } from '@noble/curves/ed25519.js' +import { + combineSigners, + ecSigner, + ml_kem768_x25519, +} from '@noble/post-quantum/hybrid.js' +import { ml_dsa65, ml_dsa87 } from '@noble/post-quantum/ml-dsa.js' import { ml_kem1024 } from '@noble/post-quantum/ml-kem.js' import { toBase64UrlString } from '@sovereignbase/bytecodec' +const ed25519MlDsa65 = combineSigners( + undefined, + (seed) => seed, + ecSigner(ed25519), + ml_dsa65 +) + export function bytes(...values) { return Uint8Array.from(values) } @@ -75,3 +88,47 @@ export function createMlDsaVerifyKey(overrides = {}) { ...overrides, } } + +export function createX25519MlKem768PublicKey(overrides = {}) { + return { + kty: 'AKP', + alg: 'X25519-ML-KEM-768', + x: toBase64UrlString(filledBytes(ml_kem768_x25519.lengths.publicKey, 7)), + use: 'enc', + key_ops: [], + ...overrides, + } +} + +export function createX25519MlKem768PrivateKey(overrides = {}) { + return { + kty: 'AKP', + alg: 'X25519-ML-KEM-768', + d: toBase64UrlString(filledBytes(ml_kem768_x25519.lengths.secretKey, 8)), + use: 'enc', + key_ops: ['deriveKey', 'deriveBits'], + ...overrides, + } +} + +export function createEd25519MlDsa65SignKey(overrides = {}) { + return { + kty: 'AKP', + alg: 'Ed25519-ML-DSA-65', + d: toBase64UrlString(filledBytes(ed25519MlDsa65.lengths.secretKey, 9)), + use: 'sig', + key_ops: ['sign'], + ...overrides, + } +} + +export function createEd25519MlDsa65VerifyKey(overrides = {}) { + return { + kty: 'AKP', + alg: 'Ed25519-ML-DSA-65', + x: toBase64UrlString(filledBytes(ed25519MlDsa65.lengths.publicKey, 10)), + use: 'sig', + key_ops: ['verify'], + ...overrides, + } +} diff --git a/test/unit/digitalSignature.test.mjs b/test/unit/digitalSignature.test.mjs index 609be74..42eb36f 100644 --- a/test/unit/digitalSignature.test.mjs +++ b/test/unit/digitalSignature.test.mjs @@ -1,6 +1,5 @@ import assert from 'node:assert/strict' import test from 'node:test' -import { ml_dsa87 } from '@noble/post-quantum/ml-dsa.js' import { Cryptographic } from '../../dist/index.js' import { expectCodeAsync } from '../support/index.mjs' import { @@ -9,7 +8,7 @@ import { createMlDsaVerifyKey, } from '../support/fixtures.mjs' -test('digitalSignature.deriveKeypair rejects seed lengths that are not 32 bytes', async () => { +test('digitalSignature.deriveKeypair rejects seed lengths that are not 64 bytes', async () => { await expectCodeAsync( () => Cryptographic.digitalSignature.deriveKeypair(bytes(1, 2, 3)), 'SIGN_JWK_INVALID' @@ -81,45 +80,6 @@ test('digitalSignature.verify returns false for modified message bytes', async ( assert.equal(verified, false) }) -test('digitalSignature.sign maps ML-DSA runtime failures to ALGORITHM_UNSUPPORTED', async () => { - const original = ml_dsa87.sign - const { signKey } = await Cryptographic.digitalSignature.generateKeypair() - ml_dsa87.sign = () => { - throw new Error('boom') - } - - try { - await expectCodeAsync( - () => Cryptographic.digitalSignature.sign(signKey, bytes(1, 2, 3)), - 'ALGORITHM_UNSUPPORTED' - ) - } finally { - ml_dsa87.sign = original - } -}) - -test('digitalSignature.verify maps ML-DSA runtime failures to ALGORITHM_UNSUPPORTED', async () => { - const original = ml_dsa87.verify - const { verifyKey } = await Cryptographic.digitalSignature.generateKeypair() - ml_dsa87.verify = () => { - throw new Error('boom') - } - - try { - await expectCodeAsync( - () => - Cryptographic.digitalSignature.verify( - verifyKey, - bytes(1, 2, 3), - bytes(4, 5, 6) - ), - 'ALGORITHM_UNSUPPORTED' - ) - } finally { - ml_dsa87.verify = original - } -}) - test('digitalSignature cluster reuses cached harnesses for the same key objects', async () => { const { signKey, verifyKey } = await Cryptographic.digitalSignature.generateKeypair() diff --git a/test/unit/keyAgreement.test.mjs b/test/unit/keyAgreement.test.mjs index c877d19..7bc7687 100644 --- a/test/unit/keyAgreement.test.mjs +++ b/test/unit/keyAgreement.test.mjs @@ -22,7 +22,7 @@ test.afterEach(() => { restoreCrypto() }) -test('keyAgreement.deriveKeypair rejects seed lengths that do not match ML-KEM-1024', async () => { +test('keyAgreement.deriveKeypair rejects seed lengths that do not match X25519-ML-KEM-768', async () => { await expectCodeAsync( () => Cryptographic.keyAgreement.deriveKeypair(bytes(1, 2, 3)), 'KEY_AGREEMENT_KEY_INVALID' diff --git a/test/unit/source-digitalSignature.test.mjs b/test/unit/source-digitalSignature.test.mjs index b28d767..3dff3a0 100644 --- a/test/unit/source-digitalSignature.test.mjs +++ b/test/unit/source-digitalSignature.test.mjs @@ -10,19 +10,13 @@ import { VerifyKeyHarness } from '../../src/DigitalSignature/.core/VerifyKeyHarn import { expectCodeAsync, expectCodeSync } from '../support/index.mjs' import { bytes, + createEd25519MlDsa65SignKey, + createEd25519MlDsa65VerifyKey, createMlDsaSignKey, createMlDsaVerifyKey, filledBytes, } from '../support/fixtures.mjs' -const ORIGINAL_SIGN = ml_dsa87.sign -const ORIGINAL_VERIFY = ml_dsa87.verify - -test.afterEach(() => { - ml_dsa87.sign = ORIGINAL_SIGN - ml_dsa87.verify = ORIGINAL_VERIFY -}) - test('source digital signature helpers cover validation and unsupported branches', () => { expectCodeSync(() => validateKeyByAlgCode(null), 'SIGN_JWK_INVALID') expectCodeSync( @@ -75,6 +69,28 @@ test('source digital signature helpers cover validation and unsupported branches () => validateKeyByAlgCode(createMlDsaSignKey({ alg: 'ML-DSA-65' })), 'ALGORITHM_UNSUPPORTED' ) + expectCodeSync( + () => validateKeyByAlgCode(createEd25519MlDsa65SignKey({ kty: 'oct' })), + 'SIGN_JWK_INVALID' + ) + expectCodeSync( + () => + validateKeyByAlgCode( + createEd25519MlDsa65SignKey({ + d: Buffer.from([1]).toString('base64url'), + }) + ), + 'SIGN_JWK_INVALID' + ) + expectCodeSync( + () => + validateKeyByAlgCode( + createEd25519MlDsa65VerifyKey({ + x: Buffer.from([1]).toString('base64url'), + }) + ), + 'VERIFY_JWK_INVALID' + ) const normalizedSign = validateKeyByAlgCode( createMlDsaSignKey({ key_ops: undefined, extra: 'ok' }) @@ -91,6 +107,8 @@ test('source digital signature helpers cover validation and unsupported branches assert.equal(normalizedVerify.extra, 'ok') assert.equal(createImportKeyAlgorithmByAlgCode('ML-DSA-87'), ml_dsa87) + const hybridAlgorithm = createImportKeyAlgorithmByAlgCode('Ed25519-ML-DSA-65') + assert.equal(hybridAlgorithm.lengths.secretKey, 64) expectCodeSync( () => createImportKeyAlgorithmByAlgCode('ML-DSA-65'), 'ALGORITHM_UNSUPPORTED' @@ -107,6 +125,22 @@ test('source digital signature helpers cover validation and unsupported branches () => getParamsByAlgCode('ML-DSA-65', signParams), 'ALGORITHM_UNSUPPORTED' ) + const hybridSignParams = createParamsByAlgCode(createEd25519MlDsa65SignKey()) + assert.equal( + hybridSignParams.secretKey.byteLength, + hybridAlgorithm.lengths.secretKey + ) + const hybridVerifyParams = createParamsByAlgCode( + createEd25519MlDsa65VerifyKey() + ) + assert.equal( + hybridVerifyParams.publicKey.byteLength, + hybridAlgorithm.lengths.publicKey + ) + assert.equal( + getParamsByAlgCode('Ed25519-ML-DSA-65', hybridSignParams), + hybridSignParams + ) }) test('source digital signature harnesses cover constructor, invariant, and catch branches', async () => { @@ -130,24 +164,53 @@ test('source digital signature harnesses cover constructor, invariant, and catch 'VERIFY_JWK_INVALID' ) - ml_dsa87.sign = () => { - throw new Error('boom') + const failingMlDsaSigner = new SignKeyHarness(createMlDsaSignKey()) + failingMlDsaSigner.signer = { + ...createImportKeyAlgorithmByAlgCode('ML-DSA-87'), + sign() { + throw new Error('boom') + }, } await expectCodeAsync( - () => new SignKeyHarness(createMlDsaSignKey()).sign(bytes(1, 2, 3)), + () => failingMlDsaSigner.sign(bytes(1, 2, 3)), 'ALGORITHM_UNSUPPORTED' ) - ml_dsa87.sign = ORIGINAL_SIGN - ml_dsa87.verify = () => { - throw new Error('boom') + const failingMlDsaVerifier = new VerifyKeyHarness(createMlDsaVerifyKey()) + failingMlDsaVerifier.verifier = { + ...createImportKeyAlgorithmByAlgCode('ML-DSA-87'), + verify() { + throw new Error('boom') + }, } await expectCodeAsync( - () => - new VerifyKeyHarness(createMlDsaVerifyKey()).verify( - bytes(1, 2, 3), - bytes(4, 5, 6) - ), + () => failingMlDsaVerifier.verify(bytes(1, 2, 3), bytes(4, 5, 6)), + 'ALGORITHM_UNSUPPORTED' + ) + + const failingHybridSigner = new SignKeyHarness(createEd25519MlDsa65SignKey()) + failingHybridSigner.signer = { + ...createImportKeyAlgorithmByAlgCode('Ed25519-ML-DSA-65'), + sign() { + throw new Error('boom') + }, + } + await expectCodeAsync( + () => failingHybridSigner.sign(bytes(1, 2, 3)), + 'ALGORITHM_UNSUPPORTED' + ) + + const failingHybridVerifier = new VerifyKeyHarness( + createEd25519MlDsa65VerifyKey() + ) + failingHybridVerifier.verifier = { + ...createImportKeyAlgorithmByAlgCode('Ed25519-ML-DSA-65'), + verify() { + throw new Error('boom') + }, + } + await expectCodeAsync( + () => failingHybridVerifier.verify(bytes(1, 2, 3), bytes(4, 5, 6)), 'ALGORITHM_UNSUPPORTED' ) }) diff --git a/test/unit/source-keyAgreement.test.mjs b/test/unit/source-keyAgreement.test.mjs index 5e9dfe1..4a9a7b7 100644 --- a/test/unit/source-keyAgreement.test.mjs +++ b/test/unit/source-keyAgreement.test.mjs @@ -1,6 +1,7 @@ import assert from 'node:assert/strict' import test from 'node:test' import { webcrypto } from 'node:crypto' +import { ml_kem768_x25519 } from '@noble/post-quantum/hybrid.js' import { ml_kem1024 } from '@noble/post-quantum/ml-kem.js' import { createImportKeyAlgorithmByAlgCode } from '../../src/KeyAgreement/.core/helpers/createImportKeyAlgorithmByAlgCode/index.ts' import { createParamsByAlgCode } from '../../src/KeyAgreement/.core/helpers/createParamsByAlgCode/index.ts' @@ -19,6 +20,8 @@ import { createA256CtrKey, createMlKemPrivateKey, createMlKemPublicKey, + createX25519MlKem768PrivateKey, + createX25519MlKem768PublicKey, filledBytes, } from '../support/fixtures.mjs' @@ -26,13 +29,8 @@ if (!globalThis.crypto) { globalThis.crypto = webcrypto } -const ORIGINAL_ENCAPSULATE = ml_kem1024.encapsulate -const ORIGINAL_DECAPSULATE = ml_kem1024.decapsulate - test.afterEach(() => { restoreCrypto() - ml_kem1024.encapsulate = ORIGINAL_ENCAPSULATE - ml_kem1024.decapsulate = ORIGINAL_DECAPSULATE }) test('source key agreement helpers cover validation and unsupported branches', () => { @@ -88,6 +86,28 @@ test('source key agreement helpers cover validation and unsupported branches', ( () => validateKeyByAlgCode(createMlKemPublicKey({ alg: 'ML-KEM-768' })), 'ALGORITHM_UNSUPPORTED' ) + expectCodeSync( + () => validateKeyByAlgCode(createX25519MlKem768PublicKey({ kty: 'oct' })), + 'KEY_AGREEMENT_KEY_INVALID' + ) + expectCodeSync( + () => + validateKeyByAlgCode( + createX25519MlKem768PrivateKey({ + d: Buffer.from([1]).toString('base64url'), + }) + ), + 'KEY_AGREEMENT_KEY_INVALID' + ) + expectCodeSync( + () => + validateKeyByAlgCode( + createX25519MlKem768PublicKey({ + x: Buffer.from([1]).toString('base64url'), + }) + ), + 'KEY_AGREEMENT_KEY_INVALID' + ) const normalizedPrivate = validateKeyByAlgCode( createMlKemPrivateKey({ key_ops: undefined, extra: 'ok' }) @@ -104,6 +124,10 @@ test('source key agreement helpers cover validation and unsupported branches', ( assert.equal(normalizedPublic.extra, 'ok') assert.equal(createImportKeyAlgorithmByAlgCode('ML-KEM-1024'), ml_kem1024) + assert.equal( + createImportKeyAlgorithmByAlgCode('X25519-ML-KEM-768'), + ml_kem768_x25519 + ) expectCodeSync( () => createImportKeyAlgorithmByAlgCode('ML-KEM-768'), 'ALGORITHM_UNSUPPORTED' @@ -120,6 +144,24 @@ test('source key agreement helpers cover validation and unsupported branches', ( () => getParamsByAlgCode('ML-KEM-768', publicParams), 'ALGORITHM_UNSUPPORTED' ) + const hybridPublicParams = createParamsByAlgCode( + createX25519MlKem768PublicKey() + ) + assert.equal( + hybridPublicParams.publicKey.byteLength, + ml_kem768_x25519.lengths.publicKey + ) + const hybridSecretParams = createParamsByAlgCode( + createX25519MlKem768PrivateKey() + ) + assert.equal( + hybridSecretParams.secretKey.byteLength, + ml_kem768_x25519.lengths.secretKey + ) + assert.equal( + getParamsByAlgCode('X25519-ML-KEM-768', hybridPublicParams), + hybridPublicParams + ) }) test('source key agreement harnesses cover constructor, invariant, and export branches', async () => { @@ -245,24 +287,29 @@ test('source key agreement harnesses cover constructor, invariant, and export br 'KEY_AGREEMENT_KEY_INVALID' ) - ml_kem1024.encapsulate = () => { - throw new Error('boom') - } const encapsulateFailHarness = new EncapsulateKeyHarness( createMlKemPublicKey() ) + encapsulateFailHarness.kem = { + ...createImportKeyAlgorithmByAlgCode('ML-KEM-1024'), + encapsulate() { + throw new Error('boom') + }, + } await expectCodeAsync( () => encapsulateFailHarness.encapsulate(), 'ENCAPSULATION_FAILED' ) - ml_kem1024.encapsulate = ORIGINAL_ENCAPSULATE - ml_kem1024.decapsulate = () => { - throw new Error('boom') - } const decapsulateFailHarness = new DecapsulateKeyHarness( createMlKemPrivateKey() ) + decapsulateFailHarness.kem = { + ...createImportKeyAlgorithmByAlgCode('ML-KEM-1024'), + decapsulate() { + throw new Error('boom') + }, + } await expectCodeAsync( () => decapsulateFailHarness.decapsulate({ @@ -270,4 +317,35 @@ test('source key agreement harnesses cover constructor, invariant, and export br }), 'DECAPSULATION_FAILED' ) + + const hybridEncapsulateFailHarness = new EncapsulateKeyHarness( + createX25519MlKem768PublicKey() + ) + hybridEncapsulateFailHarness.kem = { + ...createImportKeyAlgorithmByAlgCode('X25519-ML-KEM-768'), + encapsulate() { + throw new Error('boom') + }, + } + await expectCodeAsync( + () => hybridEncapsulateFailHarness.encapsulate(), + 'ENCAPSULATION_FAILED' + ) + + const hybridDecapsulateFailHarness = new DecapsulateKeyHarness( + createX25519MlKem768PrivateKey() + ) + hybridDecapsulateFailHarness.kem = { + ...createImportKeyAlgorithmByAlgCode('X25519-ML-KEM-768'), + decapsulate() { + throw new Error('boom') + }, + } + await expectCodeAsync( + () => + hybridDecapsulateFailHarness.decapsulate({ + ciphertext: new ArrayBuffer(ml_kem768_x25519.lengths.cipherText), + }), + 'DECAPSULATION_FAILED' + ) })