├── packages ├── core │ ├── test │ │ ├── runtimes │ │ │ ├── browsers │ │ │ │ ├── pages │ │ │ │ │ └── src │ │ │ │ │ │ └── .gitkeep │ │ │ │ ├── test-results │ │ │ │ │ └── .last-run.json │ │ │ │ ├── package.json │ │ │ │ ├── playwright.config.ts │ │ │ │ └── core.spec.ts │ │ │ ├── bun │ │ │ │ ├── bun.lockb │ │ │ │ ├── README.md │ │ │ │ ├── package.json │ │ │ │ └── tsconfig.json │ │ │ └── cloudflare │ │ │ │ ├── src │ │ │ │ └── index.ts │ │ │ │ ├── vitest.config.mts │ │ │ │ └── package.json │ │ ├── utils.ts │ │ └── testVector.ts │ ├── samples │ │ ├── deno │ │ │ ├── deno.jsonc │ │ │ └── main.ts │ │ └── node │ │ │ ├── package.json │ │ │ └── app.js │ ├── src │ │ ├── interfaces │ │ │ ├── keyInfo.ts │ │ │ ├── encapsulator.ts │ │ │ ├── responses.ts │ │ │ ├── aeadParams.ts │ │ │ ├── exporter.ts │ │ │ ├── cipherSuiteParams.ts │ │ │ └── encryptionContext.ts │ │ ├── utils │ │ │ └── emitNotSupported.ts │ │ ├── mutex.ts │ │ ├── recipientContext.ts │ │ ├── aeads │ │ │ └── exportOnly.ts │ │ ├── senderContext.ts │ │ ├── kems │ │ │ ├── dhkemX448.ts │ │ │ ├── dhkemX25519.ts │ │ │ └── dhkemNative.ts │ │ └── encryptionContext.ts │ ├── tsconfig.json │ ├── LICENSE │ ├── mod.ts │ ├── deno.jsonc │ └── dnt.ts ├── hpke-js │ ├── test │ │ ├── runtimes │ │ │ ├── browsers │ │ │ │ ├── pages │ │ │ │ │ └── src │ │ │ │ │ │ └── .gitkeep │ │ │ │ ├── package.json │ │ │ │ ├── hpke.spec.ts │ │ │ │ └── playwright.config.ts │ │ │ ├── bun │ │ │ │ ├── .npmrc │ │ │ │ ├── bun.lockb │ │ │ │ ├── README.md │ │ │ │ ├── package.json │ │ │ │ ├── tsconfig.json │ │ │ │ └── hpke.spec.ts │ │ │ └── cloudflare │ │ │ │ ├── .npmrc │ │ │ │ ├── src │ │ │ │ ├── index.ts │ │ │ │ └── server.ts │ │ │ │ ├── vitest.config.mts │ │ │ │ └── package.json │ │ ├── utils.ts │ │ ├── keyValidationX448.test.ts │ │ └── testVector.ts │ ├── samples │ │ ├── ts-webpack │ │ │ ├── .gitignore │ │ │ ├── tsconfig.json │ │ │ ├── index.js │ │ │ ├── index.html │ │ │ ├── webpack.config.js │ │ │ ├── package.json │ │ │ └── app.ts │ │ ├── deno │ │ │ └── deno.jsonc │ │ ├── ts-node │ │ │ ├── package.json │ │ │ └── app.ts │ │ ├── node │ │ │ ├── package.json │ │ │ └── app.js │ │ └── browser │ │ │ └── index.html │ ├── tsconfig.json │ ├── src │ │ ├── kems │ │ │ ├── dhkemP256.ts │ │ │ ├── dhkemP384.ts │ │ │ └── dhkemP521.ts │ │ ├── kdfs │ │ │ └── hkdfSha384.ts │ │ └── identifiers.ts │ ├── mod.ts │ ├── LICENSE │ ├── deno.jsonc │ └── dnt.ts ├── ml-kem │ ├── test │ │ └── runtimes │ │ │ ├── browsers │ │ │ ├── pages │ │ │ │ └── src │ │ │ │ │ └── .gitkeep │ │ │ ├── package.json │ │ │ ├── ml-kem.spec.ts │ │ │ └── playwright.config.ts │ │ │ ├── bun │ │ │ ├── .npmrc │ │ │ ├── bun.lockb │ │ │ ├── README.md │ │ │ └── package.json │ │ │ └── cloudflare │ │ │ ├── src │ │ │ └── index.ts │ │ │ ├── vitest.config.mts │ │ │ ├── package.json │ │ │ └── ml-kem.spec.ts │ ├── mod.ts │ ├── samples │ │ ├── deno │ │ │ ├── deno.jsonc │ │ │ └── main.ts │ │ └── node │ │ │ ├── package.json │ │ │ └── app.js │ ├── tsconfig.json │ ├── LICENSE │ ├── CHANGES.md │ ├── dnt.ts │ └── deno.jsonc ├── dhkem-x25519 │ ├── test │ │ └── runtimes │ │ │ ├── browsers │ │ │ ├── pages │ │ │ │ └── src │ │ │ │ │ └── .gitkeep │ │ │ ├── package.json │ │ │ ├── dhkem-x25519.spec.ts │ │ │ └── playwright.config.ts │ │ │ ├── bun │ │ │ ├── .npmrc │ │ │ ├── bun.lockb │ │ │ ├── README.md │ │ │ └── package.json │ │ │ └── cloudflare │ │ │ ├── src │ │ │ └── index.ts │ │ │ ├── vitest.config.mts │ │ │ ├── dhkem-x25519.spec.ts │ │ │ └── package.json │ ├── samples │ │ ├── deno │ │ │ ├── deno.jsonc │ │ │ └── main.ts │ │ └── node │ │ │ ├── package.json │ │ │ └── app.js │ ├── mod.ts │ ├── tsconfig.json │ ├── src │ │ └── hkdfSha256.ts │ ├── LICENSE │ ├── deno.jsonc │ └── dnt.ts ├── dhkem-x448 │ ├── test │ │ └── runtimes │ │ │ ├── browsers │ │ │ ├── pages │ │ │ │ └── src │ │ │ │ │ └── .gitkeep │ │ │ ├── package.json │ │ │ ├── dhkem-x448.spec.ts │ │ │ └── playwright.config.ts │ │ │ ├── bun │ │ │ ├── .npmrc │ │ │ ├── bun.lockb │ │ │ ├── README.md │ │ │ └── package.json │ │ │ └── cloudflare │ │ │ ├── src │ │ │ └── index.ts │ │ │ ├── vitest.config.mts │ │ │ ├── dhkem-x448.spec.ts │ │ │ └── package.json │ ├── samples │ │ ├── deno │ │ │ ├── deno.jsonc │ │ │ └── main.ts │ │ └── node │ │ │ ├── package.json │ │ │ └── app.js │ ├── mod.ts │ ├── tsconfig.json │ ├── src │ │ └── hkdfSha512.ts │ ├── LICENSE │ ├── deno.jsonc │ └── dnt.ts ├── chacha20poly1305 │ ├── test │ │ └── runtimes │ │ │ ├── browsers │ │ │ ├── pages │ │ │ │ └── src │ │ │ │ │ └── .gitkeep │ │ │ ├── .npmrc │ │ │ ├── test-results │ │ │ │ └── .last-run.json │ │ │ ├── chacha20poly1305.spec.ts │ │ │ ├── package.json │ │ │ └── playwright.config.ts │ │ │ ├── bun │ │ │ ├── .npmrc │ │ │ ├── bun.lockb │ │ │ ├── README.md │ │ │ └── package.json │ │ │ └── cloudflare │ │ │ ├── src │ │ │ └── index.ts │ │ │ ├── vitest.config.mts │ │ │ ├── chacha20poly1305.spec.ts │ │ │ └── package.json │ ├── mod.ts │ ├── samples │ │ ├── deno │ │ │ ├── deno.jsonc │ │ │ └── main.ts │ │ └── node │ │ │ ├── package.json │ │ │ └── app.js │ ├── tsconfig.json │ ├── LICENSE │ ├── CHANGES.md │ ├── deno.jsonc │ └── dnt.ts ├── dhkem-secp256k1 │ ├── test │ │ └── runtimes │ │ │ ├── browsers │ │ │ ├── pages │ │ │ │ └── src │ │ │ │ │ └── .gitkeep │ │ │ ├── package.json │ │ │ ├── dhkem-secp256k1.spec.ts │ │ │ └── playwright.config.ts │ │ │ ├── bun │ │ │ ├── .npmrc │ │ │ ├── bun.lockb │ │ │ ├── README.md │ │ │ └── package.json │ │ │ └── cloudflare │ │ │ ├── src │ │ │ └── index.ts │ │ │ ├── vitest.config.mts │ │ │ ├── dhkem-secp256k1.spec.ts │ │ │ └── package.json │ ├── mod.ts │ ├── samples │ │ ├── deno │ │ │ ├── deno.jsonc │ │ │ └── main.ts │ │ └── node │ │ │ ├── package.json │ │ │ └── app.js │ ├── tsconfig.json │ ├── LICENSE │ ├── CHANGES.md │ ├── src │ │ └── dhkemSecp256k1.ts │ ├── dnt.ts │ └── deno.jsonc ├── hybridkem-x-wing │ ├── test │ │ └── runtimes │ │ │ ├── browsers │ │ │ ├── pages │ │ │ │ └── src │ │ │ │ │ └── .gitkeep │ │ │ ├── package.json │ │ │ ├── x-wing.spec.ts │ │ │ └── playwright.config.ts │ │ │ ├── bun │ │ │ ├── .npmrc │ │ │ ├── bun.lockb │ │ │ ├── README.md │ │ │ └── package.json │ │ │ └── cloudflare │ │ │ ├── src │ │ │ └── index.ts │ │ │ ├── vitest.config.mts │ │ │ ├── hybridkem-x-wing.spec.ts │ │ │ └── package.json │ ├── mod.ts │ ├── samples │ │ ├── deno │ │ │ ├── deno.jsonc │ │ │ └── main.ts │ │ └── node │ │ │ ├── package.json │ │ │ └── app.js │ ├── tsconfig.json │ ├── LICENSE │ ├── deno.jsonc │ └── dnt.ts ├── hybridkem-x25519-kyber768 │ ├── test │ │ ├── runtimes │ │ │ ├── browsers │ │ │ │ ├── pages │ │ │ │ │ └── src │ │ │ │ │ │ └── .gitkeep │ │ │ │ ├── package.json │ │ │ │ ├── hybridkem-x25519-kyber768.spec.ts │ │ │ │ └── playwright.config.ts │ │ │ ├── bun │ │ │ │ ├── .npmrc │ │ │ │ ├── bun.lockb │ │ │ │ ├── README.md │ │ │ │ └── package.json │ │ │ └── cloudflare │ │ │ │ ├── src │ │ │ │ └── index.ts │ │ │ │ ├── vitest.config.mts │ │ │ │ ├── hybridkem-x25519-kyber768.spec.ts │ │ │ │ └── package.json │ │ └── errors.test.ts │ ├── mod.ts │ ├── samples │ │ ├── deno │ │ │ ├── deno.jsonc │ │ │ └── main.ts │ │ └── node │ │ │ ├── package.json │ │ │ └── app.js │ ├── src │ │ └── kyber │ │ │ ├── errors.ts │ │ │ └── kyber768.ts │ ├── tsconfig.json │ ├── LICENSE │ ├── dnt.ts │ └── deno.jsonc └── common │ ├── tsconfig.json │ ├── src │ ├── interfaces │ │ ├── preSharedKey.ts │ │ ├── dhkemInterface.ts │ │ ├── keyScheduleParams.ts │ │ ├── senderContextParams.ts │ │ ├── recipientContextParams.ts │ │ ├── jsonWebKeyExtended.ts │ │ ├── aeadInterface.ts │ │ ├── aeadEncryptionContext.ts │ │ └── dhkemPrimitives.ts │ ├── xCryptoKey.ts │ ├── consts.ts │ ├── algorithm.ts │ ├── utils │ │ └── bignum.ts │ ├── curve │ │ ├── modular.ts │ │ └── curve.ts │ ├── identifiers.ts │ └── errors.ts │ ├── README.md │ ├── LICENSE │ ├── deno.jsonc │ ├── dnt.ts │ └── test │ └── misc.test.ts ├── utils ├── deno.json └── dntCommon.ts ├── .github ├── dependabot.yml ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── ci_docs.yml │ ├── ci_cloudflare.yml │ └── ci_bun.yml ├── tsconfig.json ├── .vscode └── settings.json ├── SECURITY.md ├── npm ├── package.json └── import_map.json └── LICENSE /packages/core/test/runtimes/browsers/pages/src/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/browsers/pages/src/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/ml-kem/test/runtimes/browsers/pages/src/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/test/runtimes/browsers/pages/src/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/dhkem-x448/test/runtimes/browsers/pages/src/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/hpke-js/samples/ts-webpack/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | app.js -------------------------------------------------------------------------------- /utils/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../deno.jsonc" 3 | } 4 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/test/runtimes/browsers/pages/src/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/test/runtimes/browsers/pages/src/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/test/runtimes/browsers/pages/src/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/bun/.npmrc: -------------------------------------------------------------------------------- 1 | @jsr:registry=https://npm.jsr.io 2 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/mod.ts: -------------------------------------------------------------------------------- 1 | export { XWing } from "./src/xWing.ts"; 2 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/test/runtimes/browsers/pages/src/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/ml-kem/test/runtimes/bun/.npmrc: -------------------------------------------------------------------------------- 1 | @jsr:registry=https://npm.jsr.io 2 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/test/runtimes/bun/.npmrc: -------------------------------------------------------------------------------- 1 | @jsr:registry=https://npm.jsr.io 2 | -------------------------------------------------------------------------------- /packages/dhkem-x448/test/runtimes/bun/.npmrc: -------------------------------------------------------------------------------- 1 | @jsr:registry=https://npm.jsr.io 2 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/test/runtimes/bun/.npmrc: -------------------------------------------------------------------------------- 1 | @jsr:registry=https://npm.jsr.io 2 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/test/runtimes/bun/.npmrc: -------------------------------------------------------------------------------- 1 | @jsr:registry=https://npm.jsr.io 2 | -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/cloudflare/.npmrc: -------------------------------------------------------------------------------- 1 | @jsr:registry=https://npm.jsr.io 2 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/test/runtimes/bun/.npmrc: -------------------------------------------------------------------------------- 1 | @jsr:registry=https://npm.jsr.io 2 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/test/runtimes/browsers/.npmrc: -------------------------------------------------------------------------------- 1 | @jsr:registry=https://npm.jsr.io 2 | -------------------------------------------------------------------------------- /packages/ml-kem/mod.ts: -------------------------------------------------------------------------------- 1 | export { MlKem1024, MlKem512, MlKem768 } from "./src/mlKem.ts"; 2 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/mod.ts: -------------------------------------------------------------------------------- 1 | export { Chacha20Poly1305 } from "./src/chacha20Poly1305.ts"; 2 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/test/runtimes/bun/.npmrc: -------------------------------------------------------------------------------- 1 | @jsr:registry=https://npm.jsr.io 2 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/mod.ts: -------------------------------------------------------------------------------- 1 | export { DhkemSecp256k1HkdfSha256 } from "./src/dhkemSecp256k1.ts"; 2 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/test/runtimes/browsers/test-results/.last-run.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": "failed" 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/samples/deno/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "dev": "deno run --watch main.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/ml-kem/samples/deno/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "dev": "deno run --watch main.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/dhkem-x448/samples/deno/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "dev": "deno run --watch main.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/hpke-js/samples/deno/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "dev": "deno run --watch main.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/mod.ts: -------------------------------------------------------------------------------- 1 | export { HybridkemX25519Kyber768 } from "./src/hybridkemX25519Kyber768.ts"; 2 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/samples/deno/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "dev": "deno run --watch main.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/core/test/runtimes/browsers/test-results/.last-run.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": "passed", 3 | "failedTests": [] 4 | } 5 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/samples/deno/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "dev": "deno run --watch main.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/samples/deno/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "dev": "deno run --watch main.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/samples/deno/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "dev": "deno run --watch main.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/core/test/runtimes/bun/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dajiaji/hpke-js/HEAD/packages/core/test/runtimes/bun/bun.lockb -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/samples/deno/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "dev": "deno run --watch main.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/ml-kem/test/runtimes/bun/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dajiaji/hpke-js/HEAD/packages/ml-kem/test/runtimes/bun/bun.lockb -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/bun/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dajiaji/hpke-js/HEAD/packages/hpke-js/test/runtimes/bun/bun.lockb -------------------------------------------------------------------------------- /packages/dhkem-x448/mod.ts: -------------------------------------------------------------------------------- 1 | export { DhkemX448HkdfSha512, X448 } from "./src/dhkemX448.ts"; 2 | export { HkdfSha512 } from "./src/hkdfSha512.ts"; 3 | -------------------------------------------------------------------------------- /packages/dhkem-x448/test/runtimes/bun/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dajiaji/hpke-js/HEAD/packages/dhkem-x448/test/runtimes/bun/bun.lockb -------------------------------------------------------------------------------- /packages/dhkem-x25519/test/runtimes/bun/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dajiaji/hpke-js/HEAD/packages/dhkem-x25519/test/runtimes/bun/bun.lockb -------------------------------------------------------------------------------- /packages/hpke-js/samples/ts-webpack/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2022", 4 | "target": "es2022" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/npm/" 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/test/runtimes/bun/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dajiaji/hpke-js/HEAD/packages/chacha20poly1305/test/runtimes/bun/bun.lockb -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/test/runtimes/bun/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dajiaji/hpke-js/HEAD/packages/dhkem-secp256k1/test/runtimes/bun/bun.lockb -------------------------------------------------------------------------------- /packages/dhkem-x25519/mod.ts: -------------------------------------------------------------------------------- 1 | export { DhkemX25519HkdfSha256, X25519 } from "./src/dhkemX25519.ts"; 2 | export { HkdfSha256 } from "./src/hkdfSha256.ts"; 3 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/test/runtimes/bun/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dajiaji/hpke-js/HEAD/packages/hybridkem-x-wing/test/runtimes/bun/bun.lockb -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [dajiaji] 4 | # open_collective: # Replace with a single Open Collective username 5 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/test/runtimes/bun/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dajiaji/hpke-js/HEAD/packages/hybridkem-x25519-kyber768/test/runtimes/bun/bun.lockb -------------------------------------------------------------------------------- /packages/hpke-js/samples/ts-webpack/index.js: -------------------------------------------------------------------------------- 1 | import * as app from "./app.js"; 2 | 3 | const test = async () => { 4 | app.test(); 5 | }; 6 | // setup exports on window 7 | window.test = { 8 | test, 9 | }; 10 | -------------------------------------------------------------------------------- /packages/core/src/interfaces/keyInfo.ts: -------------------------------------------------------------------------------- 1 | import type { AeadEncryptionContext } from "@hpke/common"; 2 | 3 | export interface KeyInfo { 4 | key: AeadEncryptionContext; 5 | baseNonce: Uint8Array; 6 | seq: number; 7 | } 8 | -------------------------------------------------------------------------------- /packages/ml-kem/test/runtimes/cloudflare/src/index.ts: -------------------------------------------------------------------------------- 1 | import { testServer } from "./server.ts"; 2 | 3 | export default { 4 | async fetch(request: Request): Promise { 5 | return await testServer(request); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/test/runtimes/cloudflare/src/index.ts: -------------------------------------------------------------------------------- 1 | import { testServer } from "./server.ts"; 2 | 3 | export default { 4 | async fetch(request: Request): Promise { 5 | return await testServer(request); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/dhkem-x448/test/runtimes/cloudflare/src/index.ts: -------------------------------------------------------------------------------- 1 | import { testServer } from "./server.ts"; 2 | 3 | export default { 4 | async fetch(request: Request): Promise { 5 | return await testServer(request); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/test/runtimes/cloudflare/src/index.ts: -------------------------------------------------------------------------------- 1 | import { testServer } from "./server.ts"; 2 | 3 | export default { 4 | async fetch(request: Request): Promise { 5 | return await testServer(request); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/core/src/interfaces/encapsulator.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The sender specific interface for an encryption context. 3 | */ 4 | export interface Encapsulator { 5 | /** The encapsulated key generated by the sender. */ 6 | enc: ArrayBuffer; 7 | } 8 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/test/runtimes/cloudflare/src/index.ts: -------------------------------------------------------------------------------- 1 | import { testServer } from "./server.ts"; 2 | 3 | export default { 4 | async fetch(request: Request): Promise { 5 | return await testServer(request); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/test/runtimes/cloudflare/src/index.ts: -------------------------------------------------------------------------------- 1 | import { testServer } from "./server.ts"; 2 | 3 | export default { 4 | async fetch(request: Request): Promise { 5 | return await testServer(request); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/test/runtimes/cloudflare/src/index.ts: -------------------------------------------------------------------------------- 1 | import { testServer } from "./server.ts"; 2 | 3 | export default { 4 | async fetch(request: Request): Promise { 5 | return await testServer(request); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/core/test/runtimes/cloudflare/src/index.ts: -------------------------------------------------------------------------------- 1 | import { testServer } from "./server.ts"; 2 | 3 | export default { 4 | async fetch(request, _env, _ctx): Promise { 5 | return await testServer(request); 6 | }, 7 | } satisfies ExportedHandler; 8 | -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/cloudflare/src/index.ts: -------------------------------------------------------------------------------- 1 | import { testServer } from "./server.ts"; 2 | 3 | export default { 4 | async fetch(request: Request): Promise { 5 | return await testServer(request); 6 | }, 7 | } satisfies ExportedHandler; 8 | -------------------------------------------------------------------------------- /packages/common/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2022", 4 | "target": "es2022", 5 | "noEmit": true, 6 | "allowImportingTsExtensions": true 7 | }, 8 | "include": [ 9 | "mod.ts", 10 | "src/**/*" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /packages/common/src/interfaces/preSharedKey.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The pre-shared key interface. 3 | */ 4 | export interface PreSharedKey { 5 | /** The key identifier. */ 6 | id: ArrayBuffer; 7 | 8 | /** The body of the pre-shared key. */ 9 | key: ArrayBuffer; 10 | } 11 | -------------------------------------------------------------------------------- /packages/core/src/utils/emitNotSupported.ts: -------------------------------------------------------------------------------- 1 | import { NotSupportedError } from "@hpke/common"; 2 | 3 | export function emitNotSupported(): Promise { 4 | return new Promise((_resolve, reject) => { 5 | reject(new NotSupportedError("Not supported")); 6 | }); 7 | } 8 | -------------------------------------------------------------------------------- /packages/core/src/interfaces/responses.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The response of the single-shot seal API. 3 | */ 4 | export interface CipherSuiteSealResponse { 5 | /** The ciphertext as bytes. */ 6 | ct: ArrayBuffer; 7 | /** The encapsulated key. */ 8 | enc: ArrayBuffer; 9 | } 10 | -------------------------------------------------------------------------------- /packages/common/src/interfaces/dhkemInterface.ts: -------------------------------------------------------------------------------- 1 | import type { KdfInterface } from "./kdfInterface.ts"; 2 | import type { KemInterface } from "./kemInterface.ts"; 3 | 4 | /** 5 | * The DHKEM interface. 6 | */ 7 | export interface DhkemInterface extends KemInterface { 8 | readonly kdf: KdfInterface; 9 | } 10 | -------------------------------------------------------------------------------- /packages/core/test/runtimes/browsers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-browsers-hpke-core", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "npx playwright test" 7 | }, 8 | "devDependencies": { 9 | "@playwright/test": "^1.55.0", 10 | "http-server": "^14.1.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/browsers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-browsers-hpke-js", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "npx playwright test" 7 | }, 8 | "devDependencies": { 9 | "@playwright/test": "^1.55.0", 10 | "http-server": "^14.1.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/core/test/runtimes/bun/README.md: -------------------------------------------------------------------------------- 1 | # bunx 2 | 3 | To install dependencies: 4 | 5 | ```bash 6 | bun install 7 | ``` 8 | 9 | To run: 10 | 11 | ```bash 12 | bun run index.ts 13 | ``` 14 | 15 | This project was created using `bun init` in bun v1.1.22. [Bun](https://bun.sh) 16 | is a fast all-in-one JavaScript runtime. 17 | -------------------------------------------------------------------------------- /packages/ml-kem/test/runtimes/browsers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-browsers-hpke-ml-kem", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "npx playwright test" 7 | }, 8 | "devDependencies": { 9 | "@playwright/test": "^1.55.0", 10 | "http-server": "^14.1.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/ml-kem/test/runtimes/bun/README.md: -------------------------------------------------------------------------------- 1 | # bunx 2 | 3 | To install dependencies: 4 | 5 | ```bash 6 | bun install 7 | ``` 8 | 9 | To run: 10 | 11 | ```bash 12 | bun run index.ts 13 | ``` 14 | 15 | This project was created using `bun init` in bun v1.1.22. [Bun](https://bun.sh) 16 | is a fast all-in-one JavaScript runtime. 17 | -------------------------------------------------------------------------------- /packages/dhkem-x448/test/runtimes/bun/README.md: -------------------------------------------------------------------------------- 1 | # bunx 2 | 3 | To install dependencies: 4 | 5 | ```bash 6 | bun install 7 | ``` 8 | 9 | To run: 10 | 11 | ```bash 12 | bun run index.ts 13 | ``` 14 | 15 | This project was created using `bun init` in bun v1.1.22. [Bun](https://bun.sh) 16 | is a fast all-in-one JavaScript runtime. 17 | -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/bun/README.md: -------------------------------------------------------------------------------- 1 | # bunx 2 | 3 | To install dependencies: 4 | 5 | ```bash 6 | bun install 7 | ``` 8 | 9 | To run: 10 | 11 | ```bash 12 | bun run index.ts 13 | ``` 14 | 15 | This project was created using `bun init` in bun v1.1.22. [Bun](https://bun.sh) 16 | is a fast all-in-one JavaScript runtime. 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2022", 4 | "target": "es2022", 5 | "noEmit": true, 6 | "allowImportingTsExtensions": true 7 | }, 8 | "include": [ 9 | "packages/**/*" 10 | ], 11 | "exclude": [ 12 | "packages/**/samples/**/*", 13 | "packages/**/test/**/*" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/test/runtimes/bun/README.md: -------------------------------------------------------------------------------- 1 | # bunx 2 | 3 | To install dependencies: 4 | 5 | ```bash 6 | bun install 7 | ``` 8 | 9 | To run: 10 | 11 | ```bash 12 | bun run index.ts 13 | ``` 14 | 15 | This project was created using `bun init` in bun v1.1.22. [Bun](https://bun.sh) 16 | is a fast all-in-one JavaScript runtime. 17 | -------------------------------------------------------------------------------- /packages/core/test/runtimes/cloudflare/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; 2 | 3 | export default defineWorkersConfig({ 4 | test: { 5 | poolOptions: { 6 | workers: { 7 | wrangler: { configPath: "./wrangler.toml" }, 8 | }, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/test/runtimes/bun/README.md: -------------------------------------------------------------------------------- 1 | # bunx 2 | 3 | To install dependencies: 4 | 5 | ```bash 6 | bun install 7 | ``` 8 | 9 | To run: 10 | 11 | ```bash 12 | bun run index.ts 13 | ``` 14 | 15 | This project was created using `bun init` in bun v1.1.22. [Bun](https://bun.sh) 16 | is a fast all-in-one JavaScript runtime. 17 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/test/runtimes/browsers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-browsers-hpke-dhkem-x25519", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "npx playwright test" 7 | }, 8 | "devDependencies": { 9 | "@playwright/test": "^1.55.0", 10 | "http-server": "^14.1.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/test/runtimes/bun/README.md: -------------------------------------------------------------------------------- 1 | # bunx 2 | 3 | To install dependencies: 4 | 5 | ```bash 6 | bun install 7 | ``` 8 | 9 | To run: 10 | 11 | ```bash 12 | bun run index.ts 13 | ``` 14 | 15 | This project was created using `bun init` in bun v1.1.22. [Bun](https://bun.sh) 16 | is a fast all-in-one JavaScript runtime. 17 | -------------------------------------------------------------------------------- /packages/dhkem-x448/test/runtimes/browsers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-browsers-hpke-dhkem-x448", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "npx playwright test" 7 | }, 8 | "devDependencies": { 9 | "@playwright/test": "^1.55.0", 10 | "http-server": "^14.1.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/bun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bun", 3 | "module": "src/index.ts", 4 | "type": "module", 5 | "devDependencies": { 6 | "@types/bun": "latest" 7 | }, 8 | "peerDependencies": { 9 | "typescript": "^5.5.4" 10 | }, 11 | "dependencies": { 12 | "hpke-js": "link:hpke-js" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/test/runtimes/bun/README.md: -------------------------------------------------------------------------------- 1 | # bunx 2 | 3 | To install dependencies: 4 | 5 | ```bash 6 | bun install 7 | ``` 8 | 9 | To run: 10 | 11 | ```bash 12 | bun run index.ts 13 | ``` 14 | 15 | This project was created using `bun init` in bun v1.1.22. [Bun](https://bun.sh) 16 | is a fast all-in-one JavaScript runtime. 17 | -------------------------------------------------------------------------------- /packages/core/test/runtimes/bun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bun", 3 | "module": "src/index.ts", 4 | "type": "module", 5 | "devDependencies": { 6 | "@types/bun": "latest" 7 | }, 8 | "peerDependencies": { 9 | "typescript": "^5.5.4" 10 | }, 11 | "dependencies": { 12 | "@hpke/core": "link:@hpke/core" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2022", 4 | "target": "es2022", 5 | "paths": { 6 | "@hpke/common": ["../common/mod.ts"] 7 | }, 8 | "noEmit": true, 9 | "allowImportingTsExtensions": true 10 | }, 11 | "include": [ 12 | "mod.ts", 13 | "src/**/*" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/dhkem-x448/test/runtimes/cloudflare/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; 2 | 3 | export default defineWorkersConfig({ 4 | test: { 5 | poolOptions: { 6 | workers: { 7 | wrangler: { configPath: "./wrangler.toml" }, 8 | }, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/hpke-js/samples/ts-webpack/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test 5 | 6 | 9 | 10 | 11 |
See developer console.
12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/cloudflare/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; 2 | 3 | export default defineWorkersConfig({ 4 | test: { 5 | poolOptions: { 6 | workers: { 7 | wrangler: { configPath: "./wrangler.toml" }, 8 | }, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/ml-kem/test/runtimes/cloudflare/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; 2 | 3 | export default defineWorkersConfig({ 4 | test: { 5 | poolOptions: { 6 | workers: { 7 | wrangler: { configPath: "./wrangler.toml" }, 8 | }, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/test/runtimes/browsers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-browsers-hpke-dhkem-secp256k1", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "npx playwright test" 7 | }, 8 | "devDependencies": { 9 | "@playwright/test": "^1.55.0", 10 | "http-server": "^14.1.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/test/runtimes/cloudflare/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; 2 | 3 | export default defineWorkersConfig({ 4 | test: { 5 | poolOptions: { 6 | workers: { 7 | wrangler: { configPath: "./wrangler.toml" }, 8 | }, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/test/runtimes/cloudflare/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; 2 | 3 | export default defineWorkersConfig({ 4 | test: { 5 | poolOptions: { 6 | workers: { 7 | wrangler: { configPath: "./wrangler.toml" }, 8 | }, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/test/runtimes/browsers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-browsers-hpke-hybridkem-x-wing", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "npx playwright test" 7 | }, 8 | "devDependencies": { 9 | "@playwright/test": "^1.55.0", 10 | "http-server": "^14.1.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/test/runtimes/bun/README.md: -------------------------------------------------------------------------------- 1 | # bunx 2 | 3 | To install dependencies: 4 | 5 | ```bash 6 | bun install 7 | ``` 8 | 9 | To run: 10 | 11 | ```bash 12 | bun run index.ts 13 | ``` 14 | 15 | This project was created using `bun init` in bun v1.1.22. [Bun](https://bun.sh) 16 | is a fast all-in-one JavaScript runtime. 17 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/test/runtimes/cloudflare/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; 2 | 3 | export default defineWorkersConfig({ 4 | test: { 5 | poolOptions: { 6 | workers: { 7 | wrangler: { configPath: "./wrangler.toml" }, 8 | }, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/test/runtimes/cloudflare/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; 2 | 3 | export default defineWorkersConfig({ 4 | test: { 5 | poolOptions: { 6 | workers: { 7 | wrangler: { configPath: "./wrangler.toml" }, 8 | }, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/test/runtimes/cloudflare/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; 2 | 3 | export default defineWorkersConfig({ 4 | test: { 5 | poolOptions: { 6 | workers: { 7 | wrangler: { configPath: "./wrangler.toml" }, 8 | }, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/test/runtimes/browsers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-browsers-hpke-hybridkem-x25519-kyber768", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "npx playwright test" 7 | }, 8 | "devDependencies": { 9 | "@playwright/test": "^1.55.0", 10 | "http-server": "^14.1.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true, 3 | "deno.lint": true, 4 | "deno.config": "../deno.jsonc", 5 | "[typescript]": { 6 | "editor.defaultFormatter": "denoland.vscode-deno", 7 | "editor.formatOnSave": true 8 | }, 9 | "[javascript]": { 10 | "editor.defaultFormatter": "denoland.vscode-deno", 11 | "editor.formatOnSave": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/core/test/utils.ts: -------------------------------------------------------------------------------- 1 | import { dirname, fromFileUrl, join } from "@std/path"; 2 | 3 | import { isDeno } from "@hpke/common"; 4 | 5 | export function getPath(name: string): string { 6 | const currentPath = dirname(fromFileUrl(import.meta.url)); 7 | if (isDeno()) { 8 | return join(currentPath, name); 9 | } 10 | return join(currentPath, "../../", name); 11 | } 12 | -------------------------------------------------------------------------------- /packages/hpke-js/test/utils.ts: -------------------------------------------------------------------------------- 1 | import { dirname, fromFileUrl, join } from "@std/path"; 2 | 3 | import { isDeno } from "@hpke/common"; 4 | 5 | export function getPath(name: string): string { 6 | const currentPath = dirname(fromFileUrl(import.meta.url)); 7 | if (isDeno()) { 8 | return join(currentPath, name); 9 | } 10 | return join(currentPath, "../../", name); 11 | } 12 | -------------------------------------------------------------------------------- /packages/ml-kem/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2022", 4 | "target": "es2022", 5 | "paths": { 6 | "@hpke/common": ["../common/mod.ts"], 7 | "@hpke/core": ["../core/mod.ts"] 8 | }, 9 | "noEmit": true, 10 | "allowImportingTsExtensions": true 11 | }, 12 | "include": [ 13 | "mod.ts", 14 | "src/**/*" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2022", 4 | "target": "es2022", 5 | "paths": { 6 | "@hpke/common": ["../common/mod.ts"], 7 | "@hpke/core": ["../core/mod.ts"] 8 | }, 9 | "noEmit": true, 10 | "allowImportingTsExtensions": true 11 | }, 12 | "include": [ 13 | "mod.ts", 14 | "src/**/*" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/dhkem-x448/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2022", 4 | "target": "es2022", 5 | "paths": { 6 | "@hpke/common": ["../common/mod.ts"], 7 | "@hpke/core": ["../core/mod.ts"] 8 | }, 9 | "noEmit": true, 10 | "allowImportingTsExtensions": true 11 | }, 12 | "include": [ 13 | "mod.ts", 14 | "src/**/*" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/hpke-js/samples/ts-node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-node-hpke-sample", 3 | "version": "1.0.0", 4 | "type": "module", 5 | "description": "", 6 | "main": "app.ts", 7 | "author": "Ajitomi Daisuke (https://github.com/dajiaji)", 8 | "license": "MIT", 9 | "dependencies": { 10 | "@hpke/core": "^1.7.5", 11 | "ts-node": "^10.7.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/hpke-js/samples/ts-webpack/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | module.exports = [{ 3 | mode: "development", 4 | entry: "./index.js", 5 | watch: true, 6 | plugins: [], 7 | resolve: { 8 | alias: { 9 | "@hpke/core": path.resolve("./node_modules/@hpke/core"), 10 | }, 11 | fallback: { 12 | "crypto": false, 13 | }, 14 | }, 15 | }]; 16 | -------------------------------------------------------------------------------- /packages/ml-kem/test/runtimes/bun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "module": "src/index.ts", 4 | "type": "module", 5 | "devDependencies": { 6 | "@types/bun": "latest" 7 | }, 8 | "peerDependencies": { 9 | "typescript": "^5.5.4" 10 | }, 11 | "dependencies": { 12 | "@hpke/core": "link:@hpke/core", 13 | "@hpke/ml-kem": "link:@hpke/ml-kem" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | | Version | Supported | 6 | | ------- | ------------------ | 7 | | 1.6.5 | :white_check_mark: | 8 | | < 1.6.4 | :x: | 9 | 10 | ## Reporting a Vulnerability 11 | 12 | Please use maintainer's email: dajiaji@gmail.com 13 | 14 | DO NOT REPORT SECURITY VULNERABILITIES VIA THE ISSUES OF THIS REPOSITORY. 15 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2022", 4 | "target": "es2022", 5 | "paths": { 6 | "@hpke/common": ["../common/mod.ts"], 7 | "@hpke/core": ["../core/mod.ts"] 8 | }, 9 | "noEmit": true, 10 | "allowImportingTsExtensions": true 11 | }, 12 | "include": [ 13 | "mod.ts", 14 | "src/**/*" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/browsers/hpke.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "@playwright/test"; 2 | 3 | test("basic test", async ({ page }) => { 4 | await page.goto("./index.html"); 5 | await page.click("text=run"); 6 | await page.waitForTimeout(5000); 7 | await expect(page.locator("id=pass")).toHaveText("45"); 8 | await expect(page.locator("id=fail")).toHaveText("0"); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/ml-kem/test/runtimes/browsers/ml-kem.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "@playwright/test"; 2 | 3 | test("basic test", async ({ page }) => { 4 | await page.goto("./index.html"); 5 | await page.click("text=run"); 6 | await page.waitForTimeout(5000); 7 | await expect(page.locator("id=pass")).toHaveText("18"); 8 | await expect(page.locator("id=fail")).toHaveText("0"); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/dhkem-x448/test/runtimes/browsers/dhkem-x448.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "@playwright/test"; 2 | 3 | test("basic test", async ({ page }) => { 4 | await page.goto("./index.html"); 5 | await page.click("text=run"); 6 | await page.waitForTimeout(5000); 7 | await expect(page.locator("id=pass")).toHaveText("6"); 8 | await expect(page.locator("id=fail")).toHaveText("0"); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/dhkem-x448/test/runtimes/bun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "module": "src/index.ts", 4 | "type": "module", 5 | "devDependencies": { 6 | "@types/bun": "latest" 7 | }, 8 | "peerDependencies": { 9 | "typescript": "^5.5.4" 10 | }, 11 | "dependencies": { 12 | "@hpke/core": "link:@hpke/core", 13 | "@hpke/dhkem-x448": "link:@hpke/dhkem-x448" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/test/runtimes/browsers/dhkem-x25519.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "@playwright/test"; 2 | 3 | test("basic test", async ({ page }) => { 4 | await page.goto("./index.html"); 5 | await page.click("text=run"); 6 | await page.waitForTimeout(5000); 7 | await expect(page.locator("id=pass")).toHaveText("6"); 8 | await expect(page.locator("id=fail")).toHaveText("0"); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/test/runtimes/bun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "module": "src/index.ts", 4 | "type": "module", 5 | "devDependencies": { 6 | "@types/bun": "latest" 7 | }, 8 | "peerDependencies": { 9 | "typescript": "^5.5.4" 10 | }, 11 | "dependencies": { 12 | "@hpke/core": "link:@hpke/core", 13 | "@hpke/dhkem-x25519": "link:@hpke/dhkem-x25519" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/test/runtimes/browsers/x-wing.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "@playwright/test"; 2 | 3 | test("basic test", async ({ page }) => { 4 | await page.goto("./index.html"); 5 | await page.click("text=run"); 6 | await page.waitForTimeout(5000); 7 | await expect(page.locator("id=pass")).toHaveText("6"); 8 | await expect(page.locator("id=fail")).toHaveText("0"); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/test/runtimes/browsers/dhkem-secp256k1.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "@playwright/test"; 2 | 3 | test("basic test", async ({ page }) => { 4 | await page.goto("./index.html"); 5 | await page.click("text=run"); 6 | await page.waitForTimeout(5000); 7 | await expect(page.locator("id=pass")).toHaveText("6"); 8 | await expect(page.locator("id=fail")).toHaveText("0"); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/test/runtimes/browsers/chacha20poly1305.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "@playwright/test"; 2 | 3 | test("basic test", async ({ page }) => { 4 | await page.goto("./index.html"); 5 | await page.click("text=run"); 6 | await page.waitForTimeout(5000); 7 | await expect(page.locator("id=pass")).toHaveText("9"); 8 | await expect(page.locator("id=fail")).toHaveText("0"); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/test/runtimes/bun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bun", 3 | "module": "src/index.ts", 4 | "type": "module", 5 | "devDependencies": { 6 | "@types/bun": "latest" 7 | }, 8 | "peerDependencies": { 9 | "typescript": "^5.5.4" 10 | }, 11 | "dependencies": { 12 | "@hpke/chacha20poly1305": "link:@hpke/chacha20poly1305", 13 | "@hpke/core": "link:@hpke/core" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/test/runtimes/bun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "module": "src/index.ts", 4 | "type": "module", 5 | "devDependencies": { 6 | "@types/bun": "latest" 7 | }, 8 | "peerDependencies": { 9 | "typescript": "^5.5.4" 10 | }, 11 | "dependencies": { 12 | "@hpke/core": "link:@hpke/core", 13 | "@hpke/dhkem-secp256k1": "link:@hpke/dhkem-secp256k1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/test/runtimes/bun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "module": "src/index.ts", 4 | "type": "module", 5 | "devDependencies": { 6 | "@types/bun": "latest" 7 | }, 8 | "peerDependencies": { 9 | "typescript": "^5.5.4" 10 | }, 11 | "dependencies": { 12 | "@hpke/core": "link:@hpke/core", 13 | "@hpke/hybridkem-x-wing": "link:@hpke/hybridkem-x-wing" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/test/runtimes/browsers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-browsers-hpke-chacha20poly1305", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "npx playwright test" 7 | }, 8 | "devDependencies": { 9 | "@playwright/test": "^1.55.0", 10 | "http-server": "^14.1.1" 11 | }, 12 | "dependencies": { 13 | "@hpke/core": "npm:@jsr/hpke__core@^1.7.4" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/test/runtimes/browsers/hybridkem-x25519-kyber768.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "@playwright/test"; 2 | 3 | test("basic test", async ({ page }) => { 4 | await page.goto("./index.html"); 5 | await page.click("text=run"); 6 | await page.waitForTimeout(5000); 7 | await expect(page.locator("id=pass")).toHaveText("6"); 8 | await expect(page.locator("id=fail")).toHaveText("0"); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/core/src/mutex.ts: -------------------------------------------------------------------------------- 1 | export class Mutex { 2 | #locked: Promise = Promise.resolve(); 3 | 4 | async lock(): Promise<() => void> { 5 | let releaseLock!: () => void; 6 | const nextLock = new Promise((resolve) => { 7 | releaseLock = resolve; 8 | }); 9 | const previousLock = this.#locked; 10 | this.#locked = nextLock; 11 | await previousLock; 12 | return releaseLock; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/hpke-js/samples/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "samples-node-hpke-js", 3 | "version": "1.0.0", 4 | "description": "A sample code of hpke-js.", 5 | "type": "module", 6 | "main": "app.js", 7 | "author": "Ajitomi Daisuke (https://github.com/dajiaji)", 8 | "license": "MIT", 9 | "scripts": { 10 | "test": "node app.js" 11 | }, 12 | "dependencies": { 13 | "hpke-js": "^1.6.5" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/core/samples/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "samples-node-hpke-core", 3 | "version": "1.0.0", 4 | "description": "A sample code of @hpke/core.", 5 | "type": "module", 6 | "main": "app.js", 7 | "author": "Ajitomi Daisuke (https://github.com/dajiaji)", 8 | "license": "MIT", 9 | "scripts": { 10 | "test": "node app.js" 11 | }, 12 | "dependencies": { 13 | "@hpke/core": "^1.7.5" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/test/runtimes/bun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "module": "src/index.ts", 4 | "type": "module", 5 | "devDependencies": { 6 | "@types/bun": "latest" 7 | }, 8 | "peerDependencies": { 9 | "typescript": "^5.0.0" 10 | }, 11 | "dependencies": { 12 | "@hpke/core": "link:@hpke/core", 13 | "@hpke/hybridkem-x25519-kyber768": "link:@hpke/hybridkem-x25519-kyber768" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2022", 4 | "target": "es2022", 5 | "paths": { 6 | "@hpke/common": ["../common/mod.ts"], 7 | "@hpke/core": ["../core/mod.ts"], 8 | "@hpke/dhkem-x25519": ["../dhkem-x25519/mod.ts"] 9 | }, 10 | "noEmit": true, 11 | "allowImportingTsExtensions": true 12 | }, 13 | "include": [ 14 | "mod.ts", 15 | "src/**/*" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /packages/hpke-js/samples/ts-webpack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-webpack", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "start": "http-server .", 6 | "build": "tsc app.ts", 7 | "bundle": "webpack" 8 | }, 9 | "devDependencies": { 10 | "http-server": "^14.1.1", 11 | "typescript": "^5.5.4", 12 | "webpack": "^5.94.0", 13 | "webpack-cli": "^5.1.4" 14 | }, 15 | "dependencies": { 16 | "@hpke/core": "^1.7.5" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/ml-kem/samples/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "samples-node-hpke-ml-kem", 3 | "version": "1.0.0", 4 | "description": "A sample code of @hpke/ml-kem.", 5 | "type": "module", 6 | "main": "app.js", 7 | "author": "Ajitomi Daisuke (https://github.com/dajiaji)", 8 | "license": "MIT", 9 | "scripts": { 10 | "test": "node app.js" 11 | }, 12 | "dependencies": { 13 | "@hpke/core": "^1.7.5", 14 | "@hpke/ml-kem": "^0.2.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /npm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hpke-js", 3 | "private": true, 4 | "workspaces": [ 5 | "packages/common", 6 | "packages/core", 7 | "packages/chacha20poly1305", 8 | "packages/dhkem-x25519", 9 | "packages/dhkem-x448", 10 | "packages/dhkem-secp256k1", 11 | "packages/hybridkem-x-wing", 12 | "packages/hpke-js", 13 | "packages/ml-kem", 14 | "test/**/*/runtimes/browsers", 15 | "test/**/*/runtimes/cloudflare", 16 | "samples/**/*" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/dhkem-x448/samples/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "samples-node-hpke-dhkem-x448", 3 | "version": "1.0.0", 4 | "description": "A sample code of @hpke/core.", 5 | "type": "module", 6 | "main": "app.js", 7 | "author": "Ajitomi Daisuke (https://github.com/dajiaji)", 8 | "license": "MIT", 9 | "scripts": { 10 | "test": "node app.js" 11 | }, 12 | "dependencies": { 13 | "@hpke/core": "^1.7.5", 14 | "@hpke/dhkem-x448": "^1.6.4" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/src/kyber/errors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The base error class of kyber. 3 | */ 4 | export class KyberError extends Error { 5 | public constructor(e: unknown) { 6 | let message: string; 7 | 8 | if (e instanceof Error) { 9 | message = e.message; 10 | } else if (typeof e === "string") { 11 | message = e; 12 | } else { 13 | message = ""; 14 | } 15 | super(message); 16 | 17 | this.name = this.constructor.name; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/samples/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "samples-node-hpke-dhkem-x25519", 3 | "version": "1.0.0", 4 | "description": "A sample code of @hpke/core.", 5 | "type": "module", 6 | "main": "app.js", 7 | "author": "Ajitomi Daisuke (https://github.com/dajiaji)", 8 | "license": "MIT", 9 | "scripts": { 10 | "test": "node app.js" 11 | }, 12 | "dependencies": { 13 | "@hpke/core": "^1.7.5", 14 | "@hpke/dhkem-x25519": "^1.6.4" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/samples/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "samples-node-hpke-chacha20poly1305", 3 | "version": "1.0.0", 4 | "description": "A sample code of @hpke/core.", 5 | "type": "module", 6 | "main": "app.js", 7 | "author": "Ajitomi Daisuke (https://github.com/dajiaji)", 8 | "license": "MIT", 9 | "scripts": { 10 | "test": "node app.js" 11 | }, 12 | "dependencies": { 13 | "@hpke/chacha20poly1305": "^1.7.1", 14 | "@hpke/core": "^1.7.5" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/samples/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "samples-node-hpke-dhkem-secp256k1", 3 | "version": "1.0.0", 4 | "description": "A sample code of @hpke/core.", 5 | "type": "module", 6 | "main": "app.js", 7 | "author": "Ajitomi Daisuke (https://github.com/dajiaji)", 8 | "license": "MIT", 9 | "scripts": { 10 | "test": "node app.js" 11 | }, 12 | "dependencies": { 13 | "@hpke/core": "^1.7.5", 14 | "@hpke/dhkem-secp256k1": "^1.6.4" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2022", 4 | "target": "es2022", 5 | "paths": { 6 | "@hpke/common": ["../common/mod.ts"], 7 | "@hpke/core": ["../core/mod.ts"], 8 | "@hpke/dhkem-x25519": ["../dhkem-x25519/mod.ts"], 9 | "@noble/*": ["../../npm/node_modules/@noble/*"] 10 | }, 11 | "noEmit": true, 12 | "allowImportingTsExtensions": true 13 | }, 14 | "include": [ 15 | "mod.ts", 16 | "src/**/*" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2022", 4 | "target": "es2022", 5 | "paths": { 6 | "@hpke/common": ["../common/mod.ts"], 7 | "@hpke/core": ["../core/mod.ts"], 8 | "@hpke/dhkem-x25519": ["../dhkem-x25519/mod.ts"], 9 | "@noble/*": ["../../npm/node_modules/@noble/*"] 10 | }, 11 | "noEmit": true, 12 | "allowImportingTsExtensions": true 13 | }, 14 | "include": [ 15 | "mod.ts", 16 | "src/**/*" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/samples/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "samples-node-hpke-hybridkem-x-wing", 3 | "version": "1.0.0", 4 | "description": "A sample code of @hpke/hybridkem-x-wing.", 5 | "type": "module", 6 | "main": "app.js", 7 | "author": "Ajitomi Daisuke (https://github.com/dajiaji)", 8 | "license": "MIT", 9 | "scripts": { 10 | "test": "node app.js" 11 | }, 12 | "dependencies": { 13 | "@hpke/core": "^1.7.5", 14 | "@hpke/hybridkem-x-wing": "^0.6.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/samples/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "samples-node-hpke-hybridkem-x25519-kyber768", 3 | "version": "1.0.0", 4 | "description": "A sample code of @hpke/core.", 5 | "type": "module", 6 | "main": "app.js", 7 | "author": "Ajitomi Daisuke (https://github.com/dajiaji)", 8 | "license": "MIT", 9 | "scripts": { 10 | "test": "node app.js" 11 | }, 12 | "dependencies": { 13 | "@hpke/core": "^1.7.5", 14 | "@hpke/hybridkem-x25519-kyber768": "^1.6.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/core/src/interfaces/aeadParams.ts: -------------------------------------------------------------------------------- 1 | import type { AeadInterface } from "@hpke/common"; 2 | 3 | /** 4 | * The AEAD parameters for building a encryption context. 5 | */ 6 | export interface AeadParams { 7 | /** The Aead indentifier. */ 8 | aead: AeadInterface; 9 | 10 | /** A secret used for the secret export interface. */ 11 | exporterSecret: ArrayBuffer; 12 | 13 | /** A secret key. */ 14 | key?: ArrayBuffer; 15 | 16 | /** A base nonce. */ 17 | baseNonce?: Uint8Array; 18 | 19 | /** A sequence number. */ 20 | seq?: number; 21 | } 22 | -------------------------------------------------------------------------------- /packages/common/src/interfaces/keyScheduleParams.ts: -------------------------------------------------------------------------------- 1 | import type { PreSharedKey } from "./preSharedKey.ts"; 2 | 3 | /** 4 | * The common parameters used to setup the `EncryptionContext`. 5 | */ 6 | export interface KeyScheduleParams { 7 | /** Application supplied information. The maximum length is 128 bytes. */ 8 | info?: ArrayBuffer; 9 | 10 | /** 11 | * A pre-shared key (PSK) held by both the sender and recipient. 12 | * The PSK should have at least 32 bytes :and the maxmum length of the PSK is 128 bytes. 13 | */ 14 | psk?: PreSharedKey; 15 | } 16 | -------------------------------------------------------------------------------- /packages/common/src/interfaces/senderContextParams.ts: -------------------------------------------------------------------------------- 1 | import type { KeyScheduleParams } from "./keyScheduleParams.ts"; 2 | 3 | /** 4 | * The parameters used to setup the `SenderContext`. 5 | */ 6 | export interface SenderContextParams extends KeyScheduleParams { 7 | /** A recipient public key. */ 8 | recipientPublicKey: CryptoKey; 9 | 10 | /** A sender private key or a key pair for Auth mode. */ 11 | senderKey?: CryptoKey | CryptoKeyPair; 12 | 13 | /** DO NOT USE. FOR DEBUGGING/TESTING PURPOSES ONLY. */ 14 | ekm?: CryptoKeyPair | ArrayBuffer; 15 | } 16 | -------------------------------------------------------------------------------- /packages/common/src/interfaces/recipientContextParams.ts: -------------------------------------------------------------------------------- 1 | import type { KeyScheduleParams } from "./keyScheduleParams.ts"; 2 | 3 | /** 4 | * The parameters used to setup the `RecipientContext`. 5 | */ 6 | export interface RecipientContextParams extends KeyScheduleParams { 7 | /** A recipient private key or a key pair. */ 8 | recipientKey: CryptoKey | CryptoKeyPair; 9 | 10 | /** A byte string of the encapsulated key received from a sender. */ 11 | enc: ArrayBuffer; 12 | 13 | /** A sender public key for Auth mode. */ 14 | senderPublicKey?: CryptoKey; 15 | } 16 | -------------------------------------------------------------------------------- /packages/hpke-js/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2022", 4 | "target": "es2022", 5 | "paths": { 6 | "@hpke/common": ["../common/mod.ts"], 7 | "@hpke/core": ["../core/mod.ts"], 8 | "@hpke/chacha20poly1305": ["../chacha20poly1305/mod.ts"], 9 | "@hpke/dhkem-x25519": ["../dhkem-x25519/mod.ts"], 10 | "@hpke/dhkem-x448": ["../dhkem-x448/mod.ts"] 11 | }, 12 | "noEmit": true, 13 | "allowImportingTsExtensions": true 14 | }, 15 | "include": [ 16 | "mod.ts", 17 | "src/**/*" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /packages/hpke-js/src/kems/dhkemP256.ts: -------------------------------------------------------------------------------- 1 | import { Dhkem, Ec, KemId } from "@hpke/common"; 2 | import { HkdfSha256 } from "@hpke/dhkem-x25519"; 3 | 4 | export class DhkemP256HkdfSha256 extends Dhkem { 5 | override id: KemId = KemId.DhkemP256HkdfSha256; 6 | override secretSize: number = 32; 7 | override encSize: number = 65; 8 | override publicKeySize: number = 65; 9 | override privateKeySize: number = 32; 10 | 11 | constructor() { 12 | const kdf = new HkdfSha256(); 13 | const prim = new Ec(KemId.DhkemP256HkdfSha256, kdf); 14 | super(KemId.DhkemP256HkdfSha256, prim, kdf); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/hpke-js/src/kems/dhkemP384.ts: -------------------------------------------------------------------------------- 1 | import { Dhkem, Ec, KemId } from "@hpke/common"; 2 | import { HkdfSha384 } from "../kdfs/hkdfSha384.ts"; 3 | 4 | export class DhkemP384HkdfSha384 extends Dhkem { 5 | override id: KemId = KemId.DhkemP384HkdfSha384; 6 | override secretSize: number = 48; 7 | override encSize: number = 97; 8 | override publicKeySize: number = 97; 9 | override privateKeySize: number = 48; 10 | 11 | constructor() { 12 | const kdf = new HkdfSha384(); 13 | const prim = new Ec(KemId.DhkemP384HkdfSha384, kdf); 14 | super(KemId.DhkemP384HkdfSha384, prim, kdf); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | ## Describe the bug 10 | 11 | A clear and concise description of what the bug is. 12 | 13 | ## To Reproduce 14 | 15 | Steps to reproduce the behavior: 16 | 17 | 1. Go to '...' 18 | 2. Click on '....' 19 | 3. Scroll down to '....' 20 | 4. See error 21 | 22 | ## Expected behavior 23 | 24 | A clear and concise description of what you expected to happen. 25 | 26 | ## Additional context 27 | 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /packages/core/src/interfaces/exporter.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The exporter interface. 3 | */ 4 | export interface Exporter { 5 | /** 6 | * Exports a secret using a variable-length pseudorandom function. 7 | * 8 | * If the error occurred, throws `ExportError`. 9 | * 10 | * @param exporterContext An exporter context string as bytes. The maximum length is 128 bytes. 11 | * @param len A desired length in bytes of the output secret. 12 | * @returns A secret string as bytes. 13 | * @throws {@link ExportError} 14 | */ 15 | export(exporterContext: ArrayBuffer, len: number): Promise; 16 | } 17 | -------------------------------------------------------------------------------- /packages/hpke-js/src/kems/dhkemP521.ts: -------------------------------------------------------------------------------- 1 | import { Dhkem, Ec, KemId } from "@hpke/common"; 2 | 3 | import { HkdfSha512 } from "@hpke/dhkem-x448"; 4 | 5 | export class DhkemP521HkdfSha512 extends Dhkem { 6 | override id: KemId = KemId.DhkemP521HkdfSha512; 7 | override secretSize: number = 64; 8 | override encSize: number = 133; 9 | override publicKeySize: number = 133; 10 | override privateKeySize: number = 64; 11 | 12 | constructor() { 13 | const kdf = new HkdfSha512(); 14 | const prim = new Ec(KemId.DhkemP521HkdfSha512, kdf); 15 | super(KemId.DhkemP521HkdfSha512, prim, kdf); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/ci_docs.yml: -------------------------------------------------------------------------------- 1 | name: Documentation CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | paths: 7 | - "**/*.md" 8 | - "**/*.mdc" 9 | pull_request: 10 | branches: [main] 11 | paths: 12 | - "**/*.md" 13 | - "**/*.mdc" 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | fmt: 20 | name: Run deno fmt --check 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v4 24 | - uses: denoland/setup-deno@v2 25 | with: 26 | deno-version: 2.x 27 | - name: Check formatting 28 | run: deno fmt --check 29 | -------------------------------------------------------------------------------- /packages/core/test/runtimes/cloudflare/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-cloudflare-hpke-core", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "deploy": "wrangler deploy", 7 | "dev": "wrangler dev", 8 | "start": "wrangler dev", 9 | "test": "vitest run", 10 | "cf-typegen": "wrangler types" 11 | }, 12 | "devDependencies": { 13 | "@cloudflare/vitest-pool-workers": "^0.8.66", 14 | "@cloudflare/workers-types": "^4.20250823.0", 15 | "typescript": "^5.9.2", 16 | "vitest": "3.2.4", 17 | "wrangler": "^4.32.0" 18 | }, 19 | "dependencies": { 20 | "@hpke/core": "^1.7.5" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/cloudflare/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-cloudflare-hpke-js", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "deploy": "wrangler deploy", 7 | "dev": "wrangler dev", 8 | "start": "wrangler dev", 9 | "test": "vitest run", 10 | "cf-typegen": "wrangler types" 11 | }, 12 | "devDependencies": { 13 | "@cloudflare/vitest-pool-workers": "^0.8.66", 14 | "@cloudflare/workers-types": "^4.20250823.0", 15 | "typescript": "^5.9.2", 16 | "vitest": "3.2.4", 17 | "wrangler": "^4.32.0" 18 | }, 19 | "dependencies": { 20 | "hpke-js": "^1.6.5" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/common/src/interfaces/jsonWebKeyExtended.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Extended JsonWebKey interface to support `pub` and `priv` properties, 3 | * which are not supported by the current `JsonWebKey`. 4 | * Both of them are defined for the newly defined JSON WWb Key type AKP (Algorithm Key Pair), 5 | * which is used to express Public and Private Keys for use with Algorithms. 6 | */ 7 | export interface JsonWebKeyExtended extends JsonWebKey { 8 | /** The public key in base64url encoding, which is used with the 'AKP' key type. */ 9 | pub?: string; 10 | /** The private key in base64url encoding, which is used with the 'AKP' key type. */ 11 | priv?: string; 12 | } 13 | -------------------------------------------------------------------------------- /packages/common/src/xCryptoKey.ts: -------------------------------------------------------------------------------- 1 | export class XCryptoKey implements CryptoKey { 2 | public readonly key: Uint8Array; 3 | public readonly type: "public" | "private"; 4 | public readonly extractable: boolean = true; 5 | public readonly algorithm: KeyAlgorithm; 6 | public readonly usages: KeyUsage[]; 7 | 8 | constructor( 9 | name: string, 10 | key: Uint8Array, 11 | type: "public" | "private", 12 | usages: KeyUsage[] = [], 13 | ) { 14 | this.key = key; 15 | this.type = type; 16 | this.algorithm = { name: name }; 17 | this.usages = usages; 18 | if (type === "public") { 19 | this.usages = []; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/dhkem-x448/test/runtimes/cloudflare/dhkem-x448.spec.ts: -------------------------------------------------------------------------------- 1 | import { SELF } from "cloudflare:test"; 2 | import { describe, expect, it } from "vitest"; 3 | 4 | describe("Cloudflare Workers", () => { 5 | describe("GET /test", () => { 6 | it("should return ok", async () => { 7 | for (const kdf of ["0x0001", "0x0002", "0x0003"]) { 8 | for (const aead of ["0x0001", "0x0002"]) { 9 | const res = await SELF.fetch( 10 | `https://example.com/test?kdf=${kdf}&aead=${aead}`, 11 | ); 12 | expect(res.status).toBe(200); 13 | expect(await res.text()).toBe("ok"); 14 | } 15 | } 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/test/runtimes/cloudflare/dhkem-x25519.spec.ts: -------------------------------------------------------------------------------- 1 | import { SELF } from "cloudflare:test"; 2 | import { describe, expect, it } from "vitest"; 3 | 4 | describe("Cloudflare Workers", () => { 5 | describe("GET /test", () => { 6 | it("should return ok", async () => { 7 | for (const kdf of ["0x0001", "0x0002", "0x0003"]) { 8 | for (const aead of ["0x0001", "0x0002"]) { 9 | const res = await SELF.fetch( 10 | `https://example.com/test?kdf=${kdf}&aead=${aead}`, 11 | ); 12 | expect(res.status).toBe(200); 13 | expect(await res.text()).toBe("ok"); 14 | } 15 | } 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/test/runtimes/cloudflare/dhkem-secp256k1.spec.ts: -------------------------------------------------------------------------------- 1 | import { SELF } from "cloudflare:test"; 2 | import { describe, expect, it } from "vitest"; 3 | 4 | describe("Cloudflare Workers", () => { 5 | describe("GET /test", () => { 6 | it("should return ok", async () => { 7 | for (const kdf of ["0x0001", "0x0002", "0x0003"]) { 8 | for (const aead of ["0x0001", "0x0002"]) { 9 | const res = await SELF.fetch( 10 | `https://example.com/test?kdf=${kdf}&aead=${aead}`, 11 | ); 12 | expect(res.status).toBe(200); 13 | expect(await res.text()).toBe("ok"); 14 | } 15 | } 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/ml-kem/test/runtimes/cloudflare/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-cloudflare-hpke-ml-kem", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "deploy": "wrangler deploy", 7 | "dev": "wrangler dev", 8 | "start": "wrangler dev", 9 | "test": "vitest run", 10 | "cf-typegen": "wrangler types" 11 | }, 12 | "devDependencies": { 13 | "@cloudflare/vitest-pool-workers": "^0.8.66", 14 | "@cloudflare/workers-types": "^4.20250823.0", 15 | "typescript": "^5.9.2", 16 | "vitest": "3.2.4", 17 | "wrangler": "^4.32.0" 18 | }, 19 | "dependencies": { 20 | "@hpke/core": "^1.7.5", 21 | "@hpke/ml-kem": "^0.2.1" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/core/src/interfaces/cipherSuiteParams.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | AeadId, 3 | AeadInterface, 4 | KdfId, 5 | KdfInterface, 6 | KemId, 7 | KemInterface, 8 | } from "@hpke/common"; 9 | 10 | /** 11 | * The parameters used to configure the `CipherSuite`. 12 | */ 13 | export interface CipherSuiteParams { 14 | /** The KEM (Key Encapsulation Mechanism) identifier or the KEM object. */ 15 | kem: KemId | KemInterface; 16 | 17 | /** The KDF (Key Derivation Function) identifier or the KDF object. */ 18 | kdf: KdfId | KdfInterface; 19 | 20 | /** The AEAD (Authenticated Encryption with Addtional Data) identifier or the AEAD object. */ 21 | aead: AeadId | AeadInterface; 22 | } 23 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/test/runtimes/cloudflare/hybridkem-x-wing.spec.ts: -------------------------------------------------------------------------------- 1 | import { SELF } from "cloudflare:test"; 2 | import { describe, expect, it } from "vitest"; 3 | 4 | describe("Cloudflare Workers", () => { 5 | describe("GET /test", () => { 6 | it("should return ok", async () => { 7 | for (const kdf of ["0x0001", "0x0002", "0x0003"]) { 8 | for (const aead of ["0x0001", "0x0002"]) { 9 | const res = await SELF.fetch( 10 | `https://example.com/test?kdf=${kdf}&aead=${aead}`, 11 | ); 12 | expect(res.status).toBe(200); 13 | expect(await res.text()).toBe("ok"); 14 | } 15 | } 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /npm/import_map.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": { 3 | "@dajiaji/mlkem": "npm:mlkem@^2.5.0", 4 | "@deno/dnt": "jsr:@deno/dnt@0.41.3", 5 | "@hpke/chacha20poly1305": "npm:@hpke/chacha20poly1305@^1.7.0", 6 | "@hpke/common": "npm:@hpke/common@^1.8.1", 7 | "@hpke/core": "npm:@hpke/core@^1.7.5", 8 | "@hpke/dhkem-x25519": "npm:@hpke/dhkem-x25519@^1.6.4", 9 | "@hpke/dhkem-x448": "npm:@hpke/dhkem-x448@^1.6.4", 10 | "@noble/curves/secp256k1": "npm:@noble/curves@^1.9.6/secp256k1", 11 | "@std/assert": "jsr:@std/assert@1.0.0", 12 | "@std/fs": "jsr:@std/fs@1.0.14", 13 | "@std/path": "jsr:@std/path@1.0.8", 14 | "@std/testing/bdd": "jsr:@std/testing@1.0.9/bdd" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/test/runtimes/cloudflare/chacha20poly1305.spec.ts: -------------------------------------------------------------------------------- 1 | import { SELF } from "cloudflare:test"; 2 | import { describe, expect, it } from "vitest"; 3 | 4 | describe("Cloudflare Workers", () => { 5 | describe("GET /test", () => { 6 | it("should return ok", async () => { 7 | for (const kem of ["0x0010", "0x0011", "0x0012"]) { 8 | for (const kdf of ["0x0001", "0x0002", "0x0003"]) { 9 | const res = await SELF.fetch( 10 | `https://example.com/test?kem=${kem}&kdf=${kdf}`, 11 | ); 12 | expect(res.status).toBe(200); 13 | expect(await res.text()).toBe("ok"); 14 | } 15 | } 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/dhkem-x448/test/runtimes/cloudflare/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-cloudflare-hpke-dhkem-x448", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "deploy": "wrangler deploy", 7 | "dev": "wrangler dev", 8 | "start": "wrangler dev", 9 | "test": "vitest run", 10 | "cf-typegen": "wrangler types" 11 | }, 12 | "devDependencies": { 13 | "@cloudflare/vitest-pool-workers": "^0.8.66", 14 | "@cloudflare/workers-types": "^4.20250823.0", 15 | "typescript": "^5.9.2", 16 | "vitest": "3.2.4", 17 | "wrangler": "^4.32.0" 18 | }, 19 | "dependencies": { 20 | "@hpke/core": "^1.7.5", 21 | "@hpke/dhkem-x448": "^1.6.4" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/test/runtimes/cloudflare/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-cloudflare-hpke-dhkem-x25519", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "deploy": "wrangler deploy", 7 | "dev": "wrangler dev", 8 | "start": "wrangler dev", 9 | "test": "vitest run", 10 | "cf-typegen": "wrangler types" 11 | }, 12 | "devDependencies": { 13 | "@cloudflare/vitest-pool-workers": "^0.8.66", 14 | "@cloudflare/workers-types": "^4.20250823.0", 15 | "typescript": "^5.9.2", 16 | "vitest": "3.2.4", 17 | "wrangler": "^4.32.0" 18 | }, 19 | "dependencies": { 20 | "@hpke/core": "^1.7.5", 21 | "@hpke/dhkem-x25519": "^1.6.4" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/test/runtimes/cloudflare/hybridkem-x25519-kyber768.spec.ts: -------------------------------------------------------------------------------- 1 | import { SELF } from "cloudflare:test"; 2 | import { describe, expect, it } from "vitest"; 3 | 4 | describe("Cloudflare Workers", () => { 5 | describe("GET /test", () => { 6 | it("should return ok", async () => { 7 | for (const kdf of ["0x0001", "0x0002", "0x0003"]) { 8 | for (const aead of ["0x0001", "0x0002"]) { 9 | const res = await SELF.fetch( 10 | `https://example.com/test?kdf=${kdf}&aead=${aead}`, 11 | ); 12 | expect(res.status).toBe(200); 13 | expect(await res.text()).toBe("ok"); 14 | } 15 | } 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/test/runtimes/cloudflare/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-cloudflare-hpke-dhkem-secp256k1", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "deploy": "wrangler deploy", 7 | "dev": "wrangler dev", 8 | "start": "wrangler dev", 9 | "test": "vitest run", 10 | "cf-typegen": "wrangler types" 11 | }, 12 | "devDependencies": { 13 | "@cloudflare/vitest-pool-workers": "^0.8.66", 14 | "@cloudflare/workers-types": "^4.20250823.0", 15 | "typescript": "^5.9.2", 16 | "vitest": "3.2.4", 17 | "wrangler": "^4.32.0" 18 | }, 19 | "dependencies": { 20 | "@hpke/core": "^1.7.5", 21 | "@hpke/dhkem-secp256k1": "^1.6.4" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/test/runtimes/cloudflare/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-cloudflare-hpke-chacha20poly1305", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "deploy": "wrangler deploy", 7 | "dev": "wrangler dev", 8 | "start": "wrangler dev", 9 | "test": "vitest run", 10 | "cf-typegen": "wrangler types" 11 | }, 12 | "devDependencies": { 13 | "@cloudflare/vitest-pool-workers": "^0.8.66", 14 | "@cloudflare/workers-types": "^4.20250823.0", 15 | "typescript": "^5.9.2", 16 | "vitest": "3.2.4", 17 | "wrangler": "^4.32.0" 18 | }, 19 | "dependencies": { 20 | "@hpke/chacha20poly1305": "^1.7.1", 21 | "@hpke/core": "^1.7.5" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/test/runtimes/cloudflare/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-cloudflare-hpke-hybridkem-x-wing", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "deploy": "wrangler deploy", 7 | "dev": "wrangler dev", 8 | "start": "wrangler dev", 9 | "test": "vitest run", 10 | "cf-typegen": "wrangler types" 11 | }, 12 | "devDependencies": { 13 | "@cloudflare/vitest-pool-workers": "^0.8.66", 14 | "@cloudflare/workers-types": "^4.20250823.0", 15 | "typescript": "^5.9.2", 16 | "vitest": "3.2.4", 17 | "wrangler": "^4.32.0" 18 | }, 19 | "dependencies": { 20 | "@hpke/core": "^1.7.5", 21 | "@hpke/hybridkem-x-wing": "^0.6.1" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | ## Is your feature request related to a problem? Please describe. 10 | 11 | A clear and concise description of what the problem is. Ex. I'm always 12 | frustrated when [...] 13 | 14 | ## Describe the solution you'd like 15 | 16 | A clear and concise description of what you want to happen. 17 | 18 | ## Describe alternatives you've considered 19 | 20 | A clear and concise description of any alternative solutions or features you've 21 | considered. 22 | 23 | ## Additional context 24 | 25 | Add any other context or screenshots about the feature request here. 26 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/test/runtimes/cloudflare/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-cloudflare-hpke-hybridkem-x25519-kyber768", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "deploy": "wrangler deploy", 7 | "dev": "wrangler dev", 8 | "start": "wrangler dev", 9 | "test": "vitest run", 10 | "cf-typegen": "wrangler types" 11 | }, 12 | "devDependencies": { 13 | "@cloudflare/vitest-pool-workers": "^0.7.7", 14 | "@cloudflare/workers-types": "^4.20250303.0", 15 | "typescript": "^5.8.2", 16 | "vitest": "3.0.8", 17 | "wrangler": "^3.114.0" 18 | }, 19 | "dependencies": { 20 | "@hpke/core": "^1.7.5", 21 | "@hpke/hybridkem-x25519-kyber768": "^1.6.1" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/common/src/consts.ts: -------------------------------------------------------------------------------- 1 | // The input length limit (psk, psk_id, info, exporter_context, ikm). 2 | export const INPUT_LENGTH_LIMIT = 8192; 3 | 4 | export const INFO_LENGTH_LIMIT = 65536; 5 | 6 | // The minimum length of a PSK. 7 | export const MINIMUM_PSK_LENGTH = 32; 8 | 9 | // b"" 10 | export const EMPTY: Uint8Array = /* @__PURE__ */ new Uint8Array(0); 11 | 12 | // Common BigInt constants 13 | export const N_0 = /* @__PURE__ */ BigInt(0); 14 | export const N_1 = /* @__PURE__ */ BigInt(1); 15 | export const N_2 = /* @__PURE__ */ BigInt(2); 16 | export const N_7 = /* @__PURE__ */ BigInt(7); 17 | export const N_32 = /* @__PURE__ */ BigInt(32); 18 | export const N_256 = /* @__PURE__ */ BigInt(256); 19 | export const N_0x71 = /* @__PURE__ */ BigInt(0x71); 20 | -------------------------------------------------------------------------------- /.github/workflows/ci_cloudflare.yml: -------------------------------------------------------------------------------- 1 | name: Cloudflare Workers CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | paths-ignore: 7 | - "**/*.md" 8 | - "**/*.mdc" 9 | pull_request: 10 | branches: [main] 11 | paths-ignore: 12 | - "**/*.md" 13 | - "**/*.mdc" 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | test: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | - uses: denoland/setup-deno@v2 24 | with: 25 | deno-version: 2.x 26 | - uses: actions/setup-node@v4 27 | with: 28 | node-version: 22 29 | - name: Prepare test 30 | run: deno task npm 31 | - name: Run test 32 | run: deno task test:cloudflare 33 | -------------------------------------------------------------------------------- /packages/ml-kem/test/runtimes/cloudflare/ml-kem.spec.ts: -------------------------------------------------------------------------------- 1 | import { SELF } from "cloudflare:test"; 2 | import { describe, expect, it } from "vitest"; 3 | 4 | describe("Cloudflare Workers", () => { 5 | describe("GET /test", () => { 6 | it("should return ok", async () => { 7 | for (const kem of ["0x0040", "0x0041", "0x0042"]) { 8 | for (const kdf of ["0x0001", "0x0002", "0x0003"]) { 9 | for (const aead of ["0x0001", "0x0002"]) { 10 | const res = await SELF.fetch( 11 | `https://example.com/test?kem=${kem}&kdf=${kdf}&aead=${aead}`, 12 | ); 13 | expect(res.status).toBe(200); 14 | expect(await res.text()).toBe("ok"); 15 | } 16 | } 17 | } 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/core/test/runtimes/bun/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Enable latest features 4 | "lib": ["ESNext", "DOM"], 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "moduleDetection": "force", 8 | "jsx": "react-jsx", 9 | "allowJs": true, 10 | 11 | // Bundler mode 12 | "moduleResolution": "bundler", 13 | "allowImportingTsExtensions": true, 14 | "verbatimModuleSyntax": true, 15 | "noEmit": true, 16 | 17 | // Best practices 18 | "strict": true, 19 | "skipLibCheck": true, 20 | "noFallthroughCasesInSwitch": true, 21 | 22 | // Some stricter flags (disabled by default) 23 | "noUnusedLocals": false, 24 | "noUnusedParameters": false, 25 | "noPropertyAccessFromIndexSignature": false 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/core/src/recipientContext.ts: -------------------------------------------------------------------------------- 1 | import { EMPTY, OpenError } from "@hpke/common"; 2 | 3 | import { EncryptionContextImpl } from "./encryptionContext.ts"; 4 | import { Mutex } from "./mutex.ts"; 5 | 6 | export class RecipientContextImpl extends EncryptionContextImpl { 7 | #mutex?: Mutex; 8 | 9 | override async open( 10 | data: ArrayBuffer, 11 | aad: ArrayBuffer = EMPTY.buffer as ArrayBuffer, 12 | ): Promise { 13 | this.#mutex ??= new Mutex(); 14 | const release = await this.#mutex.lock(); 15 | let pt: ArrayBuffer; 16 | try { 17 | pt = await this._ctx.key.open(this.computeNonce(this._ctx), data, aad); 18 | } catch (e: unknown) { 19 | throw new OpenError(e); 20 | } finally { 21 | release(); 22 | } 23 | this.incrementSeq(this._ctx); 24 | return pt; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/hpke-js/mod.ts: -------------------------------------------------------------------------------- 1 | export type { 2 | AeadEncryptionContext, 3 | AeadInterface, 4 | CipherSuiteParams, 5 | CipherSuiteSealResponse, 6 | EncryptionContext, 7 | KdfInterface, 8 | KemInterface, 9 | PreSharedKey, 10 | RecipientContext, 11 | RecipientContextParams, 12 | SenderContext, 13 | SenderContextParams, 14 | } from "@hpke/core"; 15 | 16 | export { 17 | AeadId, 18 | DecapError, 19 | DeriveKeyPairError, 20 | DeserializeError, 21 | EncapError, 22 | ExportError, 23 | HpkeError, 24 | InvalidParamError, 25 | KdfId, 26 | KemId, 27 | MessageLimitReachedError, 28 | NotSupportedError, 29 | OpenError, 30 | SealError, 31 | SerializeError, 32 | ValidationError, 33 | } from "@hpke/core"; 34 | 35 | export { Aead, Kdf, Kem } from "./src/identifiers.ts"; 36 | 37 | export { CipherSuite } from "./src/cipherSuite.ts"; 38 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/src/hkdfSha256.ts: -------------------------------------------------------------------------------- 1 | import { HkdfSha256Native, hmac, sha256 } from "@hpke/common"; 2 | 3 | export class HkdfSha256 extends HkdfSha256Native { 4 | public override async extract( 5 | salt: ArrayBuffer, 6 | ikm: ArrayBuffer, 7 | ): Promise { 8 | await this._setup(); 9 | if (salt.byteLength === 0) { 10 | salt = new ArrayBuffer(this.hashSize); 11 | } 12 | if (salt.byteLength !== this.hashSize) { 13 | return hmac(sha256, new Uint8Array(salt), new Uint8Array(ikm)) 14 | .buffer as ArrayBuffer; 15 | } 16 | const key = await (this._api as SubtleCrypto).importKey( 17 | "raw", 18 | salt, 19 | this.algHash, 20 | false, 21 | [ 22 | "sign", 23 | ], 24 | ); 25 | return await (this._api as SubtleCrypto).sign("HMAC", key, ikm); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/dhkem-x448/src/hkdfSha512.ts: -------------------------------------------------------------------------------- 1 | import { HkdfSha512Native, hmac, sha512 } from "@hpke/common"; 2 | 3 | export class HkdfSha512 extends HkdfSha512Native { 4 | public override async extract( 5 | salt: ArrayBuffer, 6 | ikm: ArrayBuffer, 7 | ): Promise { 8 | await this._setup(); 9 | if (salt.byteLength === 0) { 10 | salt = new ArrayBuffer(this.hashSize); 11 | } 12 | if (salt.byteLength !== this.hashSize) { 13 | return hmac(sha512, new Uint8Array(salt), new Uint8Array(ikm)) 14 | .buffer as ArrayBuffer; 15 | } 16 | const key = await (this._api as SubtleCrypto).importKey( 17 | "raw", 18 | salt, 19 | this.algHash, 20 | false, 21 | [ 22 | "sign", 23 | ], 24 | ); 25 | return await (this._api as SubtleCrypto).sign("HMAC", key, ikm); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/hpke-js/src/kdfs/hkdfSha384.ts: -------------------------------------------------------------------------------- 1 | import { HkdfSha384Native, hmac, sha384 } from "@hpke/common"; 2 | 3 | export class HkdfSha384 extends HkdfSha384Native { 4 | public override async extract( 5 | salt: ArrayBuffer, 6 | ikm: ArrayBuffer, 7 | ): Promise { 8 | await this._setup(); 9 | if (salt.byteLength === 0) { 10 | salt = new ArrayBuffer(this.hashSize); 11 | } 12 | if (salt.byteLength !== this.hashSize) { 13 | return hmac(sha384, new Uint8Array(salt), new Uint8Array(ikm)) 14 | .buffer as ArrayBuffer; 15 | } 16 | const key = await (this._api as SubtleCrypto).importKey( 17 | "raw", 18 | salt, 19 | this.algHash, 20 | false, 21 | [ 22 | "sign", 23 | ], 24 | ); 25 | return await (this._api as SubtleCrypto).sign("HMAC", key, ikm); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/bun/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Enable latest features 4 | "lib": ["ESNext", "DOM"], 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "moduleDetection": "force", 8 | "jsx": "react-jsx", 9 | "allowJs": true, 10 | "paths": { 11 | "@hpke/core": ["../../../core/mod.ts"] 12 | }, 13 | 14 | // Bundler mode 15 | "moduleResolution": "bundler", 16 | "allowImportingTsExtensions": true, 17 | "verbatimModuleSyntax": true, 18 | "noEmit": true, 19 | 20 | // Best practices 21 | "strict": true, 22 | "skipLibCheck": true, 23 | "noFallthroughCasesInSwitch": true, 24 | 25 | // Some stricter flags (disabled by default) 26 | "noUnusedLocals": false, 27 | "noUnusedParameters": false, 28 | "noPropertyAccessFromIndexSignature": false 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.github/workflows/ci_bun.yml: -------------------------------------------------------------------------------- 1 | name: bun CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | paths-ignore: 7 | - "**/*.md" 8 | - "**/*.mdc" 9 | pull_request: 10 | branches: [main] 11 | paths-ignore: 12 | - "**/*.md" 13 | - "**/*.mdc" 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | test: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | - uses: denoland/setup-deno@v2 24 | with: 25 | deno-version: 2.x 26 | - uses: actions/setup-node@v4 27 | with: 28 | node-version: 22 29 | - uses: oven-sh/setup-bun@v2 30 | with: 31 | bun-version: latest 32 | - name: Prepare test 33 | run: | 34 | deno task npm 35 | deno task bun-link 36 | - name: Run test 37 | run: deno task test:bun 38 | -------------------------------------------------------------------------------- /packages/common/src/interfaces/aeadInterface.ts: -------------------------------------------------------------------------------- 1 | import type { AeadEncryptionContext } from "./aeadEncryptionContext.ts"; 2 | 3 | import type { AeadId } from "../identifiers.ts"; 4 | 5 | /** 6 | * The AEAD interface. 7 | */ 8 | export interface AeadInterface { 9 | /** The KDF identifier. */ 10 | readonly id: AeadId; 11 | /** The length in bytes of an AEAD key (Nk). */ 12 | readonly keySize: number; 13 | /** The length in bytes of an AEAD nonce (Nn). */ 14 | readonly nonceSize: number; 15 | /** The length in bytes of an AEAD authentication tag (Nt). */ 16 | readonly tagSize: number; 17 | 18 | /** 19 | * Creates an AEAD encryption context which has seal/open operation. 20 | * 21 | * @param key A byte string of the raw key. 22 | * @returns An AEAD encryption context. 23 | */ 24 | createEncryptionContext(key: ArrayBuffer): AeadEncryptionContext; 25 | } 26 | -------------------------------------------------------------------------------- /packages/core/test/runtimes/browsers/playwright.config.ts: -------------------------------------------------------------------------------- 1 | // playwright.config.ts 2 | import { devices } from "@playwright/test"; 3 | import type { PlaywrightTestConfig } from "@playwright/test"; 4 | 5 | const config: PlaywrightTestConfig = { 6 | use: { 7 | baseURL: "http://localhost:3000", 8 | }, 9 | webServer: { 10 | command: "npx http-server ./pages -p 3000 -c-1", 11 | url: "http://localhost:3000", 12 | // deno-lint-ignore no-process-global 13 | reuseExistingServer: !process.env.CI, 14 | }, 15 | projects: [ 16 | { 17 | name: "chromium", 18 | use: { ...devices["Desktop Chrome"] }, 19 | }, 20 | { 21 | name: "firefox", 22 | use: { ...devices["Desktop Firefox"] }, 23 | }, 24 | { 25 | name: "webkit", 26 | use: { ...devices["Desktop Safari"] }, 27 | }, 28 | ], 29 | }; 30 | export default config; 31 | -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/browsers/playwright.config.ts: -------------------------------------------------------------------------------- 1 | // playwright.config.ts 2 | import { devices } from "@playwright/test"; 3 | import type { PlaywrightTestConfig } from "@playwright/test"; 4 | 5 | const config: PlaywrightTestConfig = { 6 | use: { 7 | baseURL: "http://localhost:3000", 8 | }, 9 | webServer: { 10 | command: "npx http-server ./pages -p 3000 -c-1", 11 | url: "http://localhost:3000", 12 | // deno-lint-ignore no-process-global 13 | reuseExistingServer: !process.env.CI, 14 | }, 15 | projects: [ 16 | { 17 | name: "chromium", 18 | use: { ...devices["Desktop Chrome"] }, 19 | }, 20 | { 21 | name: "firefox", 22 | use: { ...devices["Desktop Firefox"] }, 23 | }, 24 | { 25 | name: "webkit", 26 | use: { ...devices["Desktop Safari"] }, 27 | }, 28 | ], 29 | }; 30 | export default config; 31 | -------------------------------------------------------------------------------- /packages/ml-kem/test/runtimes/browsers/playwright.config.ts: -------------------------------------------------------------------------------- 1 | // playwright.config.ts 2 | import { devices } from "@playwright/test"; 3 | import type { PlaywrightTestConfig } from "@playwright/test"; 4 | 5 | const config: PlaywrightTestConfig = { 6 | use: { 7 | baseURL: "http://localhost:3000", 8 | }, 9 | webServer: { 10 | command: "npx http-server ./pages -p 3000 -c-1", 11 | url: "http://localhost:3000", 12 | // deno-lint-ignore no-process-global 13 | reuseExistingServer: !process.env.CI, 14 | }, 15 | projects: [ 16 | { 17 | name: "chromium", 18 | use: { ...devices["Desktop Chrome"] }, 19 | }, 20 | { 21 | name: "firefox", 22 | use: { ...devices["Desktop Firefox"] }, 23 | }, 24 | { 25 | name: "webkit", 26 | use: { ...devices["Desktop Safari"] }, 27 | }, 28 | ], 29 | }; 30 | export default config; 31 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/test/runtimes/browsers/playwright.config.ts: -------------------------------------------------------------------------------- 1 | // playwright.config.ts 2 | import { devices } from "@playwright/test"; 3 | import type { PlaywrightTestConfig } from "@playwright/test"; 4 | 5 | const config: PlaywrightTestConfig = { 6 | use: { 7 | baseURL: "http://localhost:3000", 8 | }, 9 | webServer: { 10 | command: "npx http-server ./pages -p 3000 -c-1", 11 | url: "http://localhost:3000", 12 | // deno-lint-ignore no-process-global 13 | reuseExistingServer: !process.env.CI, 14 | }, 15 | projects: [ 16 | { 17 | name: "chromium", 18 | use: { ...devices["Desktop Chrome"] }, 19 | }, 20 | { 21 | name: "firefox", 22 | use: { ...devices["Desktop Firefox"] }, 23 | }, 24 | { 25 | name: "webkit", 26 | use: { ...devices["Desktop Safari"] }, 27 | }, 28 | ], 29 | }; 30 | export default config; 31 | -------------------------------------------------------------------------------- /packages/dhkem-x448/test/runtimes/browsers/playwright.config.ts: -------------------------------------------------------------------------------- 1 | // playwright.config.ts 2 | import { devices } from "@playwright/test"; 3 | import type { PlaywrightTestConfig } from "@playwright/test"; 4 | 5 | const config: PlaywrightTestConfig = { 6 | use: { 7 | baseURL: "http://localhost:3000", 8 | }, 9 | webServer: { 10 | command: "npx http-server ./pages -p 3000 -c-1", 11 | url: "http://localhost:3000", 12 | // deno-lint-ignore no-process-global 13 | reuseExistingServer: !process.env.CI, 14 | }, 15 | projects: [ 16 | { 17 | name: "chromium", 18 | use: { ...devices["Desktop Chrome"] }, 19 | }, 20 | { 21 | name: "firefox", 22 | use: { ...devices["Desktop Firefox"] }, 23 | }, 24 | { 25 | name: "webkit", 26 | use: { ...devices["Desktop Safari"] }, 27 | }, 28 | ], 29 | }; 30 | export default config; 31 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/test/runtimes/browsers/playwright.config.ts: -------------------------------------------------------------------------------- 1 | // playwright.config.ts 2 | import { devices } from "@playwright/test"; 3 | import type { PlaywrightTestConfig } from "@playwright/test"; 4 | 5 | const config: PlaywrightTestConfig = { 6 | use: { 7 | baseURL: "http://localhost:3000", 8 | }, 9 | webServer: { 10 | command: "npx http-server ./pages -p 3000 -c-1", 11 | url: "http://localhost:3000", 12 | // deno-lint-ignore no-process-global 13 | reuseExistingServer: !process.env.CI, 14 | }, 15 | projects: [ 16 | { 17 | name: "chromium", 18 | use: { ...devices["Desktop Chrome"] }, 19 | }, 20 | { 21 | name: "firefox", 22 | use: { ...devices["Desktop Firefox"] }, 23 | }, 24 | { 25 | name: "webkit", 26 | use: { ...devices["Desktop Safari"] }, 27 | }, 28 | ], 29 | }; 30 | export default config; 31 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/test/runtimes/browsers/playwright.config.ts: -------------------------------------------------------------------------------- 1 | // playwright.config.ts 2 | import { devices } from "@playwright/test"; 3 | import type { PlaywrightTestConfig } from "@playwright/test"; 4 | 5 | const config: PlaywrightTestConfig = { 6 | use: { 7 | baseURL: "http://localhost:3000", 8 | }, 9 | webServer: { 10 | command: "npx http-server ./pages -p 3000 -c-1", 11 | url: "http://localhost:3000", 12 | // deno-lint-ignore no-process-global 13 | reuseExistingServer: !process.env.CI, 14 | }, 15 | projects: [ 16 | { 17 | name: "chromium", 18 | use: { ...devices["Desktop Chrome"] }, 19 | }, 20 | { 21 | name: "firefox", 22 | use: { ...devices["Desktop Firefox"] }, 23 | }, 24 | { 25 | name: "webkit", 26 | use: { ...devices["Desktop Safari"] }, 27 | }, 28 | ], 29 | }; 30 | export default config; 31 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/test/runtimes/browsers/playwright.config.ts: -------------------------------------------------------------------------------- 1 | // playwright.config.ts 2 | import { devices } from "@playwright/test"; 3 | import type { PlaywrightTestConfig } from "@playwright/test"; 4 | 5 | const config: PlaywrightTestConfig = { 6 | use: { 7 | baseURL: "http://localhost:3000", 8 | }, 9 | webServer: { 10 | command: "npx http-server ./pages -p 3000 -c-1", 11 | url: "http://localhost:3000", 12 | // deno-lint-ignore no-process-global 13 | reuseExistingServer: !process.env.CI, 14 | }, 15 | projects: [ 16 | { 17 | name: "chromium", 18 | use: { ...devices["Desktop Chrome"] }, 19 | }, 20 | { 21 | name: "firefox", 22 | use: { ...devices["Desktop Firefox"] }, 23 | }, 24 | { 25 | name: "webkit", 26 | use: { ...devices["Desktop Safari"] }, 27 | }, 28 | ], 29 | }; 30 | export default config; 31 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/test/runtimes/browsers/playwright.config.ts: -------------------------------------------------------------------------------- 1 | // playwright.config.ts 2 | import { devices } from "@playwright/test"; 3 | import type { PlaywrightTestConfig } from "@playwright/test"; 4 | 5 | const config: PlaywrightTestConfig = { 6 | use: { 7 | baseURL: "http://localhost:3000", 8 | }, 9 | webServer: { 10 | command: "npx http-server ./pages -p 3000 -c-1", 11 | url: "http://localhost:3000", 12 | // deno-lint-ignore no-process-global 13 | reuseExistingServer: !process.env.CI, 14 | }, 15 | projects: [ 16 | { 17 | name: "chromium", 18 | use: { ...devices["Desktop Chrome"] }, 19 | }, 20 | { 21 | name: "firefox", 22 | use: { ...devices["Desktop Firefox"] }, 23 | }, 24 | { 25 | name: "webkit", 26 | use: { ...devices["Desktop Safari"] }, 27 | }, 28 | ], 29 | }; 30 | export default config; 31 | -------------------------------------------------------------------------------- /packages/common/src/algorithm.ts: -------------------------------------------------------------------------------- 1 | import { NotSupportedError } from "./errors.ts"; 2 | 3 | async function loadSubtleCrypto(): Promise { 4 | if (globalThis !== undefined && globalThis.crypto !== undefined) { 5 | // Browsers, Node.js >= v19, Cloudflare Workers, Bun, etc. 6 | return globalThis.crypto.subtle; 7 | } 8 | // Node.js <= v18 9 | try { 10 | // @ts-ignore: to ignore "crypto" 11 | const { webcrypto } = await import("crypto"); // node:crypto 12 | return (webcrypto as unknown as Crypto).subtle; 13 | } catch (e: unknown) { 14 | throw new NotSupportedError(e); 15 | } 16 | } 17 | 18 | export class NativeAlgorithm { 19 | protected _api: SubtleCrypto | undefined = undefined; 20 | 21 | constructor() {} 22 | 23 | protected async _setup() { 24 | if (this._api !== undefined) { 25 | return; 26 | } 27 | this._api = await loadSubtleCrypto(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/hpke-js/samples/node/app.js: -------------------------------------------------------------------------------- 1 | import { KemId, KdfId, AeadId, CipherSuite } from "hpke-js"; 2 | 3 | async function doHpke() { 4 | const suite = new CipherSuite({ 5 | kem: KemId.DhkemX25519HkdfSha256, 6 | kdf: KdfId.HkdfSha256, 7 | aead: AeadId.Aes128Gcm, 8 | }); 9 | 10 | const rkp = await suite.kem.generateKeyPair(); 11 | 12 | // A sender encrypts a message. 13 | const sender = await suite.createSenderContext({ 14 | recipientPublicKey: rkp.publicKey, 15 | }); 16 | const ct = await sender.seal(new TextEncoder().encode("Hello world!")); 17 | 18 | // A recipient decrypts it. 19 | const recipient = await suite.createRecipientContext({ 20 | recipientKey: rkp.privateKey, 21 | enc: sender.enc, 22 | }); 23 | const pt = await recipient.open(ct); 24 | 25 | // Hello world! 26 | console.log(new TextDecoder().decode(pt)); 27 | } 28 | 29 | try { 30 | doHpke(); 31 | } catch (e) { 32 | console.log("Error:", e.message); 33 | } 34 | -------------------------------------------------------------------------------- /packages/core/samples/node/app.js: -------------------------------------------------------------------------------- 1 | import { Aes128Gcm, CipherSuite, DhkemP256HkdfSha256, HkdfSha256 } from "@hpke/core"; 2 | 3 | async function doHpke() { 4 | const suite = new CipherSuite({ 5 | kem: new DhkemP256HkdfSha256(), 6 | kdf: new HkdfSha256(), 7 | aead: new Aes128Gcm(), 8 | }); 9 | 10 | const rkp = await suite.kem.generateKeyPair(); 11 | 12 | // A sender encrypts a message. 13 | const sender = await suite.createSenderContext({ 14 | recipientPublicKey: rkp.publicKey, 15 | }); 16 | const ct = await sender.seal(new TextEncoder().encode("Hello world!")); 17 | 18 | // A recipient decrypts it. 19 | const recipient = await suite.createRecipientContext({ 20 | recipientKey: rkp.privateKey, 21 | enc: sender.enc, 22 | }); 23 | const pt = await recipient.open(ct); 24 | 25 | // Hello world! 26 | console.log(new TextDecoder().decode(pt)); 27 | } 28 | 29 | try { 30 | doHpke(); 31 | } catch (e) { 32 | console.log("Error:", e.message); 33 | } 34 | -------------------------------------------------------------------------------- /packages/common/README.md: -------------------------------------------------------------------------------- 1 |

@hpke/common

2 | 3 |
4 | npm 5 | JSR 6 |
7 | 8 |
9 | A TypeScript Hybrid Public Key Encryption (HPKE) internal-use common module for @hpke family modules. 10 |
11 | 12 |
13 |
14 | 15 | ## Installation 16 | 17 | Do not install this package directly, it is an internal package used by 18 | [@hpke/core](https://jsr.io/@hpke/core), 19 | [@hpke/chacha20poly1305](https://jsr.io/@hpke/chacha20poly1305) and so on. Use 20 | either of them instead. 21 | 22 | ## Contributing 23 | 24 | We welcome all kind of contributions, filing issues, suggesting new features or 25 | sending PRs. 26 | -------------------------------------------------------------------------------- /packages/ml-kem/samples/node/app.js: -------------------------------------------------------------------------------- 1 | import { Aes256Gcm, CipherSuite, HkdfSha256 } from "@hpke/core"; 2 | import { MlKem768 } from "@hpke/ml-kem"; 3 | 4 | async function doHpke() { 5 | const suite = new CipherSuite({ 6 | kem: new MlKem768(), 7 | kdf: new HkdfSha256(), 8 | aead: new Aes256Gcm(), 9 | }); 10 | 11 | const rkp = await suite.kem.generateKeyPair(); 12 | 13 | // A sender encrypts a message. 14 | const sender = await suite.createSenderContext({ 15 | recipientPublicKey: rkp.publicKey, 16 | }); 17 | const ct = await sender.seal(new TextEncoder().encode("Hello world!")); 18 | 19 | // A recipient decrypts it. 20 | const recipient = await suite.createRecipientContext({ 21 | recipientKey: rkp.privateKey, 22 | enc: sender.enc, 23 | }); 24 | const pt = await recipient.open(ct); 25 | 26 | // Hello world! 27 | console.log(new TextDecoder().decode(pt)); 28 | } 29 | 30 | try { 31 | doHpke(); 32 | } catch (e) { 33 | console.log("Error: ", e.message); 34 | } 35 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/samples/node/app.js: -------------------------------------------------------------------------------- 1 | import { Aes256Gcm, CipherSuite, HkdfSha256 } from "@hpke/core"; 2 | import { XWing } from "@hpke/hybridkem-x-wing"; 3 | 4 | async function doHpke() { 5 | const suite = new CipherSuite({ 6 | kem: new XWing(), 7 | kdf: new HkdfSha256(), 8 | aead: new Aes256Gcm(), 9 | }); 10 | 11 | const rkp = await suite.kem.generateKeyPair(); 12 | 13 | // A sender encrypts a message. 14 | const sender = await suite.createSenderContext({ 15 | recipientPublicKey: rkp.publicKey, 16 | }); 17 | const ct = await sender.seal(new TextEncoder().encode("Hello world!")); 18 | 19 | // A recipient decrypts it. 20 | const recipient = await suite.createRecipientContext({ 21 | recipientKey: rkp.privateKey, 22 | enc: sender.enc, 23 | }); 24 | const pt = await recipient.open(ct); 25 | 26 | // Hello world! 27 | console.log(new TextDecoder().decode(pt)); 28 | } 29 | 30 | try { 31 | doHpke(); 32 | } catch (e) { 33 | console.log("Error: ", e.message); 34 | } 35 | -------------------------------------------------------------------------------- /packages/dhkem-x448/samples/node/app.js: -------------------------------------------------------------------------------- 1 | import { Aes256Gcm, CipherSuite, HkdfSha512 } from "@hpke/core"; 2 | import { DhkemX448HkdfSha512 } from "@hpke/dhkem-x448"; 3 | 4 | async function doHpke() { 5 | const suite = new CipherSuite({ 6 | kem: new DhkemX448HkdfSha512(), 7 | kdf: new HkdfSha512(), 8 | aead: new Aes256Gcm(), 9 | }); 10 | 11 | const rkp = await suite.kem.generateKeyPair(); 12 | 13 | // A sender encrypts a message. 14 | const sender = await suite.createSenderContext({ 15 | recipientPublicKey: rkp.publicKey, 16 | }); 17 | const ct = await sender.seal(new TextEncoder().encode("Hello world!")); 18 | 19 | // A recipient decrypts it. 20 | const recipient = await suite.createRecipientContext({ 21 | recipientKey: rkp.privateKey, 22 | enc: sender.enc, 23 | }); 24 | const pt = await recipient.open(ct); 25 | 26 | // Hello world! 27 | console.log(new TextDecoder().decode(pt)); 28 | } 29 | 30 | try { 31 | doHpke(); 32 | } catch (e) { 33 | console.log("Error:", e.message); 34 | } 35 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/samples/node/app.js: -------------------------------------------------------------------------------- 1 | import { Aes128Gcm, CipherSuite, HkdfSha256 } from "@hpke/core"; 2 | import { DhkemX25519HkdfSha256 } from "@hpke/dhkem-x25519"; 3 | 4 | async function doHpke() { 5 | const suite = new CipherSuite({ 6 | kem: new DhkemX25519HkdfSha256(), 7 | kdf: new HkdfSha256(), 8 | aead: new Aes128Gcm(), 9 | }); 10 | 11 | const rkp = await suite.kem.generateKeyPair(); 12 | 13 | // A sender encrypts a message. 14 | const sender = await suite.createSenderContext({ 15 | recipientPublicKey: rkp.publicKey, 16 | }); 17 | const ct = await sender.seal(new TextEncoder().encode("Hello world!")); 18 | 19 | // A recipient decrypts it. 20 | const recipient = await suite.createRecipientContext({ 21 | recipientKey: rkp.privateKey, 22 | enc: sender.enc, 23 | }); 24 | const pt = await recipient.open(ct); 25 | 26 | // Hello world! 27 | console.log(new TextDecoder().decode(pt)); 28 | } 29 | 30 | try { 31 | doHpke(); 32 | } catch (e) { 33 | console.log("Error:", e.message); 34 | } 35 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/samples/node/app.js: -------------------------------------------------------------------------------- 1 | import { Aes128Gcm, CipherSuite, HkdfSha256 } from "@hpke/core"; 2 | import { DhkemSecp256k1HkdfSha256 } from "@hpke/dhkem-secp256k1"; 3 | 4 | async function doHpke() { 5 | const suite = new CipherSuite({ 6 | kem: new DhkemSecp256k1HkdfSha256(), 7 | kdf: new HkdfSha256(), 8 | aead: new Aes128Gcm(), 9 | }); 10 | 11 | const rkp = await suite.kem.generateKeyPair(); 12 | 13 | // A sender encrypts a message. 14 | const sender = await suite.createSenderContext({ 15 | recipientPublicKey: rkp.publicKey, 16 | }); 17 | const ct = await sender.seal(new TextEncoder().encode("Hello world!")); 18 | 19 | // A recipient decrypts it. 20 | const recipient = await suite.createRecipientContext({ 21 | recipientKey: rkp.privateKey, 22 | enc: sender.enc, 23 | }); 24 | const pt = await recipient.open(ct); 25 | 26 | // Hello world! 27 | console.log(new TextDecoder().decode(pt)); 28 | } 29 | 30 | try { 31 | doHpke(); 32 | } catch (e) { 33 | console.log("Error:", e.message); 34 | } 35 | -------------------------------------------------------------------------------- /packages/ml-kem/samples/deno/main.ts: -------------------------------------------------------------------------------- 1 | import { Aes256Gcm, CipherSuite, HkdfSha256 } from "@hpke/core"; 2 | import { MlKem768 } from "@hpke/ml-kem"; 3 | 4 | async function doHpke() { 5 | // setup 6 | const suite = new CipherSuite({ 7 | kem: new MlKem768(), 8 | kdf: new HkdfSha256(), 9 | aead: new Aes256Gcm(), 10 | }); 11 | 12 | const rkp = await suite.kem.generateKeyPair(); 13 | 14 | const sender = await suite.createSenderContext({ 15 | recipientPublicKey: rkp.publicKey, 16 | }); 17 | 18 | const recipient = await suite.createRecipientContext({ 19 | recipientKey: rkp.privateKey, 20 | enc: sender.enc, 21 | }); 22 | 23 | // encrypt 24 | const ct = await sender.seal( 25 | new TextEncoder().encode("Hello world!").buffer as ArrayBuffer, 26 | ); 27 | 28 | // decrypt 29 | const pt = await recipient.open(ct); 30 | 31 | // Hello world! 32 | console.log(new TextDecoder().decode(pt)); 33 | } 34 | 35 | try { 36 | doHpke(); 37 | } catch (err: unknown) { 38 | console.log("Error: ", err as Error); 39 | } 40 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/samples/node/app.js: -------------------------------------------------------------------------------- 1 | import { CipherSuite, DhkemP256HkdfSha256, HkdfSha256 } from "@hpke/core"; 2 | import { Chacha20Poly1305 } from "@hpke/chacha20poly1305"; 3 | 4 | async function doHpke() { 5 | const suite = new CipherSuite({ 6 | kem: new DhkemP256HkdfSha256(), 7 | kdf: new HkdfSha256(), 8 | aead: new Chacha20Poly1305(), 9 | }); 10 | 11 | const rkp = await suite.kem.generateKeyPair(); 12 | 13 | // A sender encrypts a message. 14 | const sender = await suite.createSenderContext({ 15 | recipientPublicKey: rkp.publicKey, 16 | }); 17 | const ct = await sender.seal(new TextEncoder().encode("Hello world!")); 18 | 19 | // A recipient decrypts it. 20 | const recipient = await suite.createRecipientContext({ 21 | recipientKey: rkp.privateKey, 22 | enc: sender.enc, 23 | }); 24 | const pt = await recipient.open(ct); 25 | 26 | // Hello world! 27 | console.log(new TextDecoder().decode(pt)); 28 | } 29 | 30 | try { 31 | doHpke(); 32 | } catch (e) { 33 | console.log("Error:", e.message); 34 | } 35 | -------------------------------------------------------------------------------- /packages/core/samples/deno/main.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Aes128Gcm, 3 | CipherSuite, 4 | DhkemP256HkdfSha256, 5 | HkdfSha256, 6 | } from "@hpke/core"; 7 | 8 | async function doHpke() { 9 | // setup 10 | const suite = new CipherSuite({ 11 | kem: new DhkemP256HkdfSha256(), 12 | kdf: new HkdfSha256(), 13 | aead: new Aes128Gcm(), 14 | }); 15 | 16 | const rkp = await suite.kem.generateKeyPair(); 17 | 18 | const sender = await suite.createSenderContext({ 19 | recipientPublicKey: rkp.publicKey, 20 | }); 21 | 22 | const recipient = await suite.createRecipientContext({ 23 | recipientKey: rkp.privateKey, 24 | enc: sender.enc, 25 | }); 26 | 27 | // encrypt 28 | const ct = await sender.seal( 29 | new TextEncoder().encode("Hello world!").buffer as ArrayBuffer, 30 | ); 31 | 32 | // decrypt 33 | const pt = await recipient.open(ct); 34 | 35 | // Hello world! 36 | console.log(new TextDecoder().decode(pt)); 37 | } 38 | 39 | try { 40 | doHpke(); 41 | } catch (err: unknown) { 42 | console.log("Error: ", err as Error); 43 | } 44 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/samples/deno/main.ts: -------------------------------------------------------------------------------- 1 | import { Aes256Gcm, CipherSuite, HkdfSha256 } from "@hpke/core"; 2 | import { XWing } from "@hpke/hybridkem-x-wing"; 3 | 4 | async function doHpke() { 5 | // setup 6 | const suite = new CipherSuite({ 7 | kem: new XWing(), 8 | kdf: new HkdfSha256(), 9 | aead: new Aes256Gcm(), 10 | }); 11 | 12 | const rkp = await suite.kem.generateKeyPair(); 13 | 14 | const sender = await suite.createSenderContext({ 15 | recipientPublicKey: rkp.publicKey, 16 | }); 17 | 18 | const recipient = await suite.createRecipientContext({ 19 | recipientKey: rkp.privateKey, 20 | enc: sender.enc, 21 | }); 22 | 23 | // encrypt 24 | const ct = await sender.seal( 25 | new TextEncoder().encode("Hello world!").buffer as ArrayBuffer, 26 | ); 27 | 28 | // decrypt 29 | const pt = await recipient.open(ct); 30 | 31 | // Hello world! 32 | console.log(new TextDecoder().decode(pt)); 33 | } 34 | 35 | try { 36 | doHpke(); 37 | } catch (err: unknown) { 38 | console.log("Error: ", err as Error); 39 | } 40 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/samples/node/app.js: -------------------------------------------------------------------------------- 1 | import { Aes256Gcm, CipherSuite, HkdfSha256 } from "@hpke/core"; 2 | import { HybridkemX25519Kyber768 } from "@hpke/hybridkem-x25519-kyber768"; 3 | 4 | async function doHpke() { 5 | const suite = new CipherSuite({ 6 | kem: new HybridkemX25519Kyber768(), 7 | kdf: new HkdfSha256(), 8 | aead: new Aes256Gcm(), 9 | }); 10 | 11 | const rkp = await suite.kem.generateKeyPair(); 12 | 13 | // A sender encrypts a message. 14 | const sender = await suite.createSenderContext({ 15 | recipientPublicKey: rkp.publicKey, 16 | }); 17 | const ct = await sender.seal(new TextEncoder().encode("Hello world!")); 18 | 19 | // A recipient decrypts it. 20 | const recipient = await suite.createRecipientContext({ 21 | recipientKey: rkp.privateKey, 22 | enc: sender.enc, 23 | }); 24 | const pt = await recipient.open(ct); 25 | 26 | // Hello world! 27 | console.log(new TextDecoder().decode(pt)); 28 | } 29 | 30 | try { 31 | doHpke(); 32 | } catch (e) { 33 | console.log("Error: ", e.message); 34 | } 35 | -------------------------------------------------------------------------------- /packages/dhkem-x448/samples/deno/main.ts: -------------------------------------------------------------------------------- 1 | import { Aes256Gcm, CipherSuite, HkdfSha256 } from "@hpke/core"; 2 | import { DhkemX448HkdfSha512 } from "@hpke/dhkem-x448"; 3 | 4 | async function doHpke() { 5 | // setup 6 | const suite = new CipherSuite({ 7 | kem: new DhkemX448HkdfSha512(), 8 | kdf: new HkdfSha256(), 9 | aead: new Aes256Gcm(), 10 | }); 11 | 12 | const rkp = await suite.kem.generateKeyPair(); 13 | 14 | const sender = await suite.createSenderContext({ 15 | recipientPublicKey: rkp.publicKey, 16 | }); 17 | 18 | const recipient = await suite.createRecipientContext({ 19 | recipientKey: rkp.privateKey, 20 | enc: sender.enc, 21 | }); 22 | 23 | // encrypt 24 | const ct = await sender.seal( 25 | new TextEncoder().encode("Hello world!").buffer as ArrayBuffer, 26 | ); 27 | 28 | // decrypt 29 | const pt = await recipient.open(ct); 30 | 31 | // Hello world! 32 | console.log(new TextDecoder().decode(pt)); 33 | } 34 | 35 | try { 36 | doHpke(); 37 | } catch (err: unknown) { 38 | console.log("Error: ", err as Error); 39 | } 40 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/samples/deno/main.ts: -------------------------------------------------------------------------------- 1 | import { Aes128Gcm, CipherSuite, HkdfSha256 } from "@hpke/core"; 2 | import { DhkemX25519HkdfSha256 } from "@hpke/dhkem-x25519"; 3 | 4 | async function doHpke() { 5 | // setup 6 | const suite = new CipherSuite({ 7 | kem: new DhkemX25519HkdfSha256(), 8 | kdf: new HkdfSha256(), 9 | aead: new Aes128Gcm(), 10 | }); 11 | 12 | const rkp = await suite.kem.generateKeyPair(); 13 | 14 | const sender = await suite.createSenderContext({ 15 | recipientPublicKey: rkp.publicKey, 16 | }); 17 | 18 | const recipient = await suite.createRecipientContext({ 19 | recipientKey: rkp.privateKey, 20 | enc: sender.enc, 21 | }); 22 | 23 | // encrypt 24 | const ct = await sender.seal( 25 | new TextEncoder().encode("Hello world!").buffer as ArrayBuffer, 26 | ); 27 | 28 | // decrypt 29 | const pt = await recipient.open(ct); 30 | 31 | // Hello world! 32 | console.log(new TextDecoder().decode(pt)); 33 | } 34 | 35 | try { 36 | doHpke(); 37 | } catch (err: unknown) { 38 | console.log("Error: ", err as Error); 39 | } 40 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/samples/deno/main.ts: -------------------------------------------------------------------------------- 1 | import { Aes128Gcm, CipherSuite, HkdfSha256 } from "@hpke/core"; 2 | import { DhkemSecp256k1HkdfSha256 } from "@hpke/dhkem-secp256k1"; 3 | 4 | async function doHpke() { 5 | // setup 6 | const suite = new CipherSuite({ 7 | kem: new DhkemSecp256k1HkdfSha256(), 8 | kdf: new HkdfSha256(), 9 | aead: new Aes128Gcm(), 10 | }); 11 | 12 | const rkp = await suite.kem.generateKeyPair(); 13 | 14 | const sender = await suite.createSenderContext({ 15 | recipientPublicKey: rkp.publicKey, 16 | }); 17 | 18 | const recipient = await suite.createRecipientContext({ 19 | recipientKey: rkp.privateKey, 20 | enc: sender.enc, 21 | }); 22 | 23 | // encrypt 24 | const ct = await sender.seal( 25 | new TextEncoder().encode("Hello world!").buffer as ArrayBuffer, 26 | ); 27 | 28 | // decrypt 29 | const pt = await recipient.open(ct); 30 | 31 | // Hello world! 32 | console.log(new TextDecoder().decode(pt)); 33 | } 34 | 35 | try { 36 | doHpke(); 37 | } catch (err: unknown) { 38 | console.log("Error: ", err as Error); 39 | } 40 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/samples/deno/main.ts: -------------------------------------------------------------------------------- 1 | import { CipherSuite, DhkemP256HkdfSha256, HkdfSha256 } from "@hpke/core"; 2 | import { Chacha20Poly1305 } from "@hpke/chacha20poly1305"; 3 | 4 | async function doHpke() { 5 | // setup 6 | const suite = new CipherSuite({ 7 | kem: new DhkemP256HkdfSha256(), 8 | kdf: new HkdfSha256(), 9 | aead: new Chacha20Poly1305(), 10 | }); 11 | 12 | const rkp = await suite.kem.generateKeyPair(); 13 | 14 | const sender = await suite.createSenderContext({ 15 | recipientPublicKey: rkp.publicKey, 16 | }); 17 | 18 | const recipient = await suite.createRecipientContext({ 19 | recipientKey: rkp.privateKey, 20 | enc: sender.enc, 21 | }); 22 | 23 | // encrypt 24 | const ct = await sender.seal( 25 | new TextEncoder().encode("Hello world!").buffer as ArrayBuffer, 26 | ); 27 | 28 | // decrypt 29 | const pt = await recipient.open(ct); 30 | 31 | // Hello world! 32 | console.log(new TextDecoder().decode(pt)); 33 | } 34 | 35 | try { 36 | doHpke(); 37 | } catch (err: unknown) { 38 | console.log("Error: ", err as Error); 39 | } 40 | -------------------------------------------------------------------------------- /packages/hpke-js/samples/ts-node/app.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Aes128Gcm, 3 | CipherSuite, 4 | DhkemP256HkdfSha256, 5 | HkdfSha256, 6 | } from "@hpke/core"; 7 | // import { AeadId, CipherSuite, KdfId, KemId } from "hpke-js"; 8 | 9 | async function doHpke() { 10 | const suite: CipherSuite = new CipherSuite({ 11 | kem: new DhkemP256HkdfSha256(), 12 | kdf: new HkdfSha256(), 13 | aead: new Aes128Gcm(), 14 | }); 15 | 16 | const rkp = await suite.kem.generateKeyPair(); 17 | 18 | const sender = await suite.createSenderContext({ 19 | recipientPublicKey: rkp.publicKey, 20 | }); 21 | 22 | const recipient = await suite.createRecipientContext({ 23 | recipientKey: rkp.privateKey, 24 | enc: sender.enc, 25 | }); 26 | 27 | // encrypt 28 | const ct = await sender.seal( 29 | new TextEncoder().encode("my-secret-message").buffer as ArrayBuffer, 30 | ); 31 | 32 | // decrypt 33 | const pt = await recipient.open(ct); 34 | 35 | // new TextDecoder().decode(pt) === "my-secret-message" 36 | console.log("decrypted: ", new TextDecoder().decode(pt)); 37 | } 38 | 39 | doHpke(); 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Ajitomi Daisuke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/ml-kem/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Ajitomi Daisuke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /packages/common/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Ajitomi Daisuke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/core/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ajitomi Daisuke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/hpke-js/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Ajitomi Daisuke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ajitomi Daisuke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/dhkem-x448/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ajitomi Daisuke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ajitomi Daisuke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ajitomi Daisuke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ajitomi Daisuke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ajitomi Daisuke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/bun/hpke.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "bun:test"; 2 | 3 | import { CipherSuite } from "hpke-js"; 4 | 5 | test("bun - normal cases", async () => { 6 | for (const kem of [0x0010, 0x0011, 0x0012, 0x0020, 0x0021]) { 7 | for (const kdf of [0x0001, 0x0002, 0x0003]) { 8 | for (const aead of [0x0001, 0x0002, 0x0003]) { 9 | try { 10 | const suite = new CipherSuite({ kem: kem, kdf: kdf, aead: aead }); 11 | const rkp = await suite.kem.generateKeyPair(); 12 | const sender = await suite.createSenderContext({ 13 | recipientPublicKey: rkp.publicKey, 14 | }); 15 | const recipient = await suite.createRecipientContext({ 16 | recipientKey: rkp, 17 | enc: sender.enc, 18 | }); 19 | const ct = await sender.seal( 20 | new TextEncoder().encode("hello world!"), 21 | ); 22 | const pt = await recipient.open(ct); 23 | expect(new TextDecoder().decode(pt)).toBe("hello world!"); 24 | } catch (e: unknown) { 25 | expect().fail("ng: " + (e as Error).message); 26 | } 27 | } 28 | } 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /packages/common/src/interfaces/aeadEncryptionContext.ts: -------------------------------------------------------------------------------- 1 | // The key usages for AEAD. 2 | export const AEAD_USAGES: KeyUsage[] = ["encrypt", "decrypt"]; 3 | 4 | /** 5 | * The AEAD encryption context interface. 6 | */ 7 | export interface AeadEncryptionContext { 8 | /** 9 | * Encrypts data with an initialization vector and additional authenticated data. 10 | * 11 | * @param iv An initialization vector. 12 | * @param data A plain text as bytes to be encrypted. 13 | * @param aad Additional authenticated data as bytes fed by an application. 14 | * @returns A cipher text as bytes. 15 | */ 16 | seal( 17 | iv: ArrayBuffer, 18 | data: ArrayBuffer, 19 | aad: ArrayBuffer, 20 | ): Promise; 21 | 22 | /** 23 | * Decrypts data with an initialization vector and additional authenticated data. 24 | * 25 | * @param iv An initialization vector. 26 | * @param data A plain text as bytes to be encrypted. 27 | * @param aad Additional authenticated data as bytes fed by an application. 28 | * @returns A decrypted plain text as bytes. 29 | */ 30 | open( 31 | iv: ArrayBuffer, 32 | data: ArrayBuffer, 33 | aad: ArrayBuffer, 34 | ): Promise; 35 | } 36 | -------------------------------------------------------------------------------- /packages/core/src/aeads/exportOnly.ts: -------------------------------------------------------------------------------- 1 | import type { AeadEncryptionContext, AeadInterface } from "@hpke/common"; 2 | import { AeadId, NotSupportedError } from "@hpke/common"; 3 | 4 | /** 5 | * The ExportOnly mode for HPKE AEAD implementing {@link AeadInterface}. 6 | * 7 | * When using `@hpke/core`, the instance of this class must be specified 8 | * to the `aead` parameter of {@link CipherSuiteParams} instead of `AeadId.ExportOnly` 9 | * as follows: 10 | * 11 | * @example 12 | * 13 | * ```ts 14 | * import { 15 | * CipherSuite, 16 | * DhkemP256HkdfSha256, 17 | * ExportOnly, 18 | * HkdfSha256, 19 | * } from "@hpke/core"; 20 | * 21 | * const suite = new CipherSuite({ 22 | * kem: new DhkemP256HkdfSha256(), 23 | * kdf: new HkdfSha256(), 24 | * aead: new ExportOnly(), 25 | * }); 26 | * ``` 27 | */ 28 | export class ExportOnly implements AeadInterface { 29 | public readonly id: AeadId = AeadId.ExportOnly; 30 | public readonly keySize: number = 0; 31 | public readonly nonceSize: number = 0; 32 | public readonly tagSize: number = 0; 33 | 34 | public createEncryptionContext(_key: ArrayBuffer): AeadEncryptionContext { 35 | throw new NotSupportedError("Export only"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/samples/deno/main.ts: -------------------------------------------------------------------------------- 1 | // import { Aes256Gcm, CipherSuite, HkdfSha256 } from "@hpke/core"; 2 | // import { HybridkemX25519Kyber768 } from "@hpke/hybridkem-x25519-kyber768"; 3 | // 4 | // async function doHpke() { 5 | // // setup 6 | // const suite = new CipherSuite({ 7 | // kem: new HybridkemX25519Kyber768(), 8 | // kdf: new HkdfSha256(), 9 | // aead: new Aes256Gcm(), 10 | // }); 11 | // 12 | // const rkp = await suite.kem.generateKeyPair(); 13 | // 14 | // const sender = await suite.createSenderContext({ 15 | // recipientPublicKey: rkp.publicKey, 16 | // }); 17 | // 18 | // const recipient = await suite.createRecipientContext({ 19 | // recipientKey: rkp.privateKey, 20 | // enc: sender.enc, 21 | // }); 22 | // 23 | // // encrypt 24 | // const ct = await sender.seal( 25 | // new TextEncoder().encode("Hello world!").buffer as ArrayBuffer, 26 | // ); 27 | // 28 | // // decrypt 29 | // const pt = await recipient.open(ct); 30 | // 31 | // // Hello world! 32 | // console.log(new TextDecoder().decode(pt)); 33 | // } 34 | // 35 | // try { 36 | // doHpke(); 37 | // } catch (err: unknown) { 38 | // console.log("Error: ", err as Error); 39 | // } 40 | -------------------------------------------------------------------------------- /packages/common/src/interfaces/dhkemPrimitives.ts: -------------------------------------------------------------------------------- 1 | // The key usages for KEM. 2 | export const KEM_USAGES: KeyUsage[] = ["deriveBits"]; 3 | 4 | // b"dkp_prk" 5 | export const LABEL_DKP_PRK: Uint8Array = /* @__PURE__ */ new Uint8Array([ 6 | 100, 7 | 107, 8 | 112, 9 | 95, 10 | 112, 11 | 114, 12 | 107, 13 | ]); 14 | 15 | // b"sk" 16 | export const LABEL_SK: Uint8Array = /* @__PURE__ */ new Uint8Array([115, 107]); 17 | 18 | export interface DhkemPrimitives { 19 | serializePublicKey(key: CryptoKey): Promise; 20 | 21 | deserializePublicKey(key: ArrayBuffer): Promise; 22 | 23 | serializePrivateKey(key: CryptoKey): Promise; 24 | 25 | deserializePrivateKey(key: ArrayBuffer): Promise; 26 | 27 | importKey( 28 | format: "raw" | "jwk", 29 | key: ArrayBuffer | JsonWebKey, 30 | isPublic: boolean, 31 | ): Promise; 32 | 33 | generateKeyPair(): Promise; 34 | 35 | deriveKeyPair(ikm: ArrayBuffer): Promise; 36 | 37 | // DHKEM-specific function. 38 | derivePublicKey(key: CryptoKey): Promise; 39 | 40 | // DHKEM-specific function. 41 | dh(sk: CryptoKey, pk: CryptoKey): Promise; 42 | } 43 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/test/errors.test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "@std/assert"; 2 | 3 | import { describe, it } from "@std/testing/bdd"; 4 | 5 | import { KyberError } from "../src/kyber/errors.ts"; 6 | 7 | describe("KyberError", () => { 8 | describe("constructor with neigher string or Error", () => { 9 | it("should have valid name and message", () => { 10 | const err = new KyberError(undefined); 11 | 12 | // assert 13 | assertEquals(err.name, "KyberError"); 14 | assertEquals(err.message, ""); 15 | }); 16 | }); 17 | 18 | describe("constructor with string", () => { 19 | it("should have valid name and message", () => { 20 | const err = new KyberError("failed"); 21 | 22 | // assert 23 | assertEquals(err.name, "KyberError"); 24 | assertEquals(err.message, "failed"); 25 | }); 26 | }); 27 | 28 | describe("constructor with another Error", () => { 29 | it("should have valid name and message", () => { 30 | const origin = new Error("failed"); 31 | const err = new KyberError(origin); 32 | 33 | // assert 34 | assertEquals(err.name, "KyberError"); 35 | assertEquals(err.message, "failed"); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /packages/common/src/utils/bignum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The minimum inplementation of bignum to derive an EC key pair. 3 | */ 4 | export class Bignum { 5 | private _num: Uint8Array; 6 | 7 | public constructor(size: number) { 8 | this._num = new Uint8Array(size); 9 | } 10 | 11 | public val(): Uint8Array { 12 | return this._num; 13 | } 14 | 15 | public reset() { 16 | this._num.fill(0); 17 | } 18 | 19 | public set(src: Uint8Array) { 20 | if (src.length !== this._num.length) { 21 | throw new Error("Bignum.set: invalid argument"); 22 | } 23 | this._num.set(src); 24 | } 25 | 26 | public isZero(): boolean { 27 | for (let i = 0; i < this._num.length; i++) { 28 | if (this._num[i] !== 0) { 29 | return false; 30 | } 31 | } 32 | return true; 33 | } 34 | 35 | public lessThan(v: Uint8Array): boolean { 36 | if (v.length !== this._num.length) { 37 | throw new Error("Bignum.lessThan: invalid argument"); 38 | } 39 | for (let i = 0; i < this._num.length; i++) { 40 | if (this._num[i] < v[i]) { 41 | return true; 42 | } 43 | if (this._num[i] > v[i]) { 44 | return false; 45 | } 46 | } 47 | return false; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/common/src/curve/modular.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is based on noble-curves (https://github.com/paulmillr/noble-curves). 3 | * 4 | * noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) 5 | * 6 | * The original file is located at: 7 | * https://github.com/paulmillr/noble-curves/blob/b9d49d2b41d550571a0c5be443ecb62109fa3373/src/abstract/modular.ts 8 | */ 9 | 10 | /** 11 | * Utils for modular division and fields. 12 | * Field over 11 is a finite (Galois) field is integer number operations `mod 11`. 13 | * There is no division: it is replaced by modular multiplicative inverse. 14 | * @module 15 | */ 16 | /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ 17 | 18 | import { N_0 } from "../consts.ts"; 19 | 20 | // Numbers aren't used in x25519 / x448 builds 21 | 22 | // Calculates a modulo b 23 | export function mod(a: bigint, b: bigint): bigint { 24 | const result = a % b; 25 | return result >= N_0 ? result : b + result; 26 | } 27 | 28 | /** Does `x^(2^power)` mod p. `pow2(30, 4)` == `30^(2^4)` */ 29 | export function pow2(x: bigint, power: bigint, modulo: bigint): bigint { 30 | let res = x; 31 | while (power-- > N_0) { 32 | res *= res; 33 | res %= modulo; 34 | } 35 | return res; 36 | } 37 | -------------------------------------------------------------------------------- /packages/core/src/senderContext.ts: -------------------------------------------------------------------------------- 1 | import type { KdfInterface } from "@hpke/common"; 2 | import { EMPTY, SealError } from "@hpke/common"; 3 | 4 | import type { AeadParams } from "./interfaces/aeadParams.ts"; 5 | import type { Encapsulator } from "./interfaces/encapsulator.ts"; 6 | import { EncryptionContextImpl } from "./encryptionContext.ts"; 7 | import { Mutex } from "./mutex.ts"; 8 | 9 | export class SenderContextImpl extends EncryptionContextImpl 10 | implements Encapsulator { 11 | public readonly enc: ArrayBuffer; 12 | #mutex?: Mutex; 13 | 14 | constructor( 15 | api: SubtleCrypto, 16 | kdf: KdfInterface, 17 | params: AeadParams, 18 | enc: ArrayBuffer, 19 | ) { 20 | super(api, kdf, params); 21 | this.enc = enc; 22 | } 23 | 24 | override async seal( 25 | data: ArrayBuffer, 26 | aad: ArrayBuffer = EMPTY.buffer as ArrayBuffer, 27 | ): Promise { 28 | this.#mutex ??= new Mutex(); 29 | const release = await this.#mutex.lock(); 30 | let ct: ArrayBuffer; 31 | try { 32 | ct = await this._ctx.key.seal(this.computeNonce(this._ctx), data, aad); 33 | } catch (e: unknown) { 34 | throw new SealError(e); 35 | } finally { 36 | release(); 37 | } 38 | this.incrementSeq(this._ctx); 39 | return ct; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/core/src/kems/dhkemX448.ts: -------------------------------------------------------------------------------- 1 | import { Dhkem, HkdfSha512Native, KemId } from "@hpke/common"; 2 | 3 | import { X448 } from "./dhkemPrimitives/x448.ts"; 4 | 5 | /** 6 | * The DHKEM(X448, HKDF-SHA512) for HPKE KEM implementing {@link KemInterface}. 7 | * 8 | * The instance of this class can be specified to the 9 | * {@link https://jsr.io/@hpke/core/doc/~/CipherSuiteParams | CipherSuiteParams} as follows: 10 | * 11 | * @example 12 | * 13 | * ```ts 14 | * import { 15 | * Aes256Gcm, 16 | * CipherSuite, 17 | * HkdfSha512, 18 | * DhkemX448HkdfSha512, 19 | * } from "@hpke/core"; 20 | * 21 | * const suite = new CipherSuite({ 22 | * kem: new DhkemX448HkdfSha512(), 23 | * kdf: new HkdfSha512(), 24 | * aead: new Aes256Gcm(), 25 | * }); 26 | * ``` 27 | */ 28 | export class DhkemX448HkdfSha512 extends Dhkem { 29 | /** KemId.DhkemX448HkdfSha512 (0x0021) */ 30 | override id: KemId = KemId.DhkemX448HkdfSha512; 31 | /** 64 */ 32 | override secretSize: number = 64; 33 | /** 56 */ 34 | override encSize: number = 56; 35 | /** 56 */ 36 | override publicKeySize: number = 56; 37 | /** 56 */ 38 | override privateKeySize: number = 56; 39 | 40 | constructor() { 41 | const kdf = new HkdfSha512Native(); 42 | super(KemId.DhkemX448HkdfSha512, new X448(kdf), kdf); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/src/kyber/kyber768.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This implementation is based on https://github.com/antontutoveanu/crystals-kyber-javascript, 3 | * which was deveploped under the MIT licence below: 4 | * https://github.com/antontutoveanu/crystals-kyber-javascript/blob/main/LICENSE 5 | */ 6 | import { N } from "./consts.ts"; 7 | import { KyberBase } from "./kyberBase.ts"; 8 | 9 | /** 10 | * The Kyber768 implementation. 11 | * 12 | * @example 13 | * 14 | * ```ts 15 | * import { Kyber768 } from "./kyber768.ts"; 16 | * 17 | * const recipient = new Kyber768(); 18 | * const [pkR, skR] = await recipient.generateKeyPair(); 19 | 20 | * const sender = new Kyber768(); 21 | * const [ct, ssS] = await sender.encap(pkR); 22 | 23 | * const ssR = await recipient.decap(ct, skR); 24 | 25 | * console.assert(ssS === ssR, "The two shared secrets must match."); 26 | * ``` 27 | */ 28 | export class Kyber768 extends KyberBase { 29 | override _k = 3; 30 | override _du = 10; 31 | override _dv = 4; 32 | override _eta1 = 2; 33 | override _eta2 = 2; 34 | 35 | constructor() { 36 | super(); 37 | this._skSize = 12 * this._k * N / 8; 38 | this._pkSize = this._skSize + 32; 39 | this._compressedUSize = this._k * this._du * N / 8; 40 | this._compressedVSize = this._dv * N / 8; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/CHANGES.md: -------------------------------------------------------------------------------- 1 | # Changes 2 | 3 | ## Version 1.7.1 4 | 5 | Released 2025-08-15 6 | 7 | - [(#606) chacha20poly1305: remove unused funcs.](https://github.com/dajiaji/hpke-js/pull/606) 8 | 9 | ## Version 1.7.0 10 | 11 | Released 2025-08-09 12 | 13 | - [(#547) chacha20poly1305: import chacha20 implementation from @noble/ciphers.](https://github.com/dajiaji/hpke-js/pull/547) 14 | 15 | ## Version 1.6.3 16 | 17 | Released 2025-07-12 18 | 19 | - [(#527) base: bump @noble/cipher to 1.3.0](https://github.com/dajiaji/hpke-js/pull/527) 20 | - [(#526) base: bump @hpke/core to 1.7.3](https://github.com/dajiaji/hpke-js/pull/526) 21 | - [(#504) Add deno check to deno.json.](https://github.com/dajiaji/hpke-js/pull/504) 22 | 23 | ## Version 1.6.2 24 | 25 | Released 2025-03-09 26 | 27 | - [(#493) Bump @hpke/core to 1.7.2.](https://github.com/dajiaji/hpke-js/pull/493) 28 | - [(#491) Remove package-lock.json for cloudflare test.](https://github.com/dajiaji/hpke-js/pull/491) 29 | - [(#489) Bump @hpke/common to 1.7.2.](https://github.com/dajiaji/hpke-js/pull/489) 30 | - [(#483) Bump @noble/ciphers to 1.2.1.](https://github.com/dajiaji/hpke-js/pull/483) 31 | - [(#483) Apply deno formatter/linter.](https://github.com/dajiaji/hpke-js/pull/483) 32 | - [(#483) Fix type declaration error.](https://github.com/dajiaji/hpke-js/pull/483) 33 | -------------------------------------------------------------------------------- /packages/core/src/kems/dhkemX25519.ts: -------------------------------------------------------------------------------- 1 | import { Dhkem, HkdfSha256Native, KemId } from "@hpke/common"; 2 | 3 | import { X25519 } from "./dhkemPrimitives/x25519.ts"; 4 | 5 | /** 6 | * The DHKEM(X25519, HKDF-SHA256) for HPKE KEM implementing {@link KemInterface}. 7 | * 8 | * The instance of this class can be specified to the 9 | * {@link https://jsr.io/@hpke/core/doc/~/CipherSuiteParams | CipherSuiteParams} as follows: 10 | * 11 | * @example 12 | * 13 | * ```ts 14 | * import { 15 | * Aes128Gcm, 16 | * CipherSuite, 17 | * HkdfSha256, 18 | * DhkemX25519HkdfSha256, 19 | * } from "@hpke/core"; 20 | * 21 | * const suite = new CipherSuite({ 22 | * kem: new DhkemX25519HkdfSha256(), 23 | * kdf: new HkdfSha256(), 24 | * aead: new Aes128Gcm(), 25 | * }); 26 | * ``` 27 | */ 28 | export class DhkemX25519HkdfSha256 extends Dhkem { 29 | /** KemId.DhkemX25519HkdfSha256 (0x0020) */ 30 | override id: KemId = KemId.DhkemX25519HkdfSha256; 31 | /** 32 */ 32 | override secretSize: number = 32; 33 | /** 32 */ 34 | override encSize: number = 32; 35 | /** 32 */ 36 | override publicKeySize: number = 32; 37 | /** 32 */ 38 | override privateKeySize: number = 32; 39 | 40 | constructor() { 41 | const kdf = new HkdfSha256Native(); 42 | super(KemId.DhkemX25519HkdfSha256, new X25519(kdf), kdf); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/hpke-js/samples/ts-webpack/app.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Aes128Gcm, 3 | CipherSuite, 4 | DhkemP256HkdfSha256, 5 | HkdfSha256, 6 | } from "@hpke/core"; 7 | 8 | export const test = async () => { 9 | const suite = new CipherSuite({ 10 | kem: new DhkemP256HkdfSha256(), 11 | kdf: new HkdfSha256(), 12 | aead: new Aes128Gcm(), 13 | }); 14 | 15 | // I expected to be able to do: 16 | // const rkp = await suite.kem.generateKeyPair(); 17 | // instead I needed to do: 18 | const extractable = true; 19 | const rkp = await globalThis.crypto.subtle.generateKey( 20 | { 21 | name: "ECDH", 22 | namedCurve: "P-256", 23 | }, 24 | extractable, 25 | ["deriveBits"], 26 | ); 27 | 28 | // A sender encrypts a message. 29 | const sender = await suite.createSenderContext({ 30 | recipientPublicKey: rkp.publicKey, 31 | }); 32 | const ct = await sender.seal( 33 | new TextEncoder().encode("✨ hello world! ✨").buffer as ArrayBuffer, 34 | ); 35 | // A recipient decripts it. 36 | const recipient = await suite.createRecipientContext({ 37 | recipientKey: rkp.privateKey, 38 | enc: sender.enc, 39 | }); 40 | try { 41 | const pt = await recipient.open(ct); 42 | // hello world! 43 | alert(new TextDecoder().decode(pt)); 44 | } catch (_err) { 45 | alert("failed to decrypt."); 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /packages/common/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hpke/common", 3 | "version": "1.8.1", 4 | "exports": "./mod.ts", 5 | "publish": { 6 | "exclude": [ 7 | "dnt.ts", 8 | "test/", 9 | "tsconfig.json" 10 | ] 11 | }, 12 | "fmt": { 13 | "include": [ 14 | "**/*.md", 15 | "**/*.json", 16 | "dnt.ts", 17 | "mod.ts", 18 | "src/", 19 | "test/" 20 | ], 21 | "exclude": [ 22 | "**/*/*.js", 23 | "**/*/npm/", 24 | "coverage/*.json" 25 | ] 26 | }, 27 | "lint": { 28 | "include": [ 29 | "**/*.md", 30 | "**/*.json", 31 | "dnt.ts", 32 | "mod.ts", 33 | "src/", 34 | "test/" 35 | ], 36 | "exclude": [ 37 | "**/*/*.js", 38 | "**/*/npm/", 39 | "coverage/*.json" 40 | ] 41 | }, 42 | "tasks": { 43 | "test": "deno fmt && deno lint && deno task check && deno test --fail-fast --doc --coverage=coverage --parallel --allow-read", 44 | "check": "deno check *.ts src/**/*.ts test/*.ts", 45 | "cov": "deno coverage ./coverage --lcov --exclude='test'", 46 | "npm-build": "deno run --import-map=../../npm/import_map.json -A dnt.ts --skip-test", 47 | "dnt": "deno run --import-map=../../npm/import_map.json -A dnt.ts", 48 | "minify": "esbuild ../../npm/packages/common/esm/mod.js --bundle --format=esm --minify" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/ml-kem/CHANGES.md: -------------------------------------------------------------------------------- 1 | # Changes 2 | 3 | ## Version 0.2.1 4 | 5 | Released 2025-08-15 6 | 7 | - [(#625) base: add deno task test:browsers.](https://github.com/dajiaji/hpke-js/pull/625) 8 | - [(#623) base: update test dependencies.](https://github.com/dajiaji/hpke-js/pull/623) 9 | - [(#622) base: add deno task update.](https://github.com/dajiaji/hpke-js/pull/622) 10 | - [(#617) base: add deno task dry-publish.](https://github.com/dajiaji/hpke-js/pull/617) 11 | - [(#616) base: add deno task minify.](https://github.com/dajiaji/hpke-js/pull/616) 12 | - [(#615) base: remove dependency on noble/hashes/sha3.](https://github.com/dajiaji/hpke-js/pull/615) 13 | - [(#614) base: add deno task npm-build.](https://github.com/dajiaji/hpke-js/pull/614) 14 | - [(#613) base: add deno task check.](https://github.com/dajiaji/hpke-js/pull/613) 15 | - [(#610) base: remove path to noble from tsconfig.json.](https://github.com/dajiaji/hpke-js/pull/610) 16 | 17 | ## Version 0.2.0 18 | 19 | Released 2025-08-11 20 | 21 | - [(#567) ml-kem: bump mlkem to 2.5.0.](https://github.com/dajiaji/hpke-js/pull/567) 22 | 23 | ## Version 0.1.1 24 | 25 | Released 2025-07-13 26 | 27 | - [(#526) base: bump @hpke/core to 1.7.3](https://github.com/dajiaji/hpke-js/pull/526) 28 | - [(#524) base: bump @hpke/common to 1.7.3](https://github.com/dajiaji/hpke-js/pull/524) 29 | 30 | Released 2024-11-10 31 | 32 | - First public preview release. 33 | -------------------------------------------------------------------------------- /packages/core/mod.ts: -------------------------------------------------------------------------------- 1 | export type { 2 | AeadEncryptionContext, 3 | AeadInterface, 4 | JsonWebKeyExtended, 5 | KdfInterface, 6 | KemInterface, 7 | PreSharedKey, 8 | RecipientContextParams, 9 | SenderContextParams, 10 | } from "@hpke/common"; 11 | 12 | export type { CipherSuiteParams } from "./src/interfaces/cipherSuiteParams.ts"; 13 | export type { 14 | EncryptionContext, 15 | RecipientContext, 16 | SenderContext, 17 | } from "./src/interfaces/encryptionContext.ts"; 18 | export type { CipherSuiteSealResponse } from "./src/interfaces/responses.ts"; 19 | 20 | export { 21 | AeadId, 22 | DecapError, 23 | DeriveKeyPairError, 24 | DeserializeError, 25 | EncapError, 26 | ExportError, 27 | HpkeError, 28 | InvalidParamError, 29 | KdfId, 30 | KemId, 31 | MessageLimitReachedError, 32 | NotSupportedError, 33 | OpenError, 34 | SealError, 35 | SerializeError, 36 | ValidationError, 37 | } from "@hpke/common"; 38 | export { Aes128Gcm, Aes256Gcm } from "./src/aeads/aesGcm.ts"; 39 | export { ExportOnly } from "./src/aeads/exportOnly.ts"; 40 | export { 41 | CipherSuite, 42 | DhkemP256HkdfSha256, 43 | DhkemP384HkdfSha384, 44 | DhkemP521HkdfSha512, 45 | HkdfSha256, 46 | HkdfSha384, 47 | HkdfSha512, 48 | } from "./src/native.ts"; 49 | 50 | export { DhkemX25519HkdfSha256 } from "./src/kems/dhkemX25519.ts"; 51 | export { DhkemX448HkdfSha512 } from "./src/kems/dhkemX448.ts"; 52 | -------------------------------------------------------------------------------- /packages/common/src/curve/curve.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is based on noble-curves (https://github.com/paulmillr/noble-curves). 3 | * 4 | * noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) 5 | * 6 | * The original file is located at: 7 | * https://github.com/paulmillr/noble-curves/blob/b9d49d2b41d550571a0c5be443ecb62109fa3373/src/abstract/curve.ts 8 | */ 9 | 10 | /** 11 | * Methods for elliptic curve multiplication by scalars. 12 | * Contains wNAF, pippenger. 13 | * @module 14 | */ 15 | /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ 16 | import type { Signer } from "../utils/noble.ts"; 17 | 18 | // import { Field, FpInvertBatch, type IField, validateField } from "./modular.ts"; 19 | 20 | export interface CurveLengths { 21 | secretKey?: number; 22 | publicKey?: number; 23 | publicKeyUncompressed?: number; 24 | publicKeyHasPrefix?: boolean; 25 | signature?: number; 26 | seed?: number; 27 | } 28 | 29 | type KeygenFn = ( 30 | seed?: Uint8Array, 31 | isCompressed?: boolean, 32 | ) => { secretKey: Uint8Array; publicKey: Uint8Array }; 33 | export function createKeygen( 34 | // deno-lint-ignore ban-types 35 | randomSecretKey: Function, 36 | getPublicKey: Signer["getPublicKey"], 37 | ): KeygenFn { 38 | return function keygen(seed?: Uint8Array) { 39 | const secretKey = randomSecretKey(seed); 40 | return { secretKey, publicKey: getPublicKey(secretKey) }; 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /packages/core/src/interfaces/encryptionContext.ts: -------------------------------------------------------------------------------- 1 | import type { Exporter } from "./exporter.ts"; 2 | 3 | /** 4 | * The encryption context interface for a recipient and a sender. 5 | */ 6 | export interface EncryptionContext extends Exporter { 7 | /** 8 | * Encrypts data. 9 | * 10 | * If the error occurred, throws `SealError` | `MessageLimitReachedError`. 11 | * 12 | * @param data A plain text as bytes to be encrypted. 13 | * @param aad Additional authenticated data as bytes fed by an application. 14 | * @returns A cipher text as bytes. 15 | * @throws {@link MessageLimitReachedError}, {@link SealError} 16 | */ 17 | seal(data: ArrayBuffer, aad?: ArrayBuffer): Promise; 18 | 19 | /** 20 | * Decrypts data. 21 | * 22 | * If the error occurred, throws `OpenError`. 23 | * 24 | * @param data An encrypted text as bytes to be decrypted. 25 | * @param aad Additional authenticated data as bytes fed by an application. 26 | * @returns A decrypted plain text as bytes. 27 | * @throws {@link OpenError} 28 | */ 29 | open(data: ArrayBuffer, aad?: ArrayBuffer): Promise; 30 | } 31 | 32 | /** 33 | * The recipient encryption context. 34 | */ 35 | export type RecipientContext = EncryptionContext; 36 | 37 | /** 38 | * The sender encryption context. 39 | */ 40 | export interface SenderContext extends EncryptionContext { 41 | /** The encapsulated key generated by the sender. */ 42 | enc: ArrayBuffer; 43 | } 44 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/CHANGES.md: -------------------------------------------------------------------------------- 1 | # Changes 2 | 3 | ## Version 1.6.4 4 | 5 | Released 2025-08-13 6 | 7 | - [(#617) base: add deno task dry-publish.](https://github.com/dajiaji/hpke-js/pull/617) 8 | - [(#616) base: add deno task minify.](https://github.com/dajiaji/hpke-js/pull/616) 9 | - [(#614) base: add deno task npm-build.](https://github.com/dajiaji/hpke-js/pull/614) 10 | - [(#613) base: add deno task check.](https://github.com/dajiaji/hpke-js/pull/613) 11 | - [(#612) base: bump common to 1.8.0.](https://github.com/dajiaji/hpke-js/pull/612) 12 | - [(#610) base: remove path to noble from tsconfig.json.](https://github.com/dajiaji/hpke-js/pull/610) 13 | 14 | ## Version 1.6.3 15 | 16 | Released 2025-08-12 17 | 18 | - [(#594) dhkem-secp256k1: bump noble/curves to 1.9.6.](https://github.com/dajiaji/hpke-js/pull/594) 19 | - [(#593) base: bump samples dependencies to latest.](https://github.com/dajiaji/hpke-js/pull/593) 20 | - [(#555) dhkem-secp256k1: use local http-server for testing on browsers.](https://github.com/dajiaji/hpke-js/pull/555) 21 | 22 | ## Version 1.6.2 23 | 24 | Released 2025-07-13 25 | 26 | - [(#533) base: bump @hpke/dhkem-x25519 to 1.6.3](https://github.com/dajiaji/hpke-js/pull/533) 27 | - [(#529) base: bump @noble/curves to 1.9.2](https://github.com/dajiaji/hpke-js/pull/529) 28 | - [(#526) base: bump @hpke/core to 1.7.3](https://github.com/dajiaji/hpke-js/pull/526) 29 | - [(#524) base: bump @hpke/common to 1.7.3](https://github.com/dajiaji/hpke-js/pull/524) 30 | -------------------------------------------------------------------------------- /packages/hpke-js/samples/browser/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /packages/hpke-js/test/keyValidationX448.test.ts: -------------------------------------------------------------------------------- 1 | import { afterAll, beforeAll, describe, it } from "@std/testing/bdd"; 2 | 3 | import type { ConformanceTester } from "./conformanceTester.ts"; 4 | import type { WycheproofTestVector } from "./testVector.ts"; 5 | 6 | import { createConformanceTester } from "./conformanceTester.ts"; 7 | import { getPath } from "./utils.ts"; 8 | 9 | describe("X448 key validation", () => { 10 | let totalCount: number; 11 | let tester: ConformanceTester; 12 | 13 | beforeAll(async () => { 14 | tester = await createConformanceTester(); 15 | totalCount = 0; 16 | }); 17 | 18 | afterAll(() => { 19 | const count = tester.count(); 20 | console.log(`passed/total: ${count}/${totalCount}`); 21 | }); 22 | 23 | describe("X448", () => { 24 | it("should validate properly", async () => { 25 | // Use test vectors quoted from https://github.com/google/wycheproof under Apache-2.0 license. 26 | const tv: WycheproofTestVector = JSON.parse( 27 | await Deno.readTextFile( 28 | getPath("../../../test/vectors/x448_test.json"), 29 | ), 30 | ); 31 | 32 | totalCount += tv.testGroups[0].tests.length; 33 | 34 | for (const v of tv.testGroups[0].tests) { 35 | if (v.flags.find((k) => k === "ZeroSharedSecret")) { 36 | await tester.testInvalidX448PublicKey(v.public); 37 | } else if (v.flags.find((k) => k === "NonCanonicalPublic")) { 38 | continue; 39 | } else { 40 | await tester.testValidX448PublicKey(v.public); 41 | } 42 | } 43 | }); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /packages/hpke-js/test/runtimes/cloudflare/src/server.ts: -------------------------------------------------------------------------------- 1 | import { CipherSuite } from "hpke-js"; 2 | 3 | export async function testServer(request: Request): Promise { 4 | const url = new URL(request.url); 5 | if (url.pathname !== "/test") { 6 | return new Response("ng: invalid path"); 7 | } 8 | const params = url.searchParams; 9 | const kemStr = params.get("kem"); 10 | const kdfStr = params.get("kdf"); 11 | const aeadStr = params.get("aead"); 12 | if (kemStr === null || kdfStr === null || aeadStr === null) { 13 | return new Response("ng: invalid params"); 14 | } 15 | const kem = Number.parseInt(kemStr); 16 | const kdf = Number.parseInt(kdfStr); 17 | const aead = Number.parseInt(aeadStr); 18 | if (Number.isNaN(kem) || Number.isNaN(kdf) || Number.isNaN(aead)) { 19 | return new Response("ng: invalid params"); 20 | } 21 | 22 | try { 23 | const suite = new CipherSuite({ kem: kem, kdf: kdf, aead: aead }); 24 | const rkp = await suite.generateKeyPair(); 25 | const sender = await suite.createSenderContext({ 26 | recipientPublicKey: rkp.publicKey, 27 | }); 28 | const recipient = await suite.createRecipientContext({ 29 | recipientKey: rkp, 30 | enc: sender.enc, 31 | }); 32 | const ct = await sender.seal(new TextEncoder().encode("hello world!")); 33 | const pt = await recipient.open(ct); 34 | if ("hello world!" !== new TextDecoder().decode(pt)) { 35 | return new Response("ng"); 36 | } 37 | } catch (e: unknown) { 38 | return new Response("ng: " + (e as Error).message); 39 | } 40 | return new Response("ok"); 41 | } 42 | -------------------------------------------------------------------------------- /packages/core/test/testVector.ts: -------------------------------------------------------------------------------- 1 | import type { AeadId, KdfId, KemId } from "@hpke/common"; 2 | 3 | interface TestVectorEncryption { 4 | aad: string; 5 | ct: string; 6 | nonce: string; 7 | pt: string; 8 | } 9 | 10 | interface TestVectorExport { 11 | exporter_context: string; 12 | L: number; 13 | exported_value: string; 14 | } 15 | 16 | export interface TestVector { 17 | mode: number; 18 | kem_id: KemId; 19 | kdf_id: KdfId; 20 | aead_id: AeadId; 21 | psk_id?: string; 22 | psk?: string; 23 | info: string; 24 | ikmR: string; 25 | ikmE: string; 26 | skRm: string; 27 | skSm?: string; 28 | skEm: string; 29 | pkRm: string; 30 | pkSm?: string; 31 | pkEm: string; 32 | ier: string; 33 | enc: string; 34 | shared_secret: string; 35 | key_schedule_context: string; 36 | secret: string; 37 | key: string; 38 | base_nonce: string; 39 | exporter_secret: string; 40 | encryptions: Array; 41 | exports: Array; 42 | } 43 | 44 | // The minimum interface to load test vectors on https://github.com/google/wycheproof 45 | interface WycheproofTestCase { 46 | tcId: number; 47 | public: string; 48 | flags: Array; 49 | result: string; 50 | } 51 | 52 | // The minimum interface to load test vectors on https://github.com/google/wycheproof 53 | interface WycheproofTestGroup { 54 | tests: Array; 55 | } 56 | 57 | // The minimum interface to load test vectors on https://github.com/google/wycheproof 58 | export interface WycheproofTestVector { 59 | numberOfTests: number; 60 | testGroups: Array; 61 | } 62 | -------------------------------------------------------------------------------- /packages/hpke-js/test/testVector.ts: -------------------------------------------------------------------------------- 1 | import type { AeadId, KdfId, KemId } from "@hpke/core"; 2 | 3 | interface TestVectorEncryption { 4 | aad: string; 5 | ct: string; 6 | nonce: string; 7 | pt: string; 8 | } 9 | 10 | interface TestVectorExport { 11 | exporter_context: string; 12 | L: number; 13 | exported_value: string; 14 | } 15 | 16 | export interface TestVector { 17 | mode: number; 18 | kem_id: KemId; 19 | kdf_id: KdfId; 20 | aead_id: AeadId; 21 | psk_id?: string; 22 | psk?: string; 23 | info: string; 24 | ikmR: string; 25 | ikmE: string; 26 | skRm: string; 27 | skSm?: string; 28 | skEm: string; 29 | pkRm: string; 30 | pkSm?: string; 31 | pkEm: string; 32 | ier: string; 33 | enc: string; 34 | shared_secret: string; 35 | key_schedule_context: string; 36 | secret: string; 37 | key: string; 38 | base_nonce: string; 39 | exporter_secret: string; 40 | encryptions: Array; 41 | exports: Array; 42 | } 43 | 44 | // The minimum interface to load test vectors on https://github.com/google/wycheproof 45 | interface WycheproofTestCase { 46 | tcId: number; 47 | public: string; 48 | flags: Array; 49 | result: string; 50 | } 51 | 52 | // The minimum interface to load test vectors on https://github.com/google/wycheproof 53 | interface WycheproofTestGroup { 54 | tests: Array; 55 | } 56 | 57 | // The minimum interface to load test vectors on https://github.com/google/wycheproof 58 | export interface WycheproofTestVector { 59 | numberOfTests: number; 60 | testGroups: Array; 61 | } 62 | -------------------------------------------------------------------------------- /packages/hpke-js/src/identifiers.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The supported Key Encapsulation Mechanism (KEM) identifiers. 3 | * 4 | * @deprecated Use {@link KdfId} instead. 5 | */ 6 | export const Kem = { 7 | NotAssigned: 0x0000, 8 | DhkemP256HkdfSha256: 0x0010, 9 | DhkemP384HkdfSha384: 0x0011, 10 | DhkemP521HkdfSha512: 0x0012, 11 | DhkemSecp256k1HkdfSha256: 0x0013, 12 | DhkemX25519HkdfSha256: 0x0020, 13 | DhkemX448HkdfSha512: 0x0021, 14 | HybridkemX25519Kyber768: 0x0030, 15 | } as const; 16 | 17 | /** 18 | * The type alias of the supported KEM identifiers. 19 | * 20 | * @deprecated Use {@link KdfId} instead. 21 | */ 22 | export type Kem = typeof Kem[keyof typeof Kem]; 23 | 24 | /** 25 | * The supported Key Derivation Function (KDF) identifiers. 26 | * 27 | * @deprecated Use {@link KdfId} instead. 28 | */ 29 | export const Kdf = { 30 | HkdfSha256: 0x0001, 31 | HkdfSha384: 0x0002, 32 | HkdfSha512: 0x0003, 33 | } as const; 34 | 35 | /** 36 | * The type alias of the supported KDF identifiers. 37 | * 38 | * @deprecated Use {@link KdfId} instead. 39 | */ 40 | export type Kdf = typeof Kdf[keyof typeof Kdf]; 41 | 42 | /** 43 | * The supported Authenticated Encryption with Associated Data (AEAD) identifiers. 44 | * 45 | * @deprecated Use {@link AeadId} instead. 46 | */ 47 | export const Aead = { 48 | Aes128Gcm: 0x0001, 49 | Aes256Gcm: 0x0002, 50 | Chacha20Poly1305: 0x0003, 51 | ExportOnly: 0xFFFF, 52 | } as const; 53 | 54 | /** 55 | * The type alias of the supported AEAD identifiers. 56 | * 57 | * @deprecated Use {@link AeadId} instead. 58 | */ 59 | export type Aead = typeof Aead[keyof typeof Aead]; 60 | -------------------------------------------------------------------------------- /packages/core/src/kems/dhkemNative.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Dhkem, 3 | Ec, 4 | HkdfSha256Native, 5 | HkdfSha384Native, 6 | HkdfSha512Native, 7 | KemId, 8 | } from "@hpke/common"; 9 | 10 | export class DhkemP256HkdfSha256Native extends Dhkem { 11 | override id: KemId = KemId.DhkemP256HkdfSha256; 12 | override secretSize: number = 32; 13 | override encSize: number = 65; 14 | override publicKeySize: number = 65; 15 | override privateKeySize: number = 32; 16 | 17 | constructor() { 18 | const kdf = new HkdfSha256Native(); 19 | const prim = new Ec(KemId.DhkemP256HkdfSha256, kdf); 20 | super(KemId.DhkemP256HkdfSha256, prim, kdf); 21 | } 22 | } 23 | 24 | export class DhkemP384HkdfSha384Native extends Dhkem { 25 | override id: KemId = KemId.DhkemP384HkdfSha384; 26 | override secretSize: number = 48; 27 | override encSize: number = 97; 28 | override publicKeySize: number = 97; 29 | override privateKeySize: number = 48; 30 | 31 | constructor() { 32 | const kdf = new HkdfSha384Native(); 33 | const prim = new Ec(KemId.DhkemP384HkdfSha384, kdf); 34 | super(KemId.DhkemP384HkdfSha384, prim, kdf); 35 | } 36 | } 37 | 38 | export class DhkemP521HkdfSha512Native extends Dhkem { 39 | override id: KemId = KemId.DhkemP521HkdfSha512; 40 | override secretSize: number = 64; 41 | override encSize: number = 133; 42 | override publicKeySize: number = 133; 43 | override privateKeySize: number = 64; 44 | 45 | constructor() { 46 | const kdf = new HkdfSha512Native(); 47 | const prim = new Ec(KemId.DhkemP521HkdfSha512, kdf); 48 | super(KemId.DhkemP521HkdfSha512, prim, kdf); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/src/dhkemSecp256k1.ts: -------------------------------------------------------------------------------- 1 | import { Dhkem, KemId } from "@hpke/common"; 2 | import { HkdfSha256 } from "@hpke/dhkem-x25519"; 3 | 4 | import { Secp256k1 } from "./secp256k1.ts"; 5 | 6 | /** 7 | * The DHKEM(secp256k1, HKDF-SHA256) for HPKE KEM implementing {@link KemInterface}. 8 | * 9 | * This class is implemented using 10 | * {@link https://github.com/paulmillr/noble-curves | @noble/curves}. 11 | * 12 | * The public keys are assumed to be compressed. 13 | * 14 | * The instance of this class can be specified to the 15 | * {@link https://jsr.io/@hpke/core/doc/~/CipherSuiteParams | CipherSuiteParams} as follows: 16 | * 17 | * @example Use with `@hpke/core`: 18 | * 19 | * ```ts 20 | * import { 21 | * Aes128Gcm, 22 | * CipherSuite, 23 | * HkdfSha256, 24 | * } from "@hpke/core"; 25 | * import { DhkemSecp256k1HkdfSha256 } from "@hpke/dhkem-secp256k1"; 26 | * 27 | * const suite = new CipherSuite({ 28 | * kem: new DhkemSecp256k1HkdfSha256(), 29 | * kdf: new HkdfSha256(), 30 | * aead: new Aes128Gcm(), 31 | * }); 32 | * ``` 33 | * 34 | * @experimental Note that it is experimental and not standardized. 35 | */ 36 | export class DhkemSecp256k1HkdfSha256 extends Dhkem { 37 | /** KemId.DhkemSecp256k1HkdfSha256 (0x0013) EXPERIMENTAL */ 38 | override id: KemId = KemId.DhkemSecp256k1HkdfSha256; 39 | /** 32 */ 40 | override secretSize: number = 32; 41 | /** 33 */ 42 | override encSize: number = 33; 43 | /** 33 */ 44 | override publicKeySize: number = 33; 45 | /** 32 */ 46 | override privateKeySize: number = 32; 47 | 48 | constructor() { 49 | const kdf = new HkdfSha256(); 50 | super(KemId.DhkemSecp256k1HkdfSha256, new Secp256k1(kdf), kdf); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /utils/dntCommon.ts: -------------------------------------------------------------------------------- 1 | import { emptyDir } from "@deno/dnt"; 2 | import { copySync } from "@std/fs"; 3 | 4 | export async function beforeBuild(name: string): Promise { 5 | // Clean up dist 6 | await emptyDir(`../../npm/packages/${name}`); 7 | await emptyDir(`../../npm/samples/${name}`); 8 | await emptyDir(`../../npm/test/${name}/runtimes/browsers`); 9 | await emptyDir(`../../npm/test/${name}/runtimes/cloudflare`); 10 | 11 | // Remove node_modules 12 | try { 13 | await Deno.remove("test/runtimes/browsers/node_modules", { 14 | recursive: true, 15 | }); 16 | } catch { 17 | // ignore 18 | } 19 | try { 20 | await Deno.remove("test/runtimes/bun/node_modules", { 21 | recursive: true, 22 | }); 23 | } catch { 24 | // ignore 25 | } 26 | try { 27 | await Deno.remove("test/runtimes/browsers/node_modules", { 28 | recursive: true, 29 | }); 30 | } catch { 31 | // ignore 32 | } 33 | try { 34 | await Deno.remove("test/runtimes/cloudflare/node_modules", { 35 | recursive: true, 36 | }); 37 | } catch { 38 | // ignore 39 | } 40 | return; 41 | } 42 | 43 | export function afterBuild(name: string) { 44 | copySync( 45 | "samples/node", 46 | `../../npm/samples/${name}`, 47 | { overwrite: true }, 48 | ); 49 | copySync( 50 | "test/runtimes/browsers", 51 | `../../npm/test/${name}/runtimes/browsers`, 52 | { overwrite: true }, 53 | ); 54 | copySync( 55 | "test/runtimes/cloudflare", 56 | `../../npm/test/${name}/runtimes/cloudflare`, 57 | { overwrite: true }, 58 | ); 59 | Deno.copyFileSync("LICENSE", `../../npm/packages/${name}/LICENSE`); 60 | Deno.copyFileSync("README.md", `../../npm/packages/${name}/README.md`); 61 | } 62 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hpke/chacha20poly1305", 3 | "version": "1.7.1", 4 | "exports": "./mod.ts", 5 | "publish": { 6 | "exclude": [ 7 | "dnt.ts", 8 | "samples/", 9 | "test/", 10 | "tsconfig.json" 11 | ] 12 | }, 13 | "fmt": { 14 | "include": [ 15 | "**/*.md", 16 | "**/*.json", 17 | "dnt.ts", 18 | "mod.ts", 19 | "samples/", 20 | "src/", 21 | "test/" 22 | ], 23 | "exclude": [ 24 | "**/*/*.js", 25 | "**/*/npm/", 26 | "coverage/*.json" 27 | ] 28 | }, 29 | "lint": { 30 | "include": [ 31 | "**/*.md", 32 | "**/*.json", 33 | "dnt.ts", 34 | "mod.ts", 35 | "samples/", 36 | "src/", 37 | "test/" 38 | ], 39 | "exclude": [ 40 | "**/*/*.js", 41 | "**/*/npm/", 42 | "coverage/*.json" 43 | ] 44 | }, 45 | "tasks": { 46 | "test": "deno fmt && deno lint && deno task check && deno test --fail-fast --doc --coverage=coverage --parallel --allow-read", 47 | "test:cloudflare": "cd test/runtimes/cloudflare && npm install && npm link @hpke/common @hpke/chacha20poly1305 && npm run test", 48 | "test:bun": "cd test/runtimes/bun && bun install && bun test", 49 | "check": "deno check *.ts src/**/*.ts samples/**/*.ts test/*.ts", 50 | "cov": "deno coverage ./coverage --lcov --exclude='test'", 51 | "npm-build": "deno run --import-map=../../npm/import_map.json -A dnt.ts --skip-test", 52 | "dnt": "deno run --import-map=../../npm/import_map.json -A dnt.ts", 53 | "sample:deno": "cd samples/deno && deno run main.ts", 54 | "minify": "esbuild ../../npm/packages/chacha20poly1305/esm/mod.js --bundle --format=esm --minify" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/core/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hpke/core", 3 | "version": "1.7.5", 4 | "exports": "./mod.ts", 5 | "publish": { 6 | "exclude": [ 7 | "dnt.ts", 8 | "samples/", 9 | "test/", 10 | "tsconfig.json" 11 | ] 12 | }, 13 | "fmt": { 14 | "include": [ 15 | "**/*.md", 16 | "**/*.json", 17 | "dnt.ts", 18 | "mod.ts", 19 | "samples/", 20 | "src/", 21 | "test/" 22 | ], 23 | "exclude": [ 24 | "**/*/*.js", 25 | "**/*/npm/", 26 | "coverage/*.json" 27 | ] 28 | }, 29 | "lint": { 30 | "include": [ 31 | "**/*.md", 32 | "**/*.json", 33 | "dnt.ts", 34 | "mod.ts", 35 | "samples/", 36 | "src/", 37 | "test/" 38 | ], 39 | "exclude": [ 40 | "**/*/*.js", 41 | "**/*/npm/", 42 | "coverage/*.json" 43 | ] 44 | }, 45 | "tasks": { 46 | "test": "deno fmt && deno lint && deno task check && deno test --fail-fast --doc --coverage=coverage --parallel --allow-read", 47 | "test:cloudflare": "cd test/runtimes/cloudflare && npm install && npm link @hpke/core && npm run test", 48 | "test:bun": "cd test/runtimes/bun && bun install && bun test", 49 | "check": "deno check *.ts src/**/*.ts samples/**/*.ts test/*.ts", 50 | "cov": "deno coverage ./coverage --lcov --exclude='test'", 51 | "npm-build": "deno run --import-map=../../npm/import_map.json -A dnt.ts --skip-test", 52 | "dnt": "deno run --import-map=../../npm/import_map.json -A dnt.ts", 53 | "sample:deno": "cd samples/deno && deno run main.ts", 54 | "sample:node": "cd samples/node && npm install && node app.js", 55 | "minify": "esbuild ../../npm/packages/core/esm/mod.js --bundle --format=esm --minify" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/hpke-js/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hpke/hpke-js", 3 | "version": "1.6.5", 4 | "exports": "./mod.ts", 5 | "publish": { 6 | "exclude": [ 7 | "dnt.ts", 8 | "samples/", 9 | "test/", 10 | "tsconfig.json" 11 | ] 12 | }, 13 | "fmt": { 14 | "include": [ 15 | "**/*.md", 16 | "**/*.json", 17 | "dnt.ts", 18 | "mod.ts", 19 | "samples/", 20 | "src/", 21 | "test/" 22 | ], 23 | "exclude": [ 24 | "**/*/*.js", 25 | "**/*/npm/", 26 | "coverage/*.json" 27 | ] 28 | }, 29 | "lint": { 30 | "include": [ 31 | "**/*.md", 32 | "**/*.json", 33 | "dnt.ts", 34 | "mod.ts", 35 | "samples/", 36 | "src/", 37 | "test/" 38 | ], 39 | "exclude": [ 40 | "**/*/*.js", 41 | "**/*/npm/", 42 | "coverage/*.json" 43 | ] 44 | }, 45 | "tasks": { 46 | "test": "deno fmt && deno lint && deno task check && deno test --fail-fast --doc --coverage=coverage --parallel --allow-read", 47 | "test:cloudflare": "cd test/runtimes/cloudflare && npm install && npm link hpke-js && npm run test", 48 | "test:bun": "cd test/runtimes/bun && bun install && bun test", 49 | "check": "deno check *.ts src/**/*.ts samples/**/*.ts test/*.ts", 50 | "cov": "deno coverage ./coverage --lcov --exclude='test'", 51 | "npm-build": "deno run --import-map=../../npm/import_map.json -A dnt.ts --skip-test", 52 | "dnt": "deno run --import-map=../../npm/import_map.json -A dnt.ts", 53 | "sample:deno": "cd samples/deno && deno run main.ts", 54 | "sample:node": "cd samples/node && npm install && node app.js", 55 | "minify": "esbuild ../../npm/packages/hpke-js/esm/mod.js --bundle --format=esm --minify" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/core/dnt.ts: -------------------------------------------------------------------------------- 1 | import { build } from "@deno/dnt"; 2 | import { afterBuild, beforeBuild } from "../../utils/dntCommon.ts"; 3 | 4 | const denoPkg = JSON.parse(await Deno.readTextFile("./deno.jsonc")); 5 | 6 | await beforeBuild("core"); 7 | 8 | await build({ 9 | entryPoints: ["./mod.ts"], 10 | outDir: "../../npm/packages/core", 11 | typeCheck: "both", 12 | test: !Deno.args.includes("--skip-test"), 13 | declaration: "inline", 14 | scriptModule: "umd", 15 | importMap: "../../npm/import_map.json", 16 | compilerOptions: { 17 | lib: ["ES2022", "DOM"], 18 | }, 19 | shims: { 20 | deno: "dev", 21 | }, 22 | testPattern: "test/**/*.test.ts", 23 | package: { 24 | name: denoPkg.name, 25 | version: denoPkg.version, 26 | description: 27 | "A Hybrid Public Key Encryption (HPKE) core module for various JavaScript runtimes", 28 | repository: { 29 | type: "git", 30 | url: "git+https://github.com/dajiaji/hpke-js.git", 31 | }, 32 | homepage: "https://github.com/dajiaji/hpke-js/tree/main/core#readme", 33 | license: "MIT", 34 | module: "./esm/mod.js", 35 | main: "./script/mod.js", 36 | types: "./esm/mod.d.ts", 37 | sideEffects: false, 38 | exports: { 39 | ".": { 40 | "import": "./esm/mod.js", 41 | "require": "./script/mod.js", 42 | }, 43 | "./package.json": "./package.json", 44 | }, 45 | keywords: [ 46 | "hpke", 47 | "rfc9180", 48 | "hkdf", 49 | "dh", 50 | "security", 51 | "encryption", 52 | ], 53 | engines: { 54 | "node": ">=16.0.0", 55 | }, 56 | author: "Ajitomi Daisuke", 57 | bugs: { 58 | url: "https://github.com/dajiaji/hpke-js/issues", 59 | }, 60 | }, 61 | }); 62 | 63 | afterBuild("core"); 64 | -------------------------------------------------------------------------------- /packages/ml-kem/dnt.ts: -------------------------------------------------------------------------------- 1 | import { build } from "@deno/dnt"; 2 | import { afterBuild, beforeBuild } from "../../utils/dntCommon.ts"; 3 | 4 | const denoPkg = JSON.parse(await Deno.readTextFile("./deno.jsonc")); 5 | 6 | await beforeBuild("ml-kem"); 7 | 8 | await build({ 9 | entryPoints: ["./mod.ts"], 10 | outDir: "../../npm/packages/ml-kem", 11 | typeCheck: "both", 12 | test: !Deno.args.includes("--skip-test"), 13 | declaration: "inline", 14 | scriptModule: "umd", 15 | importMap: "../../npm/import_map.json", 16 | compilerOptions: { 17 | lib: ["ES2022", "DOM"], 18 | }, 19 | shims: { 20 | deno: "dev", 21 | }, 22 | testPattern: "test/**/*.test.ts", 23 | package: { 24 | name: denoPkg.name, 25 | version: denoPkg.version, 26 | description: 27 | "A Hybrid Public Key Encryption (HPKE) module extension for ML-KEM.", 28 | repository: { 29 | type: "git", 30 | url: "git+https://github.com/dajiaji/hpke-js.git", 31 | }, 32 | homepage: "https://github.com/dajiaji/hpke-js#readme", 33 | license: "MIT", 34 | module: "./esm/mod.js", 35 | main: "./script/mod.js", 36 | types: "./esm/mod.d.ts", 37 | sideEffects: false, 38 | exports: { 39 | ".": { 40 | "import": "./esm/mod.js", 41 | "require": "./script/mod.js", 42 | }, 43 | "./package.json": "./package.json", 44 | }, 45 | keywords: [ 46 | "hpke", 47 | "ml-kem", 48 | "kyber", 49 | "post-quantum", 50 | "pqc", 51 | "security", 52 | "encryption", 53 | ], 54 | engines: { 55 | "node": ">=16.0.0", 56 | }, 57 | author: "Ajitomi Daisuke", 58 | bugs: { 59 | url: "https://github.com/dajiaji/hpke-js/issues", 60 | }, 61 | }, 62 | }); 63 | 64 | afterBuild("ml-kem"); 65 | -------------------------------------------------------------------------------- /packages/dhkem-x448/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hpke/dhkem-x448", 3 | "version": "1.6.4", 4 | "exports": "./mod.ts", 5 | "publish": { 6 | "exclude": [ 7 | "dnt.ts", 8 | "samples/", 9 | "test/", 10 | "tsconfig.json" 11 | ] 12 | }, 13 | "fmt": { 14 | "include": [ 15 | "**/*.md", 16 | "**/*.json", 17 | "dnt.ts", 18 | "mod.ts", 19 | "samples/", 20 | "src/", 21 | "test/" 22 | ], 23 | "exclude": [ 24 | "**/*/*.js", 25 | "**/*/npm/", 26 | "coverage/*.json" 27 | ] 28 | }, 29 | "lint": { 30 | "include": [ 31 | "**/*.md", 32 | "**/*.json", 33 | "dnt.ts", 34 | "mod.ts", 35 | "samples/", 36 | "src/", 37 | "test/" 38 | ], 39 | "exclude": [ 40 | "**/*/*.js", 41 | "**/*/npm/", 42 | "coverage/*.json" 43 | ] 44 | }, 45 | "tasks": { 46 | "test": "deno fmt && deno lint && deno task check && deno test --fail-fast --doc --coverage=coverage --parallel --allow-read", 47 | "test:cloudflare": "cd test/runtimes/cloudflare && npm install && npm link @hpke/common @hpke/dhkem-x448 && npm run test", 48 | "test:bun": "cd test/runtimes/bun && bun install && bun test", 49 | "check": "deno check *.ts src/**/*.ts samples/**/*.ts test/*.ts", 50 | "cov": "deno coverage ./coverage --lcov --exclude='test'", 51 | "npm-build": "deno run --import-map=../../npm/import_map.json -A dnt.ts --skip-test", 52 | "dnt": "deno run --import-map=../../npm/import_map.json -A dnt.ts", 53 | "sample:deno": "cd samples/deno && deno run main.ts", 54 | "sample:node": "cd samples/node && npm install && node app.js", 55 | "minify": "esbuild ../../npm/packages/dhkem-x448/esm/mod.js --bundle --format=esm --minify" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hpke/dhkem-x25519", 3 | "version": "1.6.4", 4 | "exports": "./mod.ts", 5 | "publish": { 6 | "exclude": [ 7 | "dnt.ts", 8 | "samples/", 9 | "test/", 10 | "tsconfig.json" 11 | ] 12 | }, 13 | "fmt": { 14 | "include": [ 15 | "**/*.md", 16 | "**/*.json", 17 | "dnt.ts", 18 | "mod.ts", 19 | "samples/", 20 | "src/", 21 | "test/" 22 | ], 23 | "exclude": [ 24 | "**/*/*.js", 25 | "**/*/npm/", 26 | "coverage/*.json" 27 | ] 28 | }, 29 | "lint": { 30 | "include": [ 31 | "**/*.md", 32 | "**/*.json", 33 | "dnt.ts", 34 | "mod.ts", 35 | "samples/", 36 | "src/", 37 | "test/" 38 | ], 39 | "exclude": [ 40 | "**/*/*.js", 41 | "**/*/npm/", 42 | "coverage/*.json" 43 | ] 44 | }, 45 | "tasks": { 46 | "test": "deno fmt && deno lint && deno task check && deno test --fail-fast --doc --coverage=coverage --parallel --allow-read", 47 | "test:cloudflare": "cd test/runtimes/cloudflare && npm install && npm link @hpke/common @hpke/dhkem-x25519 && npm run test", 48 | "test:bun": "cd test/runtimes/bun && bun install && bun test", 49 | "check": "deno check *.ts src/**/*.ts samples/**/*.ts test/*.ts", 50 | "cov": "deno coverage ./coverage --lcov --exclude='test'", 51 | "npm-build": "deno run --import-map=../../npm/import_map.json -A dnt.ts --skip-test", 52 | "dnt": "deno run --import-map=../../npm/import_map.json -A dnt.ts", 53 | "sample:deno": "cd samples/deno && deno run main.ts", 54 | "sample:node": "cd samples/node && npm install && node app.js", 55 | "minify": "esbuild ../../npm/packages/dhkem-x25519/esm/mod.js --bundle --format=esm --minify" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/dhkem-x448/dnt.ts: -------------------------------------------------------------------------------- 1 | import { build } from "@deno/dnt"; 2 | import { afterBuild, beforeBuild } from "../../utils/dntCommon.ts"; 3 | 4 | const denoPkg = JSON.parse(await Deno.readTextFile("./deno.jsonc")); 5 | 6 | await beforeBuild("dhkem-x448"); 7 | 8 | await build({ 9 | entryPoints: ["./mod.ts"], 10 | outDir: "../../npm/packages/dhkem-x448", 11 | typeCheck: "both", 12 | test: !Deno.args.includes("--skip-test"), 13 | declaration: "inline", 14 | scriptModule: "umd", 15 | importMap: "../../npm/import_map.json", 16 | compilerOptions: { 17 | lib: ["ES2022", "DOM"], 18 | }, 19 | shims: { 20 | deno: "dev", 21 | }, 22 | testPattern: "test/**/*.test.ts", 23 | package: { 24 | name: denoPkg.name, 25 | version: denoPkg.version, 26 | description: 27 | "A Hybrid Public Key Encryption (HPKE) module extension for X448", 28 | repository: { 29 | type: "git", 30 | url: "git+https://github.com/dajiaji/hpke-js.git", 31 | }, 32 | homepage: "https://github.com/dajiaji/hpke-js#readme", 33 | license: "MIT", 34 | module: "./esm/mod.js", 35 | main: "./script/mod.js", 36 | types: "./esm/mod.d.ts", 37 | sideEffects: false, 38 | exports: { 39 | ".": { 40 | "import": "./esm/mod.js", 41 | "require": "./script/mod.js", 42 | }, 43 | "./package.json": "./package.json", 44 | }, 45 | keywords: [ 46 | "hpke", 47 | "rfc9180", 48 | "kem", 49 | "hkdf", 50 | "dh", 51 | "x448", 52 | "security", 53 | "encryption", 54 | ], 55 | engines: { 56 | "node": ">=16.0.0", 57 | }, 58 | author: "Ajitomi Daisuke", 59 | bugs: { 60 | url: "https://github.com/dajiaji/hpke-js/issues", 61 | }, 62 | }, 63 | }); 64 | 65 | afterBuild("dhkem-x448"); 66 | -------------------------------------------------------------------------------- /packages/dhkem-x25519/dnt.ts: -------------------------------------------------------------------------------- 1 | import { build } from "@deno/dnt"; 2 | import { afterBuild, beforeBuild } from "../../utils/dntCommon.ts"; 3 | 4 | const denoPkg = JSON.parse(await Deno.readTextFile("./deno.jsonc")); 5 | 6 | await beforeBuild("dhkem-x25519"); 7 | 8 | await build({ 9 | entryPoints: ["./mod.ts"], 10 | outDir: "../../npm/packages/dhkem-x25519", 11 | typeCheck: "both", 12 | test: !Deno.args.includes("--skip-test"), 13 | declaration: "inline", 14 | scriptModule: "umd", 15 | importMap: "../../npm/import_map.json", 16 | compilerOptions: { 17 | lib: ["ES2022", "DOM"], 18 | }, 19 | shims: { 20 | deno: "dev", 21 | }, 22 | testPattern: "test/**/*.test.ts", 23 | package: { 24 | name: denoPkg.name, 25 | version: denoPkg.version, 26 | description: 27 | "A Hybrid Public Key Encryption (HPKE) module extension for X25519", 28 | repository: { 29 | type: "git", 30 | url: "git+https://github.com/dajiaji/hpke-js.git", 31 | }, 32 | homepage: "https://github.com/dajiaji/hpke-js#readme", 33 | license: "MIT", 34 | module: "./esm/mod.js", 35 | main: "./script/mod.js", 36 | types: "./esm/mod.d.ts", 37 | sideEffects: false, 38 | exports: { 39 | ".": { 40 | "import": "./esm/mod.js", 41 | "require": "./script/mod.js", 42 | }, 43 | "./package.json": "./package.json", 44 | }, 45 | keywords: [ 46 | "hpke", 47 | "rfc9180", 48 | "kem", 49 | "hkdf", 50 | "dh", 51 | "x25519", 52 | "security", 53 | "encryption", 54 | ], 55 | engines: { 56 | "node": ">=16.0.0", 57 | }, 58 | author: "Ajitomi Daisuke", 59 | bugs: { 60 | url: "https://github.com/dajiaji/hpke-js/issues", 61 | }, 62 | }, 63 | }); 64 | 65 | afterBuild("dhkem-x25519"); 66 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/dnt.ts: -------------------------------------------------------------------------------- 1 | import { build } from "@deno/dnt"; 2 | import { afterBuild, beforeBuild } from "../../utils/dntCommon.ts"; 3 | 4 | const denoPkg = JSON.parse(await Deno.readTextFile("./deno.jsonc")); 5 | 6 | await beforeBuild("dhkem-secp256k1"); 7 | 8 | await build({ 9 | entryPoints: ["./mod.ts"], 10 | outDir: "../../npm/packages/dhkem-secp256k1", 11 | typeCheck: "both", 12 | test: !Deno.args.includes("--skip-test"), 13 | declaration: "inline", 14 | scriptModule: "umd", 15 | importMap: "../../npm/import_map.json", 16 | compilerOptions: { 17 | lib: ["ES2022", "DOM"], 18 | }, 19 | shims: { 20 | deno: "dev", 21 | }, 22 | testPattern: "test/**/*.test.ts", 23 | package: { 24 | name: denoPkg.name, 25 | version: denoPkg.version, 26 | description: 27 | "A Hybrid Public Key Encryption (HPKE) module extension for secp256k1 curve (EXPERIMENTAL)", 28 | repository: { 29 | type: "git", 30 | url: "git+https://github.com/dajiaji/hpke-js.git", 31 | }, 32 | homepage: "https://github.com/dajiaji/hpke-js#readme", 33 | license: "MIT", 34 | module: "./esm/mod.js", 35 | main: "./script/mod.js", 36 | types: "./esm/mod.d.ts", 37 | sideEffects: false, 38 | exports: { 39 | ".": { 40 | "import": "./esm/mod.js", 41 | "require": "./script/mod.js", 42 | }, 43 | "./package.json": "./package.json", 44 | }, 45 | keywords: [ 46 | "hpke", 47 | "rfc9180", 48 | "kem", 49 | "hkdf", 50 | "dh", 51 | "secp256k1", 52 | "security", 53 | "encryption", 54 | ], 55 | engines: { 56 | "node": ">=16.0.0", 57 | }, 58 | author: "Ajitomi Daisuke", 59 | bugs: { 60 | url: "https://github.com/dajiaji/hpke-js/issues", 61 | }, 62 | }, 63 | }); 64 | 65 | afterBuild("dhkem-secp256k1"); 66 | -------------------------------------------------------------------------------- /packages/ml-kem/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hpke/ml-kem", 3 | "version": "0.2.1", 4 | "exports": "./mod.ts", 5 | "imports": { 6 | "@dajiaji/mlkem": "jsr:@dajiaji/mlkem@^2.5.0" 7 | }, 8 | "publish": { 9 | "exclude": [ 10 | "dnt.ts", 11 | "samples/", 12 | "test/", 13 | "tsconfig.json" 14 | ] 15 | }, 16 | "fmt": { 17 | "include": [ 18 | "**/*.md", 19 | "**/*.json", 20 | "dnt.ts", 21 | "mod.ts", 22 | "samples/", 23 | "src/", 24 | "test/" 25 | ], 26 | "exclude": [ 27 | "**/*/*.js", 28 | "**/*/npm/", 29 | "coverage/*.json" 30 | ] 31 | }, 32 | "lint": { 33 | "include": [ 34 | "**/*.md", 35 | "**/*.json", 36 | "dnt.ts", 37 | "mod.ts", 38 | "samples/", 39 | "src/", 40 | "test/" 41 | ], 42 | "exclude": [ 43 | "**/*/*.js", 44 | "**/*/npm/", 45 | "coverage/*.json" 46 | ] 47 | }, 48 | "tasks": { 49 | "test": "deno fmt && deno lint && deno task check && deno test --fail-fast --doc --coverage=coverage --cached-only --parallel --allow-read", 50 | "test:cloudflare": "cd test/runtimes/cloudflare && npm install && npm link @hpke/common @hpke/ml-kem && npm run test", 51 | "test:bun": "cd test/runtimes/bun && bun install && bun test", 52 | "check": "deno check *.ts src/**/*.ts samples/**/*.ts test/*.ts", 53 | "cov": "deno coverage ./coverage --lcov --exclude='test'", 54 | "npm-build": "deno run --import-map=../../npm/import_map.json -A dnt.ts --skip-test", 55 | "dnt": "deno run --import-map=../../npm/import_map.json -A dnt.ts", 56 | "sample:deno": "cd samples/deno && deno run main.ts", 57 | "sample:node": "cd samples/node && npm install && node app.js", 58 | "minify": "esbuild ../../npm/packages/ml-kem/esm/mod.js --bundle --format=esm --minify" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /packages/core/test/runtimes/browsers/core.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "@playwright/test"; 2 | 3 | test("standard curves test with generateKeyPair", async ({ page }) => { 4 | await page.goto("./index.html"); 5 | await page.click("text=run"); 6 | await page.waitForTimeout(5000); 7 | await expect(page.locator("id=pass")).toHaveText("18"); 8 | await expect(page.locator("id=fail")).toHaveText("0"); 9 | }); 10 | 11 | test("standard curves test with deriveKeyPair", async ({ browserName, page }) => { 12 | await page.goto("./standardCurvesWithDeriveKeyPair.html"); 13 | await page.click("text=run"); 14 | await page.waitForTimeout(5000); 15 | if (browserName === "firefox") { 16 | await expect(page.locator("id=pass")).toHaveText("0"); 17 | await expect(page.locator("id=fail")).toHaveText("18"); 18 | } else { 19 | await expect(page.locator("id=pass")).toHaveText("18"); 20 | await expect(page.locator("id=fail")).toHaveText("0"); 21 | } 22 | }); 23 | 24 | test("secure curves test with generateKeyPair", async ({ page }) => { 25 | await page.goto("./secureCurves.html"); 26 | await page.click("text=run"); 27 | await page.waitForTimeout(5000); 28 | await expect(page.locator("id=pass")).toHaveText("6"); 29 | await expect(page.locator("id=fail")).toHaveText("0"); 30 | }); 31 | 32 | test("secure curves test with deriveKeyPair", async ({ browserName, page }) => { 33 | await page.goto("./secureCurvesWithDeriveKeyPair.html"); 34 | await page.click("text=run"); 35 | await page.waitForTimeout(5000); 36 | if (browserName === "chromium" || browserName === "webkit") { 37 | await expect(page.locator("id=pass")).toHaveText("6"); 38 | await expect(page.locator("id=fail")).toHaveText("0"); 39 | } else { 40 | await expect(page.locator("id=pass")).toHaveText("0"); 41 | await expect(page.locator("id=fail")).toHaveText("6"); 42 | } 43 | }); 44 | -------------------------------------------------------------------------------- /packages/chacha20poly1305/dnt.ts: -------------------------------------------------------------------------------- 1 | import { build } from "@deno/dnt"; 2 | import { afterBuild, beforeBuild } from "../../utils/dntCommon.ts"; 3 | 4 | const denoPkg = JSON.parse(await Deno.readTextFile("./deno.jsonc")); 5 | 6 | await beforeBuild("chacha20poly1305"); 7 | 8 | await build({ 9 | entryPoints: ["./mod.ts"], 10 | outDir: "../../npm/packages/chacha20poly1305", 11 | typeCheck: "both", 12 | test: !Deno.args.includes("--skip-test"), 13 | declaration: "inline", 14 | scriptModule: "umd", 15 | importMap: "../../npm/import_map.json", 16 | compilerOptions: { 17 | lib: ["ES2022", "DOM"], 18 | }, 19 | shims: { 20 | deno: "dev", 21 | }, 22 | testPattern: "test/**/*.test.ts", 23 | package: { 24 | name: denoPkg.name, 25 | version: denoPkg.version, 26 | description: 27 | "A Hybrid Public Key Encryption (HPKE) module extension for ChaCha20/Poly1305", 28 | repository: { 29 | type: "git", 30 | url: "git+https://github.com/dajiaji/hpke-js.git", 31 | }, 32 | homepage: 33 | "https://github.com/dajiaji/hpke-js/tree/main/packages/chacha20poly1305#readme", 34 | license: "MIT", 35 | module: "./esm/mod.js", 36 | main: "./script/mod.js", 37 | types: "./esm/mod.d.ts", 38 | sideEffects: false, 39 | exports: { 40 | ".": { 41 | "import": "./esm/mod.js", 42 | "require": "./script/mod.js", 43 | }, 44 | "./package.json": "./package.json", 45 | }, 46 | keywords: [ 47 | "hpke", 48 | "rfc9180", 49 | "aead", 50 | "chacha20", 51 | "poly1305", 52 | "security", 53 | "encryption", 54 | ], 55 | engines: { 56 | "node": ">=16.0.0", 57 | }, 58 | author: "Ajitomi Daisuke", 59 | bugs: { 60 | url: "https://github.com/dajiaji/hpke-js/issues", 61 | }, 62 | }, 63 | }); 64 | 65 | afterBuild("chacha20poly1305"); 66 | -------------------------------------------------------------------------------- /packages/dhkem-secp256k1/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hpke/dhkem-secp256k1", 3 | "version": "1.6.4", 4 | "exports": "./mod.ts", 5 | "imports": { 6 | "@noble/curves": "npm:@noble/curves@^1.9.6" 7 | }, 8 | "publish": { 9 | "exclude": [ 10 | "dnt.ts", 11 | "samples/", 12 | "test/", 13 | "tsconfig.json" 14 | ] 15 | }, 16 | "fmt": { 17 | "include": [ 18 | "**/*.md", 19 | "**/*.json", 20 | "dnt.ts", 21 | "mod.ts", 22 | "samples/", 23 | "src/", 24 | "test/" 25 | ], 26 | "exclude": [ 27 | "**/*/*.js", 28 | "**/*/npm/", 29 | "coverage/*.json" 30 | ] 31 | }, 32 | "lint": { 33 | "include": [ 34 | "**/*.md", 35 | "**/*.json", 36 | "dnt.ts", 37 | "mod.ts", 38 | "samples/", 39 | "src/", 40 | "test/" 41 | ], 42 | "exclude": [ 43 | "**/*/*.js", 44 | "**/*/npm/", 45 | "coverage/*.json" 46 | ] 47 | }, 48 | "tasks": { 49 | "test": "deno fmt && deno lint && deno task check && deno test --fail-fast --doc --coverage=coverage --parallel --allow-read", 50 | "test:cloudflare": "cd test/runtimes/cloudflare && npm install && npm link @hpke/common @hpke/dhkem-secp256k1 && npm run test", 51 | "test:bun": "cd test/runtimes/bun && bun install && bun test", 52 | "check": "deno check *.ts src/**/*.ts samples/**/*.ts test/*.ts", 53 | "cov": "deno coverage ./coverage --lcov --exclude='test'", 54 | "npm-build": "deno run --import-map=../../npm/import_map.json -A dnt.ts --skip-test", 55 | "dnt": "deno run --import-map=../../npm/import_map.json -A dnt.ts", 56 | "sample:deno": "cd samples/deno && deno run main.ts", 57 | "sample:node": "cd samples/node && npm install && node app.js", 58 | "minify": "esbuild ../../npm/packages/dhkem-secp256k1/esm/mod.js --bundle --format=esm --minify" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /packages/common/dnt.ts: -------------------------------------------------------------------------------- 1 | import { build, emptyDir } from "@deno/dnt"; 2 | 3 | await emptyDir("../../npm/packages/common"); 4 | 5 | const denoPkg = JSON.parse(await Deno.readTextFile("./deno.jsonc")); 6 | 7 | await build({ 8 | entryPoints: ["./mod.ts"], 9 | outDir: "../../npm/packages/common", 10 | typeCheck: "both", 11 | test: !Deno.args.includes("--skip-test"), 12 | declaration: "inline", 13 | scriptModule: "umd", 14 | importMap: "../../npm/import_map.json", 15 | compilerOptions: { 16 | lib: ["ES2022", "DOM"], 17 | }, 18 | shims: { 19 | deno: "dev", 20 | }, 21 | testPattern: "test/**/*.test.ts", 22 | package: { 23 | name: denoPkg.name, 24 | version: denoPkg.version, 25 | description: 26 | "A Hybrid Public Key Encryption (HPKE) internal-use common module for @hpke family modules.", 27 | repository: { 28 | type: "git", 29 | url: "git+https://github.com/dajiaji/hpke-js.git", 30 | }, 31 | homepage: "https://github.com/dajiaji/hpke-js/tree/main/common#readme", 32 | license: "MIT", 33 | module: "./esm/mod.js", 34 | main: "./script/mod.js", 35 | types: "./esm/mod.d.ts", 36 | sideEffects: false, 37 | exports: { 38 | ".": { 39 | "import": "./esm/mod.js", 40 | "require": "./script/mod.js", 41 | }, 42 | "./package.json": "./package.json", 43 | }, 44 | keywords: [ 45 | "hpke", 46 | "rfc9180", 47 | "hkdf", 48 | "dh", 49 | "security", 50 | "encryption", 51 | ], 52 | engines: { 53 | "node": ">=16.0.0", 54 | }, 55 | author: "Ajitomi Daisuke", 56 | bugs: { 57 | url: "https://github.com/dajiaji/hpke-js/issues", 58 | }, 59 | }, 60 | }); 61 | 62 | // post build steps 63 | Deno.copyFileSync("LICENSE", "../../npm/packages/common/LICENSE"); 64 | Deno.copyFileSync("README.md", "../../npm/packages/common/README.md"); 65 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hpke/hybridkem-x-wing", 3 | "version": "0.6.1", 4 | "exports": "./mod.ts", 5 | "imports": { 6 | "@dajiaji/mlkem": "jsr:@dajiaji/mlkem@^2.5.0" 7 | }, 8 | "publish": { 9 | "exclude": [ 10 | "dnt.ts", 11 | "samples/", 12 | "test/", 13 | "tsconfig.json" 14 | ] 15 | }, 16 | "fmt": { 17 | "include": [ 18 | "**/*.md", 19 | "**/*.json", 20 | "dnt.ts", 21 | "mod.ts", 22 | "samples/", 23 | "src/", 24 | "test/" 25 | ], 26 | "exclude": [ 27 | "**/*/*.js", 28 | "**/*/npm/", 29 | "coverage/*.json" 30 | ] 31 | }, 32 | "lint": { 33 | "include": [ 34 | "**/*.md", 35 | "**/*.json", 36 | "dnt.ts", 37 | "mod.ts", 38 | "samples/", 39 | "src/", 40 | "test/" 41 | ], 42 | "exclude": [ 43 | "**/*/*.js", 44 | "**/*/npm/", 45 | "coverage/*.json" 46 | ] 47 | }, 48 | "tasks": { 49 | "test": "deno fmt && deno lint && deno task check && deno test --fail-fast --doc --coverage=coverage --parallel --allow-read", 50 | "test:cloudflare": "cd test/runtimes/cloudflare && npm install && npm link @hpke/common @hpke/hybridkem-x-wing && npm run test", 51 | "test:bun": "cd test/runtimes/bun && bun install && bun test", 52 | "check": "deno check *.ts src/**/*.ts samples/**/*.ts test/*.ts", 53 | "cov": "deno coverage ./coverage --lcov --exclude='test'", 54 | "npm-build": "deno run --import-map=../../npm/import_map.json -A dnt.ts --skip-test", 55 | "dnt": "deno run --import-map=../../npm/import_map.json -A dnt.ts", 56 | "sample:deno": "cd samples/deno && deno run main.ts", 57 | "sample:node": "cd samples/node && npm install && node app.js", 58 | "minify": "esbuild ../../npm/packages/hybridkem-x-wing/esm/mod.js --bundle --format=esm --minify" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /packages/common/src/identifiers.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The supported HPKE modes. 3 | */ 4 | export const Mode = { 5 | Base: 0x00, 6 | Psk: 0x01, 7 | Auth: 0x02, 8 | AuthPsk: 0x03, 9 | } as const; 10 | 11 | /** 12 | * The type alias of the supported HPKE modes. 13 | */ 14 | export type Mode = typeof Mode[keyof typeof Mode]; 15 | 16 | /** 17 | * The supported Key Encapsulation Mechanism (KEM) identifiers. 18 | */ 19 | export const KemId = { 20 | NotAssigned: 0x0000, 21 | DhkemP256HkdfSha256: 0x0010, 22 | DhkemP384HkdfSha384: 0x0011, 23 | DhkemP521HkdfSha512: 0x0012, 24 | DhkemSecp256k1HkdfSha256: 0x0013, 25 | DhkemX25519HkdfSha256: 0x0020, 26 | DhkemX448HkdfSha512: 0x0021, 27 | HybridkemX25519Kyber768: 0x0030, 28 | MlKem512: 0x0040, 29 | MlKem768: 0x0041, 30 | MlKem1024: 0x0042, 31 | XWing: 0x647a, 32 | } as const; 33 | 34 | /** 35 | * The type alias of the supported KEM identifiers. 36 | */ 37 | export type KemId = typeof KemId[keyof typeof KemId]; 38 | 39 | /** 40 | * The supported Key Derivation Function (KDF) identifiers. 41 | */ 42 | export const KdfId = { 43 | HkdfSha256: 0x0001, 44 | HkdfSha384: 0x0002, 45 | HkdfSha512: 0x0003, 46 | Sha3256: 0x0004, 47 | Sha3384: 0x0005, 48 | Sha3512: 0x0006, 49 | Shake128: 0x0010, 50 | Shake256: 0x0011, 51 | TurboShake128: 0x0012, 52 | TurboShake256: 0x0013, 53 | } as const; 54 | 55 | /** 56 | * The type alias of the supported KDF identifiers. 57 | */ 58 | export type KdfId = typeof KdfId[keyof typeof KdfId]; 59 | 60 | /** 61 | * The supported Authenticated Encryption with Associated Data (AEAD) identifiers. 62 | */ 63 | export const AeadId = { 64 | Aes128Gcm: 0x0001, 65 | Aes256Gcm: 0x0002, 66 | Chacha20Poly1305: 0x0003, 67 | ExportOnly: 0xFFFF, 68 | } as const; 69 | 70 | /** 71 | * The type alias of the supported AEAD identifiers. 72 | */ 73 | export type AeadId = typeof AeadId[keyof typeof AeadId]; 74 | -------------------------------------------------------------------------------- /packages/hpke-js/dnt.ts: -------------------------------------------------------------------------------- 1 | import { build } from "@deno/dnt"; 2 | import { afterBuild, beforeBuild } from "../../utils/dntCommon.ts"; 3 | 4 | const denoPkg = JSON.parse(await Deno.readTextFile("./deno.jsonc")); 5 | 6 | await beforeBuild("hpke-js"); 7 | 8 | await build({ 9 | entryPoints: ["./mod.ts"], 10 | outDir: "../../npm/packages/hpke-js", 11 | typeCheck: "both", 12 | test: !Deno.args.includes("--skip-test"), 13 | declaration: "inline", 14 | scriptModule: "umd", 15 | importMap: "../../npm/import_map.json", 16 | compilerOptions: { 17 | lib: ["ES2022", "DOM"], 18 | }, 19 | shims: { 20 | deno: "dev", 21 | }, 22 | testPattern: "test/**/*.test.ts", 23 | package: { 24 | name: "hpke-js", 25 | version: denoPkg.version, 26 | description: 27 | "A Hybrid Public Key Encryption (HPKE) module for various JavaScript runtimes", 28 | repository: { 29 | type: "git", 30 | url: "git+https://github.com/dajiaji/hpke-js.git", 31 | }, 32 | homepage: "https://github.com/dajiaji/hpke-js#readme", 33 | license: "MIT", 34 | module: "./esm/mod.js", 35 | main: "./script/mod.js", 36 | types: "./esm/mod.d.ts", 37 | sideEffects: false, 38 | exports: { 39 | ".": { 40 | "import": "./esm/mod.js", 41 | "require": "./script/mod.js", 42 | }, 43 | "./package.json": "./package.json", 44 | }, 45 | keywords: [ 46 | "hpke", 47 | "public-key-encryption", 48 | "rfc9180", 49 | "e2ee", 50 | "kem", 51 | "kdf", 52 | "kyber", 53 | "aead", 54 | "post-quantum", 55 | "pqc", 56 | "security", 57 | "encryption", 58 | ], 59 | engines: { 60 | "node": ">=16.0.0", 61 | }, 62 | author: "Ajitomi Daisuke", 63 | bugs: { 64 | url: "https://github.com/dajiaji/hpke-js/issues", 65 | }, 66 | }, 67 | }); 68 | 69 | afterBuild("hpke-js"); 70 | -------------------------------------------------------------------------------- /packages/hybridkem-x-wing/dnt.ts: -------------------------------------------------------------------------------- 1 | import { build } from "@deno/dnt"; 2 | import { afterBuild, beforeBuild } from "../../utils/dntCommon.ts"; 3 | 4 | const denoPkg = JSON.parse(await Deno.readTextFile("./deno.jsonc")); 5 | 6 | await beforeBuild("hybridkem-x-wing"); 7 | 8 | await build({ 9 | entryPoints: ["./mod.ts"], 10 | outDir: "../../npm/packages/hybridkem-x-wing", 11 | typeCheck: "both", 12 | test: !Deno.args.includes("--skip-test"), 13 | declaration: "inline", 14 | scriptModule: "umd", 15 | importMap: "../../npm/import_map.json", 16 | compilerOptions: { 17 | lib: ["ES2022", "DOM"], 18 | }, 19 | shims: { 20 | deno: "dev", 21 | }, 22 | testPattern: "test/**/*.test.ts", 23 | package: { 24 | name: denoPkg.name, 25 | version: denoPkg.version, 26 | description: 27 | "A Hybrid Public Key Encryption (HPKE) module extension for X-Wing: general-purpose hybrid post-quantum KEM.", 28 | repository: { 29 | type: "git", 30 | url: "git+https://github.com/dajiaji/hpke-js.git", 31 | }, 32 | homepage: "https://github.com/dajiaji/hpke-js#readme", 33 | license: "MIT", 34 | module: "./esm/mod.js", 35 | main: "./script/mod.js", 36 | types: "./esm/mod.d.ts", 37 | sideEffects: false, 38 | exports: { 39 | ".": { 40 | "import": "./esm/mod.js", 41 | "require": "./script/mod.js", 42 | }, 43 | "./package.json": "./package.json", 44 | }, 45 | keywords: [ 46 | "hpke", 47 | "ml-kem", 48 | "kyber", 49 | "x25519", 50 | "post-quantum", 51 | "pqc", 52 | "x-wing", 53 | "security", 54 | "encryption", 55 | ], 56 | engines: { 57 | "node": ">=16.0.0", 58 | }, 59 | author: "Ajitomi Daisuke", 60 | bugs: { 61 | url: "https://github.com/dajiaji/hpke-js/issues", 62 | }, 63 | }, 64 | }); 65 | 66 | afterBuild("hybridkem-x-wing"); 67 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/dnt.ts: -------------------------------------------------------------------------------- 1 | import { build } from "@deno/dnt"; 2 | import { afterBuild, beforeBuild } from "../../utils/dntCommon.ts"; 3 | 4 | const denoPkg = JSON.parse(await Deno.readTextFile("./deno.jsonc")); 5 | 6 | await beforeBuild("hybridkem-x25519-kyber768"); 7 | 8 | await build({ 9 | entryPoints: ["./mod.ts"], 10 | outDir: "../../npm/packages/hybridkem-x25519-kyber768", 11 | typeCheck: "both", 12 | test: !Deno.args.includes("--skip-test"), 13 | declaration: "inline", 14 | scriptModule: "umd", 15 | importMap: "../../npm/import_map.json", 16 | compilerOptions: { 17 | lib: ["ES2022", "DOM"], 18 | }, 19 | shims: { 20 | deno: "dev", 21 | }, 22 | testPattern: "test/**/*.test.ts", 23 | package: { 24 | name: denoPkg.name, 25 | version: denoPkg.version, 26 | description: 27 | "A Hybrid Public Key Encryption (HPKE) module extension for a hybrid post-quantum KEM, X25519Kyber768Draft00", 28 | repository: { 29 | type: "git", 30 | url: "git+https://github.com/dajiaji/hpke-js.git", 31 | }, 32 | homepage: "https://github.com/dajiaji/hpke-js#readme", 33 | license: "MIT", 34 | module: "./esm/mod.js", 35 | main: "./script/mod.js", 36 | types: "./esm/mod.d.ts", 37 | sideEffects: false, 38 | exports: { 39 | ".": { 40 | "import": "./esm/mod.js", 41 | "require": "./script/mod.js", 42 | }, 43 | "./package.json": "./package.json", 44 | }, 45 | keywords: [ 46 | "hpke", 47 | "rfc9180", 48 | "kem", 49 | "kyber", 50 | "x25519", 51 | "post-quantum", 52 | "security", 53 | "encryption", 54 | ], 55 | engines: { 56 | "node": ">=16.0.0", 57 | }, 58 | author: "Ajitomi Daisuke", 59 | bugs: { 60 | url: "https://github.com/dajiaji/hpke-js/issues", 61 | }, 62 | }, 63 | }); 64 | 65 | afterBuild("hybridkem-x25519-kyber768"); 66 | -------------------------------------------------------------------------------- /packages/hybridkem-x25519-kyber768/deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hpke/hybridkem-x25519-kyber768", 3 | "version": "1.6.1", 4 | "exports": "./mod.ts", 5 | "imports": { 6 | "@noble/hashes": "npm:@noble/hashes@^1.8.0" 7 | }, 8 | "publish": { 9 | "exclude": [ 10 | "dnt.ts", 11 | "samples/", 12 | "test/", 13 | "tsconfig.json" 14 | ] 15 | }, 16 | "fmt": { 17 | "include": [ 18 | "**/*.md", 19 | "**/*.json", 20 | "dnt.ts", 21 | "mod.ts", 22 | "samples/", 23 | "src/", 24 | "test/" 25 | ], 26 | "exclude": [ 27 | "**/*/*.js", 28 | "**/*/npm/", 29 | "coverage/*.json" 30 | ] 31 | }, 32 | "lint": { 33 | "include": [ 34 | "**/*.md", 35 | "**/*.json", 36 | "dnt.ts", 37 | "mod.ts", 38 | "samples/", 39 | "src/", 40 | "test/" 41 | ], 42 | "exclude": [ 43 | "**/*/*.js", 44 | "**/*/npm/", 45 | "coverage/*.json" 46 | ] 47 | }, 48 | "tasks": { 49 | "test": "deno fmt && deno lint && deno task check && deno test --fail-fast --doc --coverage=coverage --parallel --allow-read", 50 | "test:cloudflare": "cd test/runtimes/cloudflare && npm install && npm link @hpke/common @hpke/hybridkem-x25519-kyber768 && npm run test", 51 | "test:bun": "cd test/runtimes/bun && bun install && bun test", 52 | "check": "deno check *.ts src/**/*.ts samples/**/*.ts test/*.ts", 53 | "cov": "deno coverage ./coverage --lcov --exclude='test'", 54 | "npm-build": "deno run --import-map=../../npm/import_map.json -A dnt.ts --skip-test", 55 | "dnt": "deno run --import-map=../../npm/import_map.json -A dnt.ts", 56 | "sample:deno": "cd samples/deno && deno run main.ts", 57 | "sample:node": "cd samples/node && npm install && node app.js", 58 | "minify": "esbuild ../../npm/packages/hybridkem-x25519-kyber768/esm/mod.js --bundle --format=esm --minify" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /packages/common/test/misc.test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals, assertThrows } from "@std/assert"; 2 | import { describe, it } from "@std/testing/bdd"; 3 | 4 | import { i2Osp, xor } from "../src/utils/misc.ts"; 5 | 6 | describe("i2Osp", () => { 7 | describe("with valid params (5, 1)", () => { 8 | it("return correct result", () => { 9 | assertEquals(i2Osp(5, 1), new Uint8Array([5])); 10 | }); 11 | }); 12 | 13 | describe("with valid params (5, 2)", () => { 14 | it("return correct result", () => { 15 | assertEquals(i2Osp(5, 2), new Uint8Array([0, 5])); 16 | }); 17 | }); 18 | 19 | describe("with valid params (5, 3)", () => { 20 | it("return correct result", () => { 21 | assertEquals(i2Osp(5, 3), new Uint8Array([0, 0, 5])); 22 | }); 23 | }); 24 | 25 | describe("with invalid n", () => { 26 | it("should throw Error", () => { 27 | assertThrows(() => i2Osp(256, 1), Error, "i2Osp: too large integer"); 28 | }); 29 | }); 30 | 31 | describe("with invalid w (0)", () => { 32 | it("should throw Error", () => { 33 | assertThrows(() => i2Osp(255, 0), Error, "i2Osp: too small size"); 34 | }); 35 | }); 36 | 37 | describe("with invalid w (negative value)", () => { 38 | it("should throw Error", () => { 39 | assertThrows(() => i2Osp(255, -1), Error, "i2Osp: too small size"); 40 | }); 41 | }); 42 | }); 43 | 44 | describe("xor", () => { 45 | describe("with valid params", () => { 46 | it("return correct result", () => { 47 | const a = new Uint8Array([0, 1, 1]); 48 | const b = new Uint8Array([1, 1, 0]); 49 | assertEquals(xor(a, b), new Uint8Array([1, 0, 1])); 50 | }); 51 | }); 52 | 53 | describe("with different length inputs", () => { 54 | it("should throw Error", () => { 55 | const a = new Uint8Array([0, 1, 1]); 56 | const b = new Uint8Array([1, 1]); 57 | assertThrows(() => xor(a, b), Error, "xor: different length inputs"); 58 | }); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /packages/core/src/encryptionContext.ts: -------------------------------------------------------------------------------- 1 | import type { AeadInterface, KdfInterface } from "@hpke/common"; 2 | import { i2Osp, MessageLimitReachedError, xor } from "@hpke/common"; 3 | 4 | import type { AeadParams } from "./interfaces/aeadParams.ts"; 5 | import type { KeyInfo } from "./interfaces/keyInfo.ts"; 6 | 7 | import { ExporterContextImpl } from "./exporterContext.ts"; 8 | 9 | export class EncryptionContextImpl extends ExporterContextImpl { 10 | // AEAD id. 11 | protected _aead: AeadInterface; 12 | // The length in bytes of a key for the algorithm. 13 | protected _nK: number; 14 | // The length in bytes of a nonce for the algorithm. 15 | protected _nN: number; 16 | // The length in bytes of an authentication tag for the algorithm. 17 | protected _nT: number; 18 | // The end-to-end encryption key information. 19 | protected _ctx: KeyInfo; 20 | 21 | constructor(api: SubtleCrypto, kdf: KdfInterface, params: AeadParams) { 22 | super(api, kdf, params.exporterSecret); 23 | 24 | if ( 25 | params.key === undefined || params.baseNonce === undefined || 26 | params.seq === undefined 27 | ) { 28 | throw new Error("Required parameters are missing"); 29 | } 30 | this._aead = params.aead; 31 | this._nK = this._aead.keySize; 32 | this._nN = this._aead.nonceSize; 33 | this._nT = this._aead.tagSize; 34 | 35 | const key = this._aead.createEncryptionContext(params.key); 36 | this._ctx = { 37 | key: key, 38 | baseNonce: params.baseNonce, 39 | seq: params.seq, 40 | }; 41 | } 42 | 43 | protected computeNonce(k: KeyInfo): ArrayBuffer { 44 | const seqBytes = i2Osp(k.seq, k.baseNonce.byteLength); 45 | return xor(k.baseNonce, seqBytes).buffer as ArrayBuffer; 46 | } 47 | 48 | protected incrementSeq(k: KeyInfo) { 49 | // if (this.seq >= (1 << (8 * this.baseNonce.byteLength)) - 1) { 50 | if (k.seq > Number.MAX_SAFE_INTEGER) { 51 | throw new MessageLimitReachedError("Message limit reached"); 52 | } 53 | k.seq += 1; 54 | return; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/common/src/errors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The base error class of hpke-js. 3 | * @group Errors 4 | */ 5 | export class HpkeError extends Error { 6 | public constructor(e: unknown) { 7 | let message: string; 8 | 9 | if (e instanceof Error) { 10 | message = e.message; 11 | } else if (typeof e === "string") { 12 | message = e; 13 | } else { 14 | message = ""; 15 | } 16 | super(message); 17 | 18 | this.name = this.constructor.name; 19 | } 20 | } 21 | 22 | /** 23 | * Invalid parameter. 24 | * @group Errors 25 | */ 26 | export class InvalidParamError extends HpkeError {} 27 | 28 | /** 29 | * KEM input or output validation failure. 30 | * @group Errors 31 | */ 32 | export class ValidationError extends HpkeError {} 33 | 34 | /** 35 | * Public or private key serialization failure. 36 | * @group Errors 37 | */ 38 | export class SerializeError extends HpkeError {} 39 | 40 | /** 41 | * Public or private key deserialization failure. 42 | * @group Errors 43 | */ 44 | export class DeserializeError extends HpkeError {} 45 | 46 | /** 47 | * encap() failure. 48 | * @group Errors 49 | */ 50 | export class EncapError extends HpkeError {} 51 | 52 | /** 53 | * decap() failure. 54 | * @group Errors 55 | */ 56 | export class DecapError extends HpkeError {} 57 | 58 | /** 59 | * Secret export failure. 60 | * @group Errors 61 | */ 62 | export class ExportError extends HpkeError {} 63 | 64 | /** 65 | * seal() failure. 66 | * @group Errors 67 | */ 68 | export class SealError extends HpkeError {} 69 | 70 | /** 71 | * open() failure. 72 | * @group Errors 73 | */ 74 | export class OpenError extends HpkeError {} 75 | 76 | /** 77 | * Sequence number overflow on the encryption context. 78 | * @group Errors 79 | */ 80 | export class MessageLimitReachedError extends HpkeError {} 81 | 82 | /** 83 | * Key pair derivation failure. 84 | * @group Errors 85 | */ 86 | export class DeriveKeyPairError extends HpkeError {} 87 | 88 | /** 89 | * Not supported failure. 90 | * @group Errors 91 | */ 92 | export class NotSupportedError extends HpkeError {} 93 | --------------------------------------------------------------------------------