draft-ietf-tls-ecdhe-mlkem . pure rust . MIT/Apache

X25519MLKEM768 as a stand-alone kem.

rustls 0.23.27+ ships X25519MLKEM768 inside its TLS stack but does not expose it as a reusable kem. anyone outside rustls (custom QUIC, MLS PQ ciphersuites, embedded TLS, HPKE PQ extensions) reimplements the byte concat and shared-secret combiner by hand. the closest existing crate, x-wing, is a different CFRG construction with a different byte layout, not wire-compatible. mlkem-tls is the TLS-WG hybrid combiner as a stand-alone crate, decoupled from rustls, with the byte order pinned to the draft.

mlkem-tls hybrid handshake plus the wire-format regression tests in action
wire format

bytes match the draft.

variant            encaps key   ciphertext   shared    TLS codepoint
X25519MLKEM768     1216 B       1120 B       64 B      0x11EC
X25519MLKEM1024    1600 B       1600 B       64 B      non-standard

on-the-wire layout, both parameter sets:
   encaps_key   = MLKEM.ek  || X25519.pub
   ciphertext   = MLKEM.ct  || X25519.eph_pub
   shared       = MLKEM.ss  || X25519.ss

ML-KEM bytes first, X25519 second. the draft inverts the convention
of secp256r1+mlkem hybrids, which put ECDHE first.
construction

two halves, concat, no kdf.

classical: x25519-dalek

the audited curve25519-dalek family. the path that protects you against any classical adversary today. constant-time scalar multiplication, widely used in audited stacks (rustls, IPFS, age).

post-quantum: mlkem-rs

mlkem-rs, FIPS 203 ML-KEM in pure rust. the path that protects you when an adversary acquires a quantum computer. all three security levels, 180 NIST ACVP test vectors green, 11 kani-verified formal proofs, dudect-style timing evidence.

combiner: byte concat

the shared secret is `MLKEM.ss || X25519.ss` (32 bytes each). no kdf wrapper. matches §1.5 of draft-ietf-tls-ecdhe-mlkem-04 and what cloudflare, chrome, firefox and rustls 0.23.27+ ship today. resulting strength is at least the stronger of the two halves at any given moment.

RustCrypto-trait shaped

per-level newtypes (`EncapsKey768`, `DecapsKey768`, `Ciphertext768Hybrid`, `SharedSecret768Hybrid`). `as_bytes()` for typed exit, `TryFrom<&[u8]>` with `LengthError` for the validating entry. constant-time `PartialEq` via `subtle`. `ZeroizeOnDrop` on the secret types.

no_std-friendly

default feature `std` is on; turn it off for embedded / wasm builds. only crypto deps are mlkem-rs, x25519-dalek, sha3, subtle, zeroize. no `unsafe` blocks. no git deps. no pre-1.0 crypto.

audit-readiness pack

SECURITY.md + SUPPLY_CHAIN.md. the post-quantum half (mlkem-rs) ships a full pack of its own (SECURITY, SIDE_CHANNELS, AUDIT_SCOPE, FORMAL_VERIFICATION, SUPPLY_CHAIN).

why this exists

rustls already ships hybrid. why a separate crate?

rustls bakes the X25519MLKEM768 combiner into its TLS stack. fine for users who run their TLS through rustls. less fine for everyone else. quinn users wiring custom crypto for QUIC reimplement the concat. embedded TLS implementations need a kem they can ship in 30 KB. MLS PQ ciphersuites and HPKE PQ extensions need the hybrid combiner with the same byte order rustls uses, but as a library, not a TLS stack. the closest crate that exists today, x-wing, is a different CFRG construction with a different byte layout. it is not wire-compatible.

so this crate is the missing piece. one job: take the TLS-WG hybrid combiner, expose it as a stand-alone kem with the kind of typed surface the RustCrypto ecosystem is used to. compose it into your protocol, your way, your library.

install

one line.

$ cargo add mlkem-tls

for embedded / wasm: cargo add mlkem-tls --no-default-features. requires rust 1.70+.

not audited. for production hybrid TLS in rustls, use rustls 0.23.27+ which ships the audited rustcrypto ml-kem inside the TLS stack. this crate is for stacks that don't use rustls.