A pure-JavaScript implementation of the FIPS 203 ML-KEM (formerly CRYSTALS-Kyber) Key Encapsulation Mechanism.
This library is engineered for maximal V8 execution efficiency and strict standard compliance without allocating expensive TypedArray garbage collection loops, relying strictly on 3D simulated Int32Array polynomials. It runs entirely synchronously in pure JavaScript with native Post-Quantum resistance.
- FIPS 203 API: Provides Native
mlKemKeyGen,mlKemEncaps, andmlKemDecapsroutines mathematically checked against Reference specifications. - Mathematical Scaffolding: Implements high-performance bitwise Barrett and Montgomery reduction protocols bridging Cooley-Tukey and Gentleman-Sande NTT butterflies safely avoiding precision overflows natively.
- Constant-Time execution: Fully defends against IND-CCA2 Decapsulation timing side-channels via logical arithmetic bit-mask mappings preventing V8 branch inferences on implicit rejection states.
This project is built on @stdlib the standard library for JavaScript scientific computing. The following packages are integrated:
| Package | Usage |
|---|---|
@stdlib/ndarray-ctor |
3D polynomial matrix (PolyMatrix) backed by proper ndarray |
@stdlib/array-int32 |
Typed array allocation for polynomial buffers |
@stdlib/math-base-ops-imul |
All modular arithmetic (NTT, Barrett, Montgomery) |
@stdlib/math-base-special-floor |
Compression/decompression rounding |
@stdlib/assert-is-uint8array |
Input validation on KEM API entry points |
Here is a brief look at how poly-matrix-js utilizes @stdlib to engineer efficient, garbage-collection-free mathematical structures:
const ndarray = require('@stdlib/ndarray-ctor');
const Int32Array_ = require('@stdlib/array-int32');
// 1. Allocate a single flat typed memory buffer for polynomial rings
const N = 256; // Standard polynomial degree
const length = rows * cols * N;
const buffer = new Int32Array_(length);
// 2. Structure the flat memory buffer into a 3D PolyMatrix tensor
const tensor = ndarray('int32', buffer, [rows, cols, N], [cols * N, N, 1], 0, 'row-major');
// 3. Perform constant-time scalar index mutations safely
tensor.set(row, col, coeffIndex, value);How @stdlib empowers this ML-KEM Implementation:
- Zero-Allocation Math Engine: Polynomial multiplications and Number-Theoretic Transforms (NTT) execute right over flat integer arrays without instantiating intermediate objects, entirely bypassing V8 garbage collector stalls during heavy cryptographic loops.
- Cache-Locality with
ndarray:@stdlib/ndarray-ctorbeautifully bridges the conceptual need for 3D matrix arithmetic (rows × columns × 256 polynomial coefficients) whilst maintaining the strict memory contiguity of a 1D@stdlib/array-int32backend buffer. This ensures the CPU can reliably pre-fetch sequential memory segments. - Constant-Time Execution Primitives: Utilizing low-level bitwise manipulation operators and
@stdlib/math-base-ops-imulforces implicit rejection checks and reductions to evaluate via mathematical masks, mitigating branching side-channel attacks naturally. - Secure Input Assertions: Functions robustly gate-keep public-facing KEM parameters exclusively through
@stdlib/assert-is-uint8array, ensuring strict compliance to expected entropy buffers at minimum execution cost.
npm install kem-jsSupported parameter architectures uniformly match NIST standardization security mappings:
ML-KEM-512ML-KEM-768ML-KEM-1024
const crypto = require('crypto');
const { mlKemKeyGen, mlKemEncaps, mlKemDecaps } = require('kem-js');
// 1. Establish Randomness Seeds
const d = crypto.randomBytes(32);
const z = crypto.randomBytes(32); // implicit rejection key
// 2. Key Generation
const { ek, dk } = mlKemKeyGen(d, z, 'ML-KEM-512');
// 3. Encapsulation
const m = crypto.randomBytes(32);
const { K, c } = mlKemEncaps(ek, m, 'ML-KEM-512');
// K is the 32-byte shared symmetric AES candidate, c is public ciphertext
// 4. Decapsulation
const sessionKey = mlKemDecaps(c, dk, 'ML-KEM-512');
// => K and sessionKey perfectly synchronizeCryptographic operations are mathematically exhaustive. To prevent event loop locks on Node.js API backends, we integrate worker_threads natively offloading operations via deterministic queues smoothly bridged to Express routes. Reference the backend directory mapping a complete AES-256-GCM handshake API established from symmetric keys generated within ML-KEM algorithms.
Ensure the full internal math engine adheres properly:
make test