Measured inside the handshake, not beside it.
Cycle counts on a primitive don’t tell you what a connection costs. These are full TLS and SSH key exchanges — decomposed phase by phase, sized to the byte, and cross-checked against the liboqs speed tools and eBACS reference cycles so they can be verified against the canonical numbers. Measured on x86 and ARM so the figures travel.
Hybrid and pure post-quantum against the classical baseline.
Expand any suite for its phase decomposition. The wire column is fixed by the protocol; the timing columns move with host load — read them as a distribution, and read the tail column as how far it strays.
| MLKEM768vs X25519 | 83.3 µs | 82.1 µs | 89.0 µs | 95.0 µs | 2.77× | 11,998 | 2,272 B | −47.5%one run · 11 Jul 2026 · 9f57fb31 run on an unidentified host — too few for a range | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen25.7 µs KEM encapsulate28.1 µs KEM decapsulate29.6 µs Total83.3 µs
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| X25519classical baseline | 157.6 µs | 156.4 µs | 165.2 µs | 175.3 µs | 1.43× | 6,345 | 64 B | baseline | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Classical keygen31.3 µs × 2 — client and server62.6 µs Classical derive47.5 µs × 2 — client and server95.0 µs Total157.6 µs
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SecP256r1MLKEM768vs X25519 | 235.4 µs | 233.1 µs | 243.9 µs | 250.5 µs | 2.08× | 4,248 | 2,402 B | +49.0%one run · 11 Jul 2026 · 9f57fb31 run on an unidentified host — too few for a range | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen25.8 µs KEM encapsulate27.7 µs KEM decapsulate29.5 µs Classical keygen15.6 µs × 2 — client and server31.2 µs Classical derive60.6 µs × 2 — client and server121.2 µs Total235.4 µs
OQS_DIST_BUILD dispatch · NEON confirmed · ARM64v8 Graviton3CPU steal 0%run 9f57fb3 ↗SecP256r1MLKEM768 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| X25519MLKEM768vs X25519 | 240.5 µs | 238.4 µs | 249.8 µs | 255.9 µs | 1.81× | 4,157 | 2,336 B | +52.4%one run · 11 Jul 2026 · 9f57fb31 run on an unidentified host — too few for a range | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen25.8 µs KEM encapsulate27.7 µs KEM decapsulate29.5 µs Classical keygen31.3 µs × 2 — client and server62.5 µs Classical derive47.5 µs × 2 — client and server95.0 µs Total240.5 µs
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Timing comparisons are published as a median and range across runs on one machine. The current host, which the record does not identify, has 1 run since 11 Jul 2026, fewer than the 7 a range needs, so each comparison shown here is a single dated run.
| MLKEM768vs X25519 | 36.0 µs | 34.9 µs | 39.3 µs | 46.6 µs | 9.30× | 27,786 | 2,272 B | −72.2%median of 9 runs · −81.5% to −60.3%latest −78.1% · 21 Sep 2026 · 6ed429a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen11.2 µs KEM encapsulate12.2 µs KEM decapsulate12.6 µs Total36.0 µs
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| X25519classical baseline | 163.4 µs | 159.5 µs | 194.7 µs | 228.6 µs | 1.89× | 6,120 | 64 B | baseline | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Classical keygen40.2 µs × 2 — client and server80.5 µs Classical derive41.5 µs × 2 — client and server82.9 µs Total163.4 µs
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SecP256r1MLKEM768vs X25519 | 182.7 µs | 178.8 µs | 202.5 µs | 216.7 µs | 3.46× | 5,473 | 2,402 B | +48.4%median of 8 runs · +8.5% to +77.7%latest +12.1% · 21 Sep 2026 · 6ed429a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen11.3 µs KEM encapsulate12.5 µs KEM decapsulate13.8 µs Classical keygen15.4 µs × 2 — client and server30.9 µs Classical derive57.1 µs × 2 — client and server114.2 µs Total182.7 µs
OQS_DIST_BUILD dispatch · kyber768/falcon AVX2 · SHA3 AVX512VLCPU steal 0%run 6ed429a ↗SecP256r1MLKEM768 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| X25519MLKEM768vs X25519 | 248.1 µs | 244.2 µs | 279.4 µs | 296.7 µs | 2.98× | 4,030 | 2,336 B | +27.9%median of 9 runs · +16.1% to +76.6%latest +53.1% · 21 Sep 2026 · 6ed429a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen18.0 µs KEM encapsulate19.5 µs KEM decapsulate17.2 µs Classical keygen52.3 µs × 2 — client and server104.6 µs Classical derive44.4 µs × 2 — client and server88.9 µs Total248.1 µs
OQS_DIST_BUILD dispatch · kyber768/falcon AVX2 · SHA3 AVX512VLCPU steal 0%run 6ed429a ↗X25519MLKEM768 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The aarch64 column was measured 11 Jul 2026, 71 days before the newest run here. These are real measurements, not estimates — but they were not taken alongside the others, so read across the tabs as separate runs rather than as one comparison.
| curve25519-sha256classical baseline | 158.3 µs | 157.1 µs | 164.2 µs | 176.3 µs | 1.58× | 6,317 | 64 B | baseline | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Classical keygen31.4 µs × 2 — client and server62.7 µs Classical derive47.8 µs × 2 — client and server95.6 µs Total158.3 µs
OQS_DIST_BUILD dispatch · NEON confirmed · ARM64v8 Graviton3CPU steal 0%run 9f57fb3 ↗curve25519-sha256 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mlkem768x25519-sha256vs curve25519-sha256 | 241.1 µs | 238.9 µs | 250.1 µs | 262.2 µs | 1.90× | 4,148 | 2,336 B | +52.0%one run · 11 Jul 2026 · 9f57fb31 run on an unidentified host — too few for a range | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen25.6 µs KEM encapsulate27.6 µs KEM decapsulate29.6 µs Classical keygen31.3 µs × 2 — client and server62.6 µs Classical derive47.8 µs × 2 — client and server95.6 µs Total241.1 µs
OQS_DIST_BUILD dispatch · NEON confirmed · ARM64v8 Graviton3CPU steal 0%run 9f57fb3 ↗mlkem768x25519-sha256 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| curve25519-sha256classical baseline | 162.7 µs | 165.3 µs | 186.4 µs | 210.8 µs | 1.98× | 6,148 | 64 B | baseline | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Classical keygen46.5 µs × 2 — client and server93.0 µs Classical derive34.8 µs × 2 — client and server69.6 µs Total162.7 µs
OQS_DIST_BUILD dispatch · kyber768/falcon AVX2 · SHA3 AVX512VLCPU steal 0%run 6ed429a ↗curve25519-sha256 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mlkem768x25519-sha256vs curve25519-sha256 | 165.2 µs | 162.9 µs | 180.3 µs | 189.2 µs | 2.98× | 6,052 | 2,336 B | +54.1%median of 7 runs · +1.2% to +79.3%latest run withheld · 21 Sep 2026 · 6ed429a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen11.0 µs KEM encapsulate12.5 µs KEM decapsulate12.9 µs Classical keygen31.2 µs × 2 — client and server62.5 µs Classical derive33.1 µs × 2 — client and server66.3 µs Total165.2 µs
OQS_DIST_BUILD dispatch · kyber768/falcon AVX2 · SHA3 AVX512VLCPU steal 0%run 6ed429a ↗mlkem768x25519-sha256 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The aarch64 column was measured 11 Jul 2026, 71 days before the newest run here. These are real measurements, not estimates — but they were not taken alongside the others, so read across the tabs as separate runs rather than as one comparison.
| mlkem768vs curve25519 | 53.9 µs | 53.9 µs | 65.8 µs | 77.6 µs | 6.75× | 18,568 | 2,272 B | −69.4%median of 9 runs · −81.5% to −59.5%latest −71.6% · 21 Sep 2026 · 6ed429a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen17.6 µs KEM encapsulate19.2 µs KEM decapsulate17.1 µs Total53.9 µs
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| curve25519+mlkem768vs curve25519 | 166.8 µs | 163.9 µs | 182.3 µs | 196.6 µs | 3.14× | 5,994 | 2,336 B | withheldwithheld · 21 Sep 2026 · 6ed429a9 runs on c7i.large — too few for a range | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen11.1 µs KEM encapsulate12.3 µs KEM decapsulate12.8 µs Classical keygen31.3 µs × 2 — client and server62.6 µs Classical derive34.0 µs × 2 — client and server68.0 µs Total166.8 µs
OQS_DIST_BUILD dispatch · kyber768/falcon AVX2 · SHA3 AVX512VLCPU steal 0%run 6ed429a ↗curve25519+mlkem768 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ecp256vs curve25519 | 169.2 µs | 168.7 µs | 200.1 µs | 214.2 µs | 2.17× | 5,909 | 128 B | +18.5%median of 9 runs · −27.0% to +47.5%latest −11.1% · 21 Sep 2026 · 6ed429a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Classical keygen13.8 µs × 2 — client and server27.6 µs Classical derive70.8 µs × 2 — client and server141.6 µs Total169.2 µs
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ecp256+mlkem768vs curve25519 | 180.1 µs | 178.2 µs | 195.5 µs | 203.7 µs | 3.34× | 5,551 | 2,400 B | withheldwithheld · 21 Sep 2026 · 6ed429a9 runs on c7i.large — too few for a range | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen13.5 µs KEM encapsulate12.6 µs KEM decapsulate12.9 µs Classical keygen13.8 µs × 2 — client and server27.5 µs Classical derive56.8 µs × 2 — client and server113.7 µs Total180.1 µs
OQS_DIST_BUILD dispatch · kyber768/falcon AVX2 · SHA3 AVX512VLCPU steal 0%run 6ed429a ↗ecp256+mlkem768 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| curve25519classical baseline | 191.0 µs | 189.9 µs | 213.4 µs | 223.7 µs | 1.90× | 5,236 | 64 B | baseline | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Classical keygen52.1 µs × 2 — client and server104.3 µs Classical derive43.3 µs × 2 — client and server86.7 µs Total191.0 µs
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ML-DSA-44 | 18.9 µs | 72.2 µs | 19.7 µs | 1.28 KB | 2.36 KB | Lattice | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| ML-DSA-65 | 29.4 µs | 94.0 µs | 29.9 µs | 1.91 KB | 3.23 KB | Lattice | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| ML-DSA-87 | 58.6 µs | 138.6 µs | 44.4 µs | 2.53 KB | 4.52 KB | Lattice | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| Falcon-512 | 6.05 ms | 215.4 µs | 45.3 µs | 897 B | 752 B | Lattice | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| Falcon-1024 | 18.56 ms | 468.9 µs | 94.3 µs | 1.75 KB | 1.43 KB | Lattice | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| SLH_DSA_PURE_SHAKE_128S | 111.44 ms | 851.44 ms | 849.9 µs | 32 B | 7.67 KB | Hash | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| SLH_DSA_PURE_SHAKE_128F | 1.74 ms | 40.79 ms | 2.43 ms | 32 B | 16.69 KB | Hash | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| RSA-2048-PSS | 46.75 ms | 373.9 µs | 40.3 µs | 294 B | 256 B | Lattice | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| RSA-3072-PSS | 140.29 ms | 989.1 µs | 66.1 µs | 422 B | 384 B | Lattice | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| ECDSA-P256 | 13.9 µs | 25.3 µs | 81.4 µs | 91 B | 70 B | Lattice | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| ECDSA-P384 | 118.7 µs | 165.7 µs | 387.1 µs | 120 B | 101 B | Lattice | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Payload size is a cited choice, not an arbitrary one: RFC 8446 §5.2 — max TLSPlaintext record length.
| Phase | Mean | Median | p95 | p99 | Stdev | Min | Max | Iterations |
|---|---|---|---|---|---|---|---|---|
| Encrypt | 2.0 µs | 2.0 µs | 2.1 µs | 3.0 µs | 1.0 µs | 1.9 µs | 19.6 µs | 1,000 |
| Decrypt | 2.0 µs | 1.9 µs | 2.1 µs | 3.1 µs | 0.8 µs | 1.9 µs | 17.8 µs | 1,000 |
The weighting is the same as TLS on purpose. The composed total uses the same phase weights as the TLS and SSH tracks, because the crypto multiplicity is the same: both peers generate a classical keypair and both derive, and the additional RFC 9370 key exchange contributes one KEM keygen, one encapsulation and one decapsulation. A different weighting was not invented to make this track look distinct.
Two gaps worth naming. MODP (finite-field) groups are not measured. Group 14 (MODP-2048) is still very common in deployed IPsec and is arguably the most representative classical baseline, but measuring it requires the exact RFC 3526 prime -- and a mistranscribed prime would still compute a shared secret and still produce a plausible timing while measuring a group that is not 14. Left unmeasured rather than measured wrongly. MACsec is named in the same CFDIR use case (3.12) and is not measured here. This track's claim on that cell is IKEv2 key establishment only.
An IPsec tunnel rekeys on a timer or byte budget, so the number of key exchanges over its life is far higher than TLS's one per connection. That multiplier is a property of a deployment's configuration rather than of the cryptography, so it belongs to whoever is costing the tunnel. This track measures the cost of one key establishment.
An ML-DSA-87 certificate chain is 16.8× the size of the one it replaces.
Every TLS connection that isn't resumed carries the server's chain. This is real: chains minted and measured, not key sizes added up.
| Certificate | Sent on the wire | Against ECDSA-P256 |
|---|---|---|
| ML-DSA-87 | 14.70 KB | 16.78× |
| ML-DSA-65 | 10.88 KB | 12.42× |
| ML-DSA-44 | 7.89 KB | 9.01× |
| RSA-3072 | 2.14 KB | 2.45× |
| RSA-2048 | 1.64 KB | 1.88× |
| ECDSA P-256 | 897 B | the baseline |
These are a floor. The certificates behind them carry short names and no Certificate Transparency extensions, where a public certificate carries more — so a real chain is larger, and the post-quantum penalty on a real chain is larger still.
Two of them no longer fit in the first round trip.
A server's opening flight has about 14.26 KB before it has to stop and wait for an acknowledgement. Crossing that line doesn't make the handshake bigger — it makes it slower, by a full round trip, on every new connection.
Each figure adds three measured parts — a captured ServerHello, the chain above, and the signature over the handshake. The shape of the flight is assumed rather than captured, and it assumes nothing extra: no stapled revocation response, no client certificate, no session ticket. Every one of those pushes the total further over, not back under.
A post-quantum access token is 15.7× the one it replaces.
Every signed API call, session cookie and identity assertion carries one of these. Unlike a certificate chain, a token is re-sent on each request — so its size is paid over and over, not once per connection.
| Signature | Token on the wire | Against ECDSA-P256 |
|---|---|---|
| ML-DSA-87 | 6.34 KB | 15.69× |
| ML-DSA-65 | 4.63 KB | 11.44× |
| ML-DSA-44 | 3.47 KB | 8.58× |
| Falcon-512 | 1.17 KB | 2.88× |
| RSA-3072 | 830 B | 2.00× |
| RSA-2048 | 660 B | 1.59× |
Every figure above is a configurable default, not a limit of the protocol. Crossing one is a question to ask of your own stack rather than a failure — raise the buffer and the token fits. What it tells you is where a post-quantum token stops being invisible: it is the cookie, not the handshake, that runs out of room first.
Every figure traces to a run.
Clone the harness and you should reproduce these within run-to-run variance.