
Security News
Software Engineering Daily Podcast: Feross on AI, Open Source, and Supply Chain Risk
Socket CEO Feross Aboukhadijeh joins Software Engineering Daily to discuss modern software supply chain attacks and rising AI-driven security risks.
@hpke/ml-kem
Advanced tools
Documentation: jsr.io | pages (only for the latest ver.)
An example of use:
import { Aes256Gcm, CipherSuite, HkdfSha256 } from "@hpke/core";
import { MlKem768 } from "@hpke/ml-kem"; // MlKem512 and MlKem1024 are also available.
async function doHpke() {
const suite = new CipherSuite({
kem: new MlKem768(),
kdf: new HkdfSha256(),
aead: new Aes256Gcm(),
});
// NOTE: The following support for JWKs with the AKP key type is experimental.
// Please be aware that the specifications are subject to change without notice.
const jwkPub = {
kty: "AKP",
kid: "01",
alg: "ML-KEM-768",
pub:
"PxuKXPWqDLFIz6x2ajCnggmjzpfLQnqegTJU4LapmuJTcLWDwnU1fOO01sYKr9oD6Zc04OmOulau74IekrjB20OUKnw3yZd9eZRv4EdN8nuc87EsqUuwZAHQkVBTC_gq38RiO9evl0JZhLjFP1GWnrwC2bQarOeVNuMoKvWt7bY2PUp727BqaeJMiSiI9nEAVbtkTbYLo7iEIEwDsHwqisoCSawp6td9XIeaeQoJuFClXvYUzHPPf3JyI7oNY1MpXACMmGqpIANJoKxQDjR-4XlaGoNpq2FRwnsTQcrOVoUu52xtPMuDMbI83osiSvmy3uQC2WBbv6hAGXZBnFerFoa9oJayjLZUzUpdt8MlmOAUkeIbjNVEl_YP4rwx14OSjjgr-_MzK3VM-WmxKqWPQ4tKVwZBKdRFYAmhcqWas7d8yEx2lEuZpTRFpSmsCmKtSQF0pHMkpdNLgaaCppwKjddfDek8IOQwJmwjsAxIafU8b9CFTtPK9FRJUrBe07Ow1so08PKX8umnwRh4BKN6Ehpq0qtQ2vR1qjol5smg1qKd72LL0pgFD1swfAU6XIg4tMM1fzN2ZTwzZvpv4QJdGWDHW6ZDJlwVeoTJFNVZ9UDGfsFYc5Sve9F4MNUInVBZBvqfdmqbk5CfW2YnzAWgshksv8InGwsi13oHzlUe2qZSLUArAAA3I8EVk2yX9UyIqlE0gqBVVMYo5pRI62oO9vNGNByAK9q5sDugryl9nouTi5yr76RnIkIaM4qHLZqIuIyfDuxGkyw2fMWLg1c9JgNqr1J25RWw8jBZtAyEj2OKzjcD7mwn2WaZDHcC7SOgzZukz2Fppmih8LtYawdmkuHCFXVP9nhL2RokjLkPAIo-ylmFLAV5ZpM6Goa24FsvrZGyi8YWSLBBp6wEargRK2rCy5APtcCYIdxLBxa1CeEi3JfG7XNC9vSftlVZcpw4R2O6LSu4z1auNvOyaZcKxUhBITskt5LJSfPHdecKyPfMU3Y_9jitxRE-xgB1waeSdspHPBE4MpVKviB76_DNBCbA4pczlHJWx3Vr-bUNghkaB_C6XVoVSwhm4pNHO0B2oemV-dCGpHLBGKwiwhaoOZIGYKMx7uGY31saFZUjnVeAzadfc8Z2WkauSqNAAZOd-tkvfhJKXyxiiyWd6VYLv0cMxpzGUtwpuTuoakmQ3OCvGkUkwZmmkmcMr3SNFmEv7tcR-IpQXVUqZECqBCJibxhfaSGoLvklCGAoroVi_HYQ4bFknvAJTZa1Bfu38RKJbvrA0ZKvRdkDrHmSu-m_MOJXfiRYHLxPc7GA0Epp9UCznhmkrjauxPIa3ndJZTkbyuvAr4actjYxMntCG-xnJmUbh1i_7nPFkSEtT_mB9mhMWLNZwtB_oeYB1sXL_clksxkJzKN__5YgT7VojZLKWoV1jPFg6bBu0YMgpLGwyOgZaudqb2IZctF6TWSn3wTFpMMzw7wayqs3cJFJo7jKCCqPvKEyaKGwIiMOLWMCcsuf8uZlWvFzJ_O5gHCV9YK-GL0_Tgu3I-ztabBYVimYZUjXIrA7W70Vesmd7hwKmqE",
key_ops: [],
};
const pk = await suite.kem.importKey("jwk", jwkPub, true);
// In addition to importing keys from external sources, you can also generate keys as follows:
// const rkp = await suite.kem.generateKeyPair();
// const rkp = await suite.kem.deriveKeyPair(random64bytesValue);
const sender = await suite.createSenderContext({ recipientPublicKey: pk });
const jwkPriv = {
kty: "AKP",
kid: "01",
alg: "ML-KEM-768",
priv:
"1pz8ZPhNTzPkxU4Wa3_5KDo5SYalObI5h6EPOdLZaJtt5i40ZaVcnHigfSZb6FQLPliwgBoSTQf_ErQ41SAuoA",
key_ops: ["deriveBits"],
};
const sk = await suite.kem.importKey("jwk", jwkPriv, false);
const recipient = await suite.createRecipientContext({
recipientKey: sk,
enc: sender.enc,
});
const encrypted = await sender.seal(
new TextEncoder().encode("Hellow world!"),
);
const pt = await recipient.open(encrypted);
// Hello world!
console.log(new TextDecoder().decode(pt));
}
try {
doHpke();
} catch (err: unknown) {
console.log("failed:", (err as Error).message);
}
@hpke/ml-kem needs to be used with
@hpke/core,
which can be installed in the same manner as desribed below.
You can install the package with npm, yarn or pnpm.
# Using npm:
npm install @hpke/ml-kem
yarn add @hpke/ml-kem
pnpm install @hpke/ml-kem
# Using jsr:
npx jsr add @hpke/ml-kem
yarn dlx jsr add @hpke/ml-kem
pnpm dlx jsr add @@hpke/ml-kem
The above manner can be used with other JavaScript runtimes that support npm, such as Cloudflare Workers and Bun.
Then, you can use the module from code like this:
import { Aes256Gcm, CipherSuite, HkdfSha256 } from "@hpke/core";
import { MlKem768 } from "@hpke/ml-kem";
For Deno, it is recommended to use the jsr.io registry.
deno add jsr:@hpke/ml-kem
Followings are how to use this module with typical CDNs. Other CDNs can be used as well.
Using esm.sh:
<!-- use a specific version -->
<script type="module">
import {
Aes256Gcm,
CipherSuite,
HkdfSha256,
} from "https://esm.sh/@hpke/core@<SEMVER>";
import { MlKem768 } from "https://esm.sh/@hpke/ml-kem@<SEMVER>";
// ...
</script>
<!-- use the latest stable version -->
<script type="module">
import {
Aes256Gcm,
CipherSuite,
HkdfSha256,
} from "https://esm.sh/@hpke/core";
import { MlKem768 } from "https://esm.sh/@hpke/ml-kem";
// ...
</script>
Using unpkg:
<!-- use a specific version -->
<script type="module">
import {
Aes256Gcm,
CipherSuite,
HkdfSha256,
} from "https://unpkg.com/@hpke/core@<SEMVER>/esm/mod.js";
import { MlKem768 } from "https://unpkg.com/@hpke/ml-kem@<SEMVER>/esm/mod.js";
// ...
</script>
This section shows some typical usage examples.
import { Aes256Gcm, CipherSuite, HkdfSha256 } from "@hpke/core";
import { MlKem768 } from "@hpke/ml-kem";
async function doHpke() {
// setup
const suite = new CipherSuite({
kem: new MlKem768(),
kdf: new HkdfSha256(),
aead: new Aes256Gcm(),
});
const rkp = await suite.kem.generateKeyPair();
// Note that the `ct` (ciphertext) resulting from ML-KEM::Encaps() is set to `sender.enc`.
const sender = await suite.createSenderContext({
recipientPublicKey: rkp.publicKey,
});
// encrypt
const encrypted = await sender.seal(new TextEncoder().encode("Hello world!"));
const recipient = await suite.createRecipientContext({
recipientKey: rkp.privateKey,
enc: sender.enc, // == `ct` (ciphertext) in the context of ML-KEM
});
// decrypt
const pt = await recipient.open(encrypted);
// Hello world!
console.log(new TextDecoder().decode(pt));
}
try {
doHpke();
} catch (err) {
console.log("failed:", err.message);
}
import { Aes256Gcm, CipherSuite, HkdfSha256 } from "@hpke/core";
import { MlKem768 } from "@hpke/ml-kem";
async function doHpke() {
// setup
const suite = new CipherSuite({
kem: new MlKem768(),
kdf: new HkdfSha256(),
aead: new Aes256Gcm(),
});
const rkp = await suite.kem.generateKeyPair();
// Note that the `ct` (ciphertext) resulting from ML-KEM::Encaps() is set to `sender.enc`.
const sender = await suite.createSenderContext({
recipientPublicKey: rkp.publicKey,
});
// encrypt
const encrypted = await sender.seal(new TextEncoder().encode("Hello world!"));
const recipient = await suite.createRecipientContext({
recipientKey: rkp.privateKey,
enc: sender.enc, // == `ct` (ciphertext) in the context of ML-KEM
});
// decrypt
const pt = await recipient.open(encrypted);
// Hello world!
console.log(new TextDecoder().decode(pt));
}
try {
doHpke();
} catch (_err: unknown) {
console.log("failed.");
}
<html>
<head></head>
<body>
<script type="module">
import {
Aes256Gcm,
CipherSuite,
HkdfSha256,
} from "https://esm.sh/@hpke/core";
import { MlKem768 } from "https://esm.sh/@hpke/ml-kem";
globalThis.doHpke = async () => {
try {
const suite = new CipherSuite({
kem: new MlKem768(),
kdf: new HkdfSha256(),
aead: new Aes256Gcm(),
});
const rkp = await suite.kem.generateKeyPair();
// Note that the `ct` (ciphertext) resulting from ML-KEM::Encaps() is set to `sender.enc`.
const sender = await suite.createSenderContext({
recipientPublicKey: rkp.publicKey,
});
// encrypt
const encrypted = await sender.seal(
new TextEncoder().encode("Hello world!"),
);
const recipient = await suite.createRecipientContext({
recipientKey: rkp.privateKey, // rkp (CryptoKeyPair) is also acceptable.
enc: sender.enc, // == `ct` (ciphertext) in the context of ML-KEM
});
// decrypt
const pt = await recipient.open(encrypted);
// Hello world!
alert(new TextDecoder().decode(pt));
} catch (err) {
alert("failed:", err.message);
}
};
</script>
<button type="button" onclick="doHpke()">do HPKE</button>
</body>
</html>
We welcome all kind of contributions, filing issues, suggesting new features or sending PRs.
FAQs
A Hybrid Public Key Encryption (HPKE) module extension for ML-KEM.
The npm package @hpke/ml-kem receives a total of 90 weekly downloads. As such, @hpke/ml-kem popularity was classified as not popular.
We found that @hpke/ml-kem demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CEO Feross Aboukhadijeh joins Software Engineering Daily to discuss modern software supply chain attacks and rising AI-driven security risks.

Security News
GitHub has revoked npm classic tokens for publishing; maintainers must migrate, but OpenJS warns OIDC trusted publishing still has risky gaps for critical projects.

Security News
Rust’s crates.io team is advancing an RFC to add a Security tab that surfaces RustSec vulnerability and unsoundness advisories directly on crate pages.