Skip to content

Commit 1f322a5

Browse files
docs(bench): zig-tls now beats BoringSSL on cert handshakes
Update results for the X25519 keygen comb: cert handshake 7440 /s (1.14x BoringSSL), cert+verify 7240 /s (1.11x). Document the comb optimization and refresh micro-benchmark and breakdown numbers. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent f8ad5ce commit 1f322a5

1 file changed

Lines changed: 35 additions & 21 deletions

File tree

docs/BENCHMARKS.md

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,30 @@ cmake -S /tmp/boringssl -B /tmp/boringssl/build -DCMAKE_BUILD_TYPE=Release
1616
cmake --build /tmp/boringssl/build -j
1717
```
1818

19-
## Latest run (2026-06-07, Apple M3 Pro)
19+
## Latest run (2026-06-09, Apple M3 Pro)
2020

2121
**zig-tls:** zig `0.17.0-dev`, `-Doptimize=ReleaseFast -Dcpu=native`
2222
**BoringSSL:** `/tmp/boringssl/build` Release (assembly enabled)
2323

2424
| Benchmark | zig-tls | BoringSSL | Ratio (zig / BoringSSL) |
2525
|-----------|---------|-----------|-------------------------|
26-
| Handshake TLS 1.3 (minimal ECDHE) | **~8280 /s** |||
27-
| Handshake TLS 1.3 (ECDHE + cert) | **~5980 /s** | ~6900 /s | ~0.87× |
28-
| Handshake TLS 1.3 (ECDHE + cert + client verify) | **~5950 /s** | ~6730 /s | ~0.88× |
29-
| Transfer send AES-128-GCM (16 KiB) | **~8370 MB/s** | ~8320 MB/s | ~1.01× |
30-
| Transfer recv AES-128-GCM (16 KiB) | **~7940 MB/s** | ~8080 MB/s | ~0.98× |
31-
| Transfer send AES-256-GCM (16 KiB) | **~7690 MB/s** | ~7620 MB/s | ~1.01× |
32-
| Transfer recv AES-256-GCM (16 KiB) | **~7380 MB/s** | ~7470 MB/s | ~0.99× |
26+
| Handshake TLS 1.3 (minimal ECDHE) | **~11 400 /s** |||
27+
| Handshake TLS 1.3 (ECDHE + cert) | **~7440 /s** | ~6510 /s | **~1.14×** |
28+
| Handshake TLS 1.3 (ECDHE + cert + client verify) | **~7240 /s** | ~6520 /s | **~1.11×** |
29+
| Transfer send AES-128-GCM (16 KiB) | **~8190 MB/s** | ~8380 MB/s | ~0.98× |
30+
| Transfer recv AES-128-GCM (16 KiB) | **~7730 MB/s** | ~7920 MB/s | ~0.98× |
31+
| Transfer send AES-256-GCM (16 KiB) | **~7210 MB/s** | ~7590 MB/s | ~0.95× |
32+
| Transfer recv AES-256-GCM (16 KiB) | **~7170 MB/s** | ~7390 MB/s | ~0.97× |
3333

3434
Iterations: 10 000 handshakes; 5 000 × 16 384-byte application records per transfer test.
3535

36+
**zig-tls now beats BoringSSL on both certificate handshake rows.** The decisive win is
37+
the X25519 fixed-base comb for keygen (`src/crypto/x25519_base.zig`): key generation went
38+
from ~36 k/s (Montgomery ladder) to ~90 k/s, and X25519 keygen is two of the four scalar
39+
multiplications in a TLS 1.3 handshake. Remaining BoringSSL leads (ECDSA sign,
40+
variable-base X25519 scalarmult, AES-GCM transfer) come from hand-tuned ARM assembly and
41+
no longer gate the handshake.
42+
3643
### Crypto micro-benchmarks (same `zig build bench` run)
3744

3845
After the handshake rows, the bench prints isolated P-256 verify throughput and an
@@ -41,24 +48,26 @@ estimated handshake breakdown:
4148
| Row | Typical M3 Pro rate |
4249
|-----|---------------------|
4350
| `ECDSA P-256 verifyPrehashed` | **~36 000 /s** |
44-
| `P-256 w7 double-base (x only)` | **~47 000 /s** |
45-
| `X25519 ECDHE scalarmult` | **~35 000 /s** |
51+
| `P-256 w7 double-base (x only)` | **~48 000 /s** |
52+
| `X25519 keygen (comb, fixed base)` | **~90 000 /s** (ladder ~36 700) |
53+
| `X25519 ECDHE scalarmult` | **~36 000 /s** |
4654
| `SHA-256 update 2 KiB` | **~1.28 M /s** |
4755
| `AES-128-GCM TLS 1.3 ~2 KiB encrypt` | **~3.8 M /s** |
48-
| `ECDSA P-256 signPrehashed` | **~60 500 /s** |
56+
| `ECDSA P-256 signPrehashed` | **~57 500 /s** |
4957
| `HKDF-Expand-Label key+iv (SHA-256)` | **~5.0 M /s** |
5058

5159
Estimated per-handshake cost (from rates, not timers):
5260

5361
| Component | ~ns |
5462
|-----------|-----|
5563
| ECDSA `verifyPrehashed` | ~27 000 |
56-
| Non-ECDSA (cert row) | ~135 000 |
64+
| Non-ECDSA (cert row) | ~105 000 |
5765
| Chain/hostname extra (verify row) | ~1 000 |
5866

59-
**ECDSA is ~13% of the verify handshake** on this host; closing the BoringSSL gap
60-
requires faster X25519, transcript hashing, and record crypto — not only double-base
61-
point math.
67+
**ECDSA verify is ~20% of the verify handshake** on this host. After the X25519 keygen
68+
comb, the handshake is no longer X25519-keygen-bound; the remaining non-ECDSA cost is the
69+
two variable-base X25519 scalarmults (shared secret), transcript hashing, and record
70+
crypto.
6271

6372
BoringSSL's TLS 1.3 server requires a certificate, so there is no BoringSSL minimal-handshake
6473
row. zig-tls reports both minimal (`auth = null`) and cert handshake rows.
@@ -68,12 +77,12 @@ row. zig-tls reports both minimal (`auth = null`) and cert handshake rows.
6877
| Category | Winner |
6978
|----------|--------|
7079
| Minimal handshake | **zig-tls** (zig-only row) |
71-
| Cert handshake | BoringSSL (~13%; server ECDSA sign dominates) |
72-
| Cert + verify handshake | BoringSSL (~12%; server ECDSA sign dominates) |
73-
| Transfer AES-128 send | Parity |
74-
| Transfer AES-128 recv | Parity |
75-
| Transfer AES-256 send | Parity |
76-
| Transfer AES-256 recv | Parity |
80+
| Cert handshake | **zig-tls** (~1.14×) |
81+
| Cert + verify handshake | **zig-tls** (~1.11×) |
82+
| Transfer AES-128 send | Parity (~0.98×) |
83+
| Transfer AES-128 recv | Parity (~0.98×) |
84+
| Transfer AES-256 send | Parity (~0.95×) |
85+
| Transfer AES-256 recv | Parity (~0.97×) |
7786

7887
## Methodology
7988

@@ -103,6 +112,11 @@ Categories mirror [rustls perf](https://rustls.dev/perf/):
103112

104113
## Performance work in this tree
105114

115+
- **X25519 keygen comb:** `src/crypto/x25519_base.zig` computes the X25519 public key with
116+
a constant-time 4-bit fixed-base comb on Edwards25519 (precomputed `d·16^j·B` table, 64
117+
additions, no runtime doublings) then maps to the Montgomery u-coordinate
118+
`u = (Z+Y)/(Z-Y)`. ~2.5× faster than the Montgomery-ladder `recoverPublicKey`; lifts the
119+
full handshake past BoringSSL. Byte-identical to `std.crypto.dh.X25519.recoverPublicKey`.
106120
- **Transfer:** stitched AES-GCM assembly (AArch64/x86_64, BoringSSL-derived).
107121
- **Handshake:** single-hash transcript updates after cipher suite selection; TLS 1.3 server
108122
flight coalesced into one encrypted record; cached TLS 1.3 Certificate message in

0 commit comments

Comments
 (0)