Kyber, formally CRYSTALS-Kyber, is a post-quantum key-encapsulation mechanism that lets two parties agree on a shared secret key over an open channel. NIST standardized it as ML-KEM in FIPS 203, published August 13, 2024. The names are not interchangeable: ML-KEM is derived from Kyber and differs from the earlier submission, so ML-KEM implementations are not wire-compatible with old Kyber ones.
A KEM has three operations. The receiver runs KeyGen to get an encapsulation key (public) and a decapsulation key (private). The sender runs Encaps on the public key and gets a 32-byte shared secret plus a ciphertext. The receiver runs Decaps on that ciphertext and recovers the same 32 bytes. The shared secret then keys a symmetric cipher such as AES-GCM. FIPS 203 bases the security on the Module Learning with Errors problem, which is believed hard even for quantum computers.
FIPS 203 defines three parameter sets, all with polynomial degree n = 256 and modulus q = 3329:
The next run uses a pure-Python implementation of ML-KEM (kyber-py 1.2.0) to print the real sizes in bytes and check that both sides agree.
from kyber_py.ml_kem import ML_KEM_512, ML_KEM_768, ML_KEM_1024
for n, k in (("ML-KEM-512", ML_KEM_512), ("ML-KEM-768", ML_KEM_768), ("ML-KEM-1024", ML_KEM_1024)):
ek, dk = k.keygen()
K, c = k.encaps(ek)
K2 = k.decaps(dk, c)
print(n, len(ek), len(dk), len(c), len(K), K == K2)
ML-KEM-512 800 1632 768 32 True
ML-KEM-768 1184 2400 1088 32 True
ML-KEM-1024 1568 3168 1568 32 True
The columns are encapsulation key, decapsulation key, ciphertext and shared secret, all matching Table 3 of FIPS 203. That library is a teaching implementation, so use a vetted library in production.
An ML-KEM-768 encapsulation key is 1,184 bytes and its ciphertext is 1,088 bytes. The size follows the formula 384k + 32 bytes for the key, so 800 bytes for ML-KEM-512 and 1,568 for ML-KEM-1024. An X25519 public key, in comparison, is 32 bytes, which is why post-quantum handshakes carry far more data.
Decapsulation does not raise an error. It returns a different 32-byte secret. After flipping one bit of an ML-KEM-768 ciphertext, comparing the result to the original secret printed True for the intact ciphertext and False for the altered one. FIPS 203 says well-formed input never explicitly fails, which prevents leaking the failure to an attacker.