Skip to content
This repository has been archived by the owner on Sep 12, 2024. It is now read-only.

A ML-KEM (NIST FIPS-203 draft) implementation written in TypeScript

License

Notifications You must be signed in to change notification settings

openpgpjs/crystals-kyber-js

 
 

Repository files navigation

crystals-kyber-js

This fork implements the ML-KEM changes from the NIST FIPS-203 (draft): it exports MlKem512, 768, 1024 instead of Kyber512, 768, 1024.
This library is published on npm (as @openpgp/crystals-kyber-js) but not on deno. We recommend you use the upstream repo. The rest of the README refers to the upstream library.


deno doc Browser CI Node.js CI Deno CI Cloudflare Workers CI Bun CI codecov

A CRYSTALS-KYBER implementation written in TypeScript for various JavaScript runtimes.

This module is based on ntontutoveanu/crystals-kyber-javascript, but includes the following improvements:

  • ✅ Available on various JavaScript runtimes: Browsers, Node.js, Deno, Cloudflare Workers, etc.
  • ✅ Written in TypeScript.
  • ✅ Deterministic key generation support.
  • ✅ Constant-time validation for ciphertext.
  • ✅ Better performance: 1.4 to 1.8 times faster than the original implementation.
  • ✅ Tree-shaking friendly.

For Node.js, you can install crystals-kyber-js via npm/yarn:

npm install crystals-kyber-js

Then, you can use it as follows:

import { Kyber768 } from "crystals-kyber-js";

async function doKyber() {
  // A recipient generates a key pair.
  const recipient = new Kyber768(); // MlKem512 and MlKem1024 are also available.
  const [pkR, skR] = await recipient.generateKeyPair();
  //// Deterministic key generation is also supported
  // const seed = new Uint8Array(64);
  // globalThis.crypto.getRandomValues(seed); // node >= 19
  // const [pkR, skR] = await recipient.deriveKeyPair(seed);

  // A sender generates a ciphertext and a shared secret with pkR.
  const sender = new Kyber768();
  const [ct, ssS] = await sender.encap(pkR);

  // The recipient decapsulates the ciphertext and generates the same shared secret with skR.
  const ssR = await recipient.decap(ct, skR);

  // ssS === ssR
  return;
}

try {
  doKyber();
} catch (err) {
  console.log("failed: ", err.message);
}

Index

Installation

Node.js

Using npm:

npm install crystals-kyber-js

Using yarn:

yarn add crystals-kyber-js

Deno

Using deno.land:

// use a specific version
import { Kyber768 } from "https://deno.land/x/[email protected]/mod.ts";

// use the latest stable version
import { Kyber768 } from "https://deno.land/x/crystals_kyber/mod.ts";

Web Browsers

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 { Kyber768 } from "https://esm.sh/[email protected]";
  // ...
</script>

<!-- use the latest stable version -->
<script type="module">
  import { Kyber768 } from "https://esm.sh/crystals-kyber-js";
  // ...
</script>

Using unpkg:

<!-- use a specific version -->
<script type="module">
  import { Kyber768 } from "https://unpkg.com/[email protected]";
  // ...
</script>

Cloudflare Workers

git clone [email protected]:dajiaji/crystals-kyber-js.git
cd crystals-kyber-js
npm install -g esbuild
deno task dnt
deno task minify > $YOUR_SRC_PATH/crystals-kyber.js

Usage

This section shows some typical usage examples.

Node.js

import { Kyber768 } from "crystals-kyber-js";
// const { Kyber768 } = require("crystals-kyber-js");

async function doKyber() {
  const recipient = new Kyber768();
  const [pkR, skR] = await recipient.generateKeyPair();

  const sender = new Kyber768();
  const [ct, ssS] = await sender.encap(pkR);

  const ssR = await recipient.decap(ct, skR);

  // ssS === ssR
  return;
}

try {
  doKyber();
} catch (err) {
  console.log("failed: ", err.message);
}

Deno

import { MlKem512 } from "https://deno.land/x/[email protected]/mod.ts";

async function doKyber() {

  const recipient = new MlKem512();
  const [pkR, skR] = await recipient.generateKeyPair();

  const sender = new MlKem512();
  const [ct, ssS] = await sender.encap(pkR);

  const ssR = await recipient.decap(ct, skR);

  // ssS === ssR
  return;
}

try {
  doKyber();
} catch (_err: unknown) {
  console.log("failed.");
}

Browsers

<html>
  <head></head>
  <body>
    <script type="module">
      import { MlKem1024 } from "https://esm.sh/[email protected]";

      globalThis.doKyber = async () => {
        try {
          const recipient = new MlKem1024();
          const [pkR, skR] = await recipient.generateKeyPair();

          const sender = new MlKem1024();
          const [ct, ssS] = await sender.encap(pkR);

          const ssR = await recipient.decap(ct, skR);

          // ssS === ssR
          return;
        } catch (err) {
          alert("failed: ", err.message);
        }
      }
    </script>
    <button type="button" onclick="doKyber()">do CRYSTALS-KYBER</button>
  </body>
</html>

Contributing

We welcome all kind of contributions, filing issues, suggesting new features or sending PRs.

About

A ML-KEM (NIST FIPS-203 draft) implementation written in TypeScript

Resources

License

Security policy

Stars

Watchers

Forks

Languages

  • TypeScript 96.4%
  • JavaScript 3.6%