Composed protocol tracks
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.
Run date
2026-08-22
Commit
7e3d474
Host
Xeon Platinum 8259CL @ 2.50GHz
liboqs
0.15.0
Architectures
aarch64 · x86_64
OpenSSL
3.0.13
Every track
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% | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
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% | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
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% | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
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
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MLKEM768vs X25519 | 65.7 µs | 61.4 µs | 76.5 µs | 86.5 µs | 5.26× | 15,225 | 2,272 B | −78.5% | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen22.3 µs KEM encapsulate21.2 µs KEM decapsulate22.1 µs Total65.7 µs
OQS_DIST_BUILD dispatch · kyber768/falcon AVX2 · SHA3 AVX512VLCPU steal 0.5714%run 7e3d474 ↗MLKEM768 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SecP256r1MLKEM768vs X25519 | 221.9 µs | 215.0 µs | 238.7 µs | 374.7 µs | 3.34× | 4,507 | 2,402 B | −24.9% | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen19.5 µs KEM encapsulate21.4 µs KEM decapsulate23.8 µs Classical keygen18.3 µs × 2 — client and server36.7 µs Classical derive60.2 µs × 2 — client and server120.5 µs Total221.9 µs
OQS_DIST_BUILD dispatch · kyber768/falcon AVX2 · SHA3 AVX512VLCPU steal 0.5714%run 7e3d474 ↗SecP256r1MLKEM768 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| X25519classical baseline | 279.6 µs | 286.1 µs | 318.6 µs | 347.8 µs | 3.35× | 3,577 | 64 B | baseline | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Classical keygen73.7 µs × 2 — client and server147.3 µs Classical derive66.1 µs × 2 — client and server132.2 µs Total279.6 µs
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| X25519MLKEM768vs X25519 | 290.2 µs | 266.1 µs | 334.1 µs | 691.5 µs | 23.84× | 3,446 | 2,336 B | −7.0% | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen32.9 µs KEM encapsulate36.0 µs KEM decapsulate43.0 µs Classical keygen48.5 µs × 2 — client and server96.9 µs Classical derive40.7 µs × 2 — client and server81.4 µs Total290.2 µs
OQS_DIST_BUILD dispatch · kyber768/falcon AVX2 · SHA3 AVX512VLCPU steal 0.5714%run 7e3d474 ↗X25519MLKEM768 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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% | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
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 | 184.1 µs | 161.6 µs | 241.1 µs | 272.8 µs | 4.11× | 5,430 | 64 B | baseline | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Classical keygen49.9 µs × 2 — client and server99.8 µs Classical derive42.2 µs × 2 — client and server84.3 µs Total184.1 µs
OQS_DIST_BUILD dispatch · kyber768/falcon AVX2 · SHA3 AVX512VLCPU steal 1%run 7e3d474 ↗curve25519-sha256 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mlkem768x25519-sha256vs curve25519-sha256 | 347.3 µs | 335.9 µs | 398.4 µs | 484.7 µs | 3.37× | 2,879 | 2,336 B | +107.9% | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KEM keygen32.1 µs KEM encapsulate35.7 µs KEM decapsulate36.8 µs Classical keygen74.2 µs × 2 — client and server148.5 µs Classical derive47.1 µs × 2 — client and server94.3 µs Total347.3 µs
OQS_DIST_BUILD dispatch · kyber768/falcon AVX2 · SHA3 AVX512VLCPU steal 1%run 7e3d474 ↗mlkem768x25519-sha256 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ML-DSA-44 | 54.8 µs | 100.8 µs | 37.0 µs | 1.28 KB | 2.36 KB | Lattice | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| ML-DSA-65 | 59.9 µs | 168.8 µs | 56.5 µs | 1.91 KB | 3.23 KB | Lattice | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| ML-DSA-87 | 77.5 µs | 238.3 µs | 76.3 µs | 2.53 KB | 4.52 KB | Lattice | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| Falcon-512 | 9.57 ms | 359.9 µs | 78.9 µs | 897 B | 752 B | Lattice | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| Falcon-1024 | 29.96 ms | 697.9 µs | 147.1 µs | 1.75 KB | 1.43 KB | Lattice | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| SLH_DSA_PURE_SHAKE_128S | 181.51 ms | 1.412 s | 1.42 ms | 32 B | 7.67 KB | Hash | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
| SLH_DSA_PURE_SHAKE_128F | 4.92 ms | 66.42 ms | 4.18 ms | 32 B | 16.69 KB | Hash | ||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
AES-256-GCMx86_6416,384 B payload · 32 B key · 12 B nonce · 16 B tag
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 | 9.3 µs | 9.2 µs | 9.6 µs | 20.2 µs | 1.7 µs | 6.8 µs | 40.3 µs | 1,000 |
| Decrypt | 9.4 µs | 9.2 µs | 9.6 µs | 20.7 µs | 1.8 µs | 7.8 µs | 40.3 µs | 1,000 |
How the handshake figure is builtThe handshake mean is composed, not timed end to end: each phase is measured in its own thousand-iteration loop and the handshake figure is their sum, with the classical keygen and derive counted twice because both parties perform them. That identity holds across every committed suite to within 0.002%, and the smoke test fails the build if it stops holding. It is why the phase bars add to exactly 100% — they are the measurement, not an attribution over it.
What these benchmarks do not measureThese are composed handshakes sized on the wire. They are not packet captures: packets per handshake, initial congestion window effects, connections per core under real concurrency, and per-connection memory are not measured here and are not inferable from this data. Where those numbers matter to a capacity decision, they need their own instrument — naming the gap is more useful than estimating across it.
Take the data
Every figure traces to a run.
Clone the harness and you should reproduce these within run-to-run variance.