Skip to content
All guides
Conformance certification

A FIPS 203 conformance checklist for ML-KEM implementations

7 min
TL;DR

Read this first

Conformance to FIPS 203 (ML-KEM) is not "it passes the known-answer vectors." The load-bearing requirements live on the paths the honest vectors never touch: the §7.2 encapsulation-key modulus check, the §7.3 ciphertext length check, and constant-time implicit rejection. Work through the checklist below against the exact implementation you ship — not a reference build — and re-run it every release.

Below is the concrete checklist we run against any ML-KEM implementation. It is deliberately narrow: this is a conformance checklist, distinct from a FIPS 140-3 module validation and from a security audit — see ACVP vs conformance vs FIPS 140-3 for where the boundaries sit. Each item maps to a normative requirement in FIPS 203 or to a class of vector you must feed the implementation to exercise it.

Input validation (§7.2 and §7.3)

  • **§7.2 — encapsulation-key modulus check.** Every coefficient of the encapsulation key must be reduced mod q = 3329. Feed a key with a single out-of-range coefficient and confirm the implementation rejects it. No honest vector contains such a key, so a build that skips this check still passes the KATs.
  • **§7.3 — ciphertext type/length check.** Decapsulation must verify the ciphertext is the correct length for the parameter set before processing it. Feed a wrong-length ciphertext and confirm it is rejected rather than parsed.
  • **Both directions, all parameter sets.** Run the malformed-input checks for ML-KEM-512, ML-KEM-768, and ML-KEM-1024 — a check present for one parameter set is sometimes absent for another.

Implicit rejection

  • **Deterministic pseudo-random secret, not an error.** On an invalid ciphertext, decapsulation must return a deterministic pseudo-random shared secret — never an error or an exception. Confirm the same invalid ciphertext yields the same secret across runs.
  • **Indistinguishable by timing.** The reject path must be indistinguishable, by timing, from the accept path. A branch that shortcuts on failure turns the reject into an observable event and an oracle. Confirm there is no data-dependent early return on the failure path.

Sizes and encoding

  • **Exact byte sizes.** For ML-KEM-768: encapsulation key 1184 B, decapsulation key 2400 B, ciphertext 1088 B, shared secret 32 B. Verify the exact sizes for the parameter set in use (ML-KEM-512 and ML-KEM-1024 differ). A right-shaped-but-wrong-length artifact must be rejected, not truncated or padded.
  • **ByteEncode / ByteDecode round-trip.** Byte-encoding and decoding of polynomial vectors must match FIPS 203. Encode then decode and confirm you recover the original; a round-trip mismatch is a conformance defect.
  • **Cross-implementation agreement.** Keys and ciphertexts produced by one conformant implementation must decode and interoperate with another. Disagreement points to an encoding deviation.

Versioning and vectors

  • **Final FIPS 203, not a Kyber round.** Confirm the implementation targets final ML-KEM, not an earlier CRYSTALS-Kyber round — they are not interoperable. Where a project still says "Kyber", check the actual parameters and encoding against FIPS 203.
  • **KATs are necessary but not sufficient.** Passing NIST ACVP known-answer vectors confirms the happy path is byte-correct; it exercises honest inputs only and cannot reach §7.2/§7.3 or the reject path.
  • **Add adversarial vectors.** Feed malformed-input vectors — out-of-range coefficients, malformed keys, wrong-length ciphertexts — such as those the C2SP/CCTV project publishes, to actually exercise the checks above.
Pitfall

"It passes the KATs" and "it's a popular, audited library" are not evidence of §7.2/§7.3 conformance

Adoption and an audit report tell you a project is scrutinized on the happy path — precisely the part the KATs already cover. Real, widely deployed implementations have passed every known-answer vector while skipping the §7.2 modulus check or leaking the reject path by timing. The only evidence of conformance is exercising the reject behaviour directly with adversarial vectors, re-run on every release so a dependency bump or optimization cannot quietly drop a check. Emit findings as SARIF so they land in your existing review flow.

How quantakrypto helps

We run this checklist against the implementation you actually ship, not a reference build. We conformance-test the §7.2/§7.3 input checks, implicit-rejection timing, sizes and encoding using adversarial vectors the KATs miss (certification), assess whether it is exploitable in your deployment (audit), and sequence the change into your rollout without breaking production (migration). The deliverable is a dated, signed conformance report backed by malformed-input vectors and re-run on every release — see conformance testing for the method. Evidence, not a vendor's assurance.

Frequently asked questions

Our ML-KEM library passes NIST's ACVP vectors — is it FIPS 203 conformant?

Not necessarily. ACVP known-answer vectors exercise only honest, well-formed inputs, so they confirm the happy path is byte-correct. Conformance also requires the §7.2 encapsulation-key modulus check (coefficients reduced mod q = 3329), the §7.3 ciphertext length check, and constant-time implicit rejection — none of which any honest vector can trigger. You have to feed adversarial, malformed-input vectors to exercise those paths.

What exact sizes should ML-KEM-768 produce?

Encapsulation key 1184 bytes, decapsulation key 2400 bytes, ciphertext 1088 bytes, and a 32-byte shared secret. ML-KEM-512 and ML-KEM-1024 have different sizes, so verify against the parameter set actually in use. A wrong-length artifact must be rejected, not truncated or padded to fit.

Why is timing part of conformance for ML-KEM?

FIPS 203 decapsulation never errors on an invalid ciphertext; it returns a deterministic pseudo-random shared secret. That design is only safe if an attacker cannot tell the reject path from the accept path. A branch that shortcuts on failure makes the reject observable and turns it into an oracle, so an indistinguishable, constant-time reject path is a conformance requirement, not just a hardening nicety.

How is this checklist different from a FIPS 140-3 validation or a security audit?

Conformance asks whether the implementation follows the letter of FIPS 203, including every input check and reject path. FIPS 140-3 is a formal module validation program, and a security audit asks whether the code is exploitable in context — side channels, RNG quality, key management. They catch different failures and none subsumes the others; see /guides/acvp-vs-conformance-vs-fips-140-3 for the full breakdown.

Take the next step

Related reading

References

Get started

Turn quantum risk into a credential.

Book a discovery call and get an indicative scope and pricing for your organisation.