Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ecies/js-post-quantum/llms.txt

Use this file to discover all available pages before exploring further.

@ecies/post-quantum is built on well-audited, standards-track cryptographic primitives. Understanding what the library guarantees — and what it deliberately leaves outside its scope — helps you integrate it correctly into a larger security architecture. This page covers the ML-KEM standard, the KEM+DEM construction used internally, authentication properties, and practical algorithm selection guidance.

What is ML-KEM?

ML-KEM (Module-Lattice Key Encapsulation Mechanism) is standardised in NIST FIPS 203 and is the primary post-quantum key encapsulation mechanism selected by NIST. It replaces classical Diffie-Hellman and elliptic-curve key exchange in post-quantum settings. ML-KEM is based on the hardness of the Module Learning With Errors (MLWE) problem, which is believed to resist attacks by both classical and quantum computers — including Shor’s algorithm, which breaks RSA and ECC. Three parameter sets are defined, each targeting a different security level:
VariantSecurity LevelClassical Equivalent
ML-KEM-512NIST Level 1≈ AES-128
ML-KEM-768NIST Level 3≈ AES-192
ML-KEM-1024NIST Level 5≈ AES-256
ML-KEM-768 is the variant recommended by NIST as the default for most applications (FIPS 203, p40), striking a balance between security margin and performance overhead.

Encryption scheme

@ecies/post-quantum uses a standard KEM+DEM (Key Encapsulation Mechanism + Data Encapsulation Mechanism) construction, also known as a hybrid encryption scheme:
  1. KEM phase — ML-KEM encapsulate is called with the receiver’s public key. It produces a cipherText (the PKE ciphertext) and a sharedSecret (256 bits). The sharedSecret is used directly as the symmetric key.
  2. DEM phase — The plaintext is encrypted with the chosen AEAD cipher (AES-256-GCM or XChaCha20-Poly1305) using the sharedSecret as the key and a freshly generated random nonce.
The final encrypted payload is laid out as a single contiguous byte array:
[ PKE ciphertext ] [ nonce ] [ AEAD tag ] [ ciphertext ]
PKE ciphertext sizes by variant:
VariantPKE Size
ML-KEM-512768 bytes
ML-KEM-7681088 bytes
ML-KEM-10241568 bytes
The AEAD tag is always 16 bytes. The nonce is 12 or 16 bytes for AES-256-GCM (configurable) and always 24 bytes for XChaCha20-Poly1305.

Authentication

Both supported symmetric ciphers — AES-256-GCM and XChaCha20-Poly1305 — are AEAD (Authenticated Encryption with Associated Data) ciphers. This means every encrypted payload carries a cryptographic authentication tag that covers both the ciphertext and the nonce. During decryption, the library verifies the tag before returning any plaintext. If the ciphertext has been tampered with, truncated, or corrupted in any way, decryption throws an error and no plaintext is returned. This provides both confidentiality (only the holder of the secret key can read the message) and integrity (any modification to the ciphertext is detected).
@ecies/post-quantum does not authenticate the sender’s identity. It guarantees that a message encrypted to a given public key can only be decrypted by the holder of the corresponding secret key, and that the ciphertext has not been tampered with. It does not prove who created the ciphertext. If sender authentication is required, sign the plaintext (or the ciphertext) with a separate signing key before or after encryption.

MITM considerations

ML-KEM encapsulation is not inherently identity-bound — the encapsulation step takes only a public key as input, with no binding to a verified identity. A man-in-the-middle attacker who can substitute a different public key before encryption will receive a ciphertext they can decrypt, without the intended recipient ever learning.
The AEAD layer will detect any tampering with the ciphertext in transit, but it cannot detect a public-key substitution attack that occurs before encryption. To prevent this, always distribute and verify public keys through a trusted, authenticated channel (e.g., a PKI, a signed key server response, or a pre-shared key fingerprint). The library does not include a key-distribution mechanism.

Choosing algorithms

ML-KEM-768 (the default) is the right choice for the overwhelming majority of applications. It is the variant explicitly recommended by NIST (FIPS 203, p40) and provides a security level equivalent to AES-192, which is well above any known or foreseeable classical or quantum attack.Use ML-KEM-1024 if you are protecting data that must remain confidential for decades, or if your threat model requires a maximum security margin regardless of the performance and payload-size cost (an extra 480 bytes per message compared to ML-KEM-768).Use ML-KEM-512 only in severely resource-constrained environments where the 320-byte payload saving over ML-KEM-768 matters and where a security level equivalent to AES-128 is accepted by your policy.
AES-256-GCM (the default) is the faster choice on any CPU with AES-NI hardware acceleration, which includes virtually all modern x86-64, ARM Cortex-A, and Apple Silicon processors. The library automatically uses the native node:crypto implementation on Node.js and Bun, making it the highest-throughput option in those environments.XChaCha20-Poly1305 ("xchacha20") is preferred when:
  • The target device lacks hardware AES acceleration (many embedded, IoT, or older mobile processors).
  • You require constant-time behaviour by design, independent of the underlying hardware.
  • You are running in a browser on an unknown device fleet and want consistent timing regardless of hardware capability.
Both ciphers provide equivalent security guarantees (256-bit key, 128-bit authentication tag, AEAD).
The symmetricNonceLength option accepts 12 or 16 bytes and applies only to AES-256-GCM.A 12-byte nonce is the most widely used GCM nonce length and aligns with the NIST SP 800-38D recommendation for random nonces. It produces slightly smaller ciphertexts (4 bytes per message).A 16-byte nonce (the default in this library) provides a larger random nonce space — 2¹²⁸ possible nonces versus 2⁹⁶ — which makes random nonce collision statistically negligible even at very high message volumes. It is the safer default when messages are numerous and nonces are generated randomly rather than tracked as counters.Both options are cryptographically secure. The default of 16 bytes is the more conservative choice.

Dependencies

The library is built on a small set of audited, widely deployed cryptographic libraries:
  • @noble/post-quantum — ML-KEM-512/768/1024 implementation by Paul Miller. Audited and used across the JavaScript cryptography ecosystem.
  • @noble/ciphers / @ecies/ciphers — AES-256-GCM and XChaCha20-Poly1305 implementations. @ecies/ciphers wraps node:crypto’s native AES-256-GCM on runtimes that support it, falling back to the pure-JS @noble/ciphers path elsewhere.
  • @noble/hashes — Provides randomBytes for secure nonce generation.
No native add-ons, WebAssembly blobs, or external network calls are made at runtime. All cryptographic operations are performed in-process using the primitives above.

Build docs developers (and LLMs) love