Skip to content

rustls-provider: a rustls CryptoProvider backed by verified-garbage, and benchmarks against aws-lc-rs - #991

Draft
alex wants to merge 29 commits into
mainfrom
claude/cool-dijkstra-o2qo01
Draft

alex wants to merge 29 commits into
mainfrom
claude/cool-dijkstra-o2qo01

Conversation

@alex

@alex alex commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

What

A new package, rustls-provider/ (rustls-verified-garbage): a rustls CryptoProvider built on verified-garbage, with tooling to benchmark it against rustls's aws-lc-rs provider and to rerun those benchmarks.

It is a separate package, like bench/, with its own [workspace]. The library's tests, lints and coverage never build it. Nothing under src/, tests/, lean/, Spec/ or TCB/ changes. It builds against rustls from git at a pinned revision (91aebe5d).

The provider

It covers what aws-lc-rs's provider does:

  • TLS 1.3 suites: AES-128-GCM, AES-256-GCM and ChaCha20-Poly1305.
  • TLS 1.2 suites: ECDHE-ECDSA and ECDHE-RSA with each of those three.
  • Key exchange: X25519MLKEM768 (the default and preferred), X25519, secp256r1 and secp384r1; also SECP256R1MLKEM768, MLKEM768 and MLKEM1024.
  • Signing keys:
  • Verification: every algorithm aws-lc-rs's provider verifies.
  • Session tickets: AES-256-GCM.
  • QUIC: packet protection with each TLS 1.3 suite's AEAD, and header protection with AES-ECB (aes_ecb::AesEcb) or ChaCha20 (RFC 9001 §5.4).
  • DER: keys and signatures are parsed and written with rust-asn1.

AES-GCM records of 512 bytes or more are sealed out of place with AesGcm::encrypt (#1228), reading the payload where it is. Shorter ones, and ChaCha20-Poly1305 records, are copied and encrypted in place, which measured faster (see bench/RESULTS.md).

Not supported:

  • HPKE, so there is no Encrypted Client Hello.
  • Compressed EC public keys in certificates.

Testing

bench/setup-rustls.sh checks out rustls and applies bench/rustls.patch. The patch adds a tests_with_verified_garbage module to rustls's API test suite, and a verified-garbage provider and a provider-primitives binary to rustls-bench.

  • rustls's API suite: all 279 tests pass, QUIC's included.
  • tests/records.rs: every suite seals contiguous and fragmented plaintext identically and opens what it sealed.
  • Wycheproof: cargo test --release with WYCHEPROOF_ROOT checks every verification algorithm. Wycheproof has no vectors for P-521 with SHA-256 or SHA-384, so those two combinations are untested.

Benchmarks

bench/run.sh [rounds] reruns everything, each benchmark pinned to one CPU:

  • rustls-bench's whole suite, for both providers;
  • provider-primitives, which times each provider's primitives through the rustls traits;
  • bench/aws-lc-compare, which times each library's primitives through its own API.

bench/summarize.py reduces the runs. bench/RESULTS.md has the runs, the analysis and the history.

Every ratio is verified-garbage's speed relative to aws-lc-rs's (below 1 is slower). The detailed run is main at 93f5444, on a Xeon with SHA-NI, IFMA and VAES:

Scenario Speed (first run in brackets)
ECDSA P-256 full handshakes 1.20–1.28 (0.10–0.24)
RSA-2048 full handshakes 1.05–1.08 (0.42–0.93)
Ed25519 full handshakes 1.08–1.34 (0.73–0.83)
Resumed handshakes 1.04–1.43
Bulk AES-GCM 0.87–0.94 (16 KiB records alone: 0.97–1.02)
Bulk ChaCha20-Poly1305 1.24–1.28

The latest run is on main at b5b6785, on a Cascade Lake-class CPU (no IFMA or VAES) and a noisy host:

  • RSA verification now reaches 0.91–0.99, because building a public key costs nothing since RSA public keys: compute the modulus' values at the key's first operation #1314.
  • P-384 is ahead of aws-lc everywhere.
  • Without IFMA, some things trail:
    • RSA private-key operations: 0.6–0.86.
    • Ed25519 signing: 0.79.
    • ChaCha20-Poly1305 under 1 KiB: 0.58–0.84.
    • The out-of-place AEADs: slower than copying and encrypting in place.

Separate sessions are working on those in the library.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DAf76RQfGxGymBaZASPY7q

@alex
alex force-pushed the claude/cool-dijkstra-o2qo01 branch from cef0cfc to 76e88c0 Compare October 6, 2026 00:34
@reaperhulk

Copy link
Copy Markdown
Member

refresh these benchmarks please

Copy link
Copy Markdown
Member

Refreshed the benchmarks against current main, faef711, using this PR's provider/harness unchanged at 7aea648.

Ran BENCH_CPU=2 sh rustls-provider/bench/run.sh 5: five rounds per provider for the full buffered rustls-bench suite, plus three rounds each of provider-primitives, aws-lc-compare, and the AEAD size sweep. rustls remains pinned to 91aebe5d, aws-lc-rs is 1.18.1, Rust is 1.99.0 (LLVM 23.1.1), with the harness's LTO build profiles.

All ratios below are verified-garbage's speed relative to aws-lc-rs; higher is better. Handshake ranges span TLS 1.2 and 1.3 and are geometric means across cipher suites, after taking per-scenario medians.

Benchmark Recorded in PR body/results (36ff93f) Current main
P-256 full handshake, client 0.52–0.60× 0.69–0.77×
P-256 full handshake, server 0.74–0.91× 1.09–1.13×
P-256 mutual handshake, client / server 0.54–0.60× / 0.54–0.63× 0.73–0.80× / 0.77–0.84×
RSA-2048 full handshake, client 0.48–0.55× 0.76–0.85×
RSA-2048 full handshake, server 0.58–0.59× 0.94–0.98×
RSA-2048 mutual handshake, client / server 0.55–0.56× / about 0.56× 0.84–0.91× / 0.88–0.92×
Ed25519 full handshake, client 0.64–0.73× about 0.91×
Ed25519 full handshake, server 0.76–0.91× 1.19–1.23×
Ed25519 mutual handshake, client / server 0.65–0.70× / 0.69–0.72× about 0.94× / 0.96–1.00×
Resumed handshakes, these three certificate types 0.94–1.58× 1.13–1.56×
TLS 1.3 bulk AES-GCM, 16 KiB, send/receive 0.88–0.93× 0.82–0.94×
TLS 1.3 bulk ChaCha20-Poly1305, 16 KiB, send/receive 1.37–1.39× 1.07–1.09×

Current resumed-handshake category ratios are 1.16–1.37× for TLS 1.3 and 1.13–1.56× for TLS 1.2.

Selected provider-primitives medians (through rustls traits):

Operation aws-lc-rs verified-garbage Current speed Recorded speed
X25519 keygen 8.05 µs 6.98 µs 1.15× 0.54×
X25519MLKEM768 client share 21.26 µs 21.81 µs 0.98× 0.73×
X25519MLKEM768 server (encaps + DH) 49.30 µs 44.06 µs 1.12× 0.83×
X25519MLKEM768 client finish 43.86 µs 40.01 µs 1.10× 1.00×
P-256 sign / verify 15.60 / 51.11 µs 18.08 / 82.95 µs 0.86 / 0.62× 0.56 / 0.44×
P-384 sign / verify 83.45 / 199.59 µs 109.31 / 456.05 µs 0.76 / 0.44× 0.77 / 0.45×
P-521 sign / verify 167.32 / 345.62 µs 500.98 / 2121.47 µs 0.33 / 0.16× 0.04 / 0.05×
Ed25519 sign / verify 9.05 / 38.26 µs 8.49 / 46.73 µs 1.07 / 0.82× 0.55 / 0.57×
RSA-2048 PSS sign / verify 246.31 / 18.48 µs 270.98 / 34.09 µs 0.91 / 0.54× 0.57 / 0.25×
RSA-3072 PSS sign / verify 720.34 / 38.55 µs 2877.89 / 69.01 µs 0.25 / 0.56× 0.59 / 0.20×
RSA-4096 PSS sign / verify 1531.77 / 66.88 µs 6239.60 / 117.85 µs 0.25 / 0.57× 0.60 / 0.19×

Improvements with relevant PRs landed since the recorded run

These are source-supported explanations, not isolated per-PR speedup measurements: I did not rerun 36ff93f on this same machine, so the exact software contribution is not separated from hardware.

Differences likely driven substantially by CPU

The recorded run used a Cascade Lake-class Intel Xeon without IFMA, VAES, VPCLMULQDQ, or SHA-NI. This run used an AMD EPYC 9V74 with all four, pinned to CPU 2. Both providers dispatch differently.

Typical across-round handshake variation was about 3–4% (90th percentile roughly 5–7%, with larger outliers). Ratios close to 1×, including modest ChaCha bulk advantages, should be read cautiously.

The full benchmark command completed successfully. These are native wall-clock measurements; no instruction-count measurements or separate correctness suite were run.

@alex
alex force-pushed the claude/cool-dijkstra-o2qo01 branch from 7aea648 to a0f24b5 Compare October 6, 2026 22:45

Copy link
Copy Markdown
Member

Refreshed against main at 5a8a04e8b84489c6a54cc8c154df6d50197cca95 (latest when this run started), and compared with the last benchmark comment, which used faef711d1280b84fceca6a1c5389618e61f3a6c2.

The largest gains versus that comment are P-521 signing/verification (5.87× / 5.36×), RSA-3072 signing (3.41×), and Ed25519 verification (2.29×). P-256 and Ed25519 full handshakes are now faster than aws-lc-rs. Bulk record throughput is broadly unchanged.

Ran BENCH_CPU=2 sh rustls-provider/bench/run.sh 5 successfully on both revisions: five rounds per provider of the full buffered TLS suite, plus three rounds each of provider-primitives, direct-library primitives, and the AEAD size sweep. Both use this PR’s harness at a0f24b5e9255e1b2e0d321cf79a6a17e1ccd7b31; compared with the previous harness at 7aea648a, only results documentation and two RSA output labels changed, not measured code.

Environment: AMD EPYC 9V74, pinned to CPU 2, with SHA-NI, IFMA, VAES and VPCLMULQDQ; Rust 1.99.0 (b940084d7, LLVM 23.1.1); rustls 91aebe5d; aws-lc-rs 1.18.1; the harness’s optimized LTO profiles. Dependency lockfiles match between the two reruns, and the direct-library RSA benchmarks use the same generated keys. This is the same CPU model and Rust version as the last comment.

TLS throughput relative to aws-lc-rs (higher is better). Medians per scenario, then geometric means across cipher suites; handshake ranges span TLS 1.2 and 1.3.

Benchmark Last comment Latest main
P-256 full, client 0.69–0.77× 1.21–1.23×
P-256 full, server 1.09–1.13× 1.32–1.36×
P-256 mutual, client 0.73–0.80× 1.20–1.24×
P-256 mutual, server 0.77–0.84× 1.23×
RSA-2048 full, client 0.76–0.85× 0.90–1.01×
RSA-2048 full, server 0.94–0.98× 0.97–1.04×
RSA-2048 mutual, client 0.84–0.91× 0.96–0.99×
RSA-2048 mutual, server 0.88–0.92× 0.97–1.01×
Ed25519 full, client about 0.91× 1.49–1.69×
Ed25519 full, server 1.19–1.23× 1.33–1.36×
Ed25519 mutual, client about 0.94× 1.45–1.62×
Ed25519 mutual, server 0.96–1.00× 1.46–1.58×
Resumed, these three certificate types 1.13–1.56× 1.13–1.57×
TLS 1.3 bulk AES-GCM, 16 KiB, send/receive 0.82–0.94× 0.86–0.97×
TLS 1.3 bulk ChaCha, 16 KiB, send/receive 1.07–1.09× 1.07–1.10×

Provider primitives through rustls traits, median microseconds per operation. Speedup is the last comment’s VG time divided by current VG time; it is distinct from the final column’s comparison with aws-lc-rs.

Operation Last comment, VG µs Latest VG µs Speedup vs comment Latest speed vs aws-lc-rs
X25519 keygen 6.98 5.75 1.21× 1.37×
X25519MLKEM768 client share 21.81 18.02 1.21× 1.18×
X25519MLKEM768 server 44.06 36.36 1.21× 1.31×
X25519MLKEM768 client finish 40.01 32.92 1.22× 1.30×
ECDSA P256: sign 18.08 13.87 1.30× 1.15×
ECDSA P256: verify 82.95 48.14 1.72× 1.10×
ECDSA P384: sign 109.31 51.28 2.13× 1.69×
ECDSA P384: verify 456.05 303.12 1.50× 0.69×
ECDSA P521: sign 500.98 85.34 5.87× 2.01×
ECDSA P521: verify 2121.47 395.72 5.36× 0.89×
Ed25519: sign 8.49 7.24 1.17× 1.26×
Ed25519: verify 46.73 20.43 2.29× 1.90×
RSA-2048: sign 270.98 261.44 1.04× 0.99×
RSA-2048: verify 34.09 27.73 1.23× 0.70×
RSA-3072: sign 2877.89 844.59 3.41× 0.87×
RSA-3072: verify 69.01 57.85 1.19× 0.69×
RSA-4096: sign 6239.60 2264.40 2.76× 0.68×
RSA-4096: verify 117.85 95.29 1.24× 0.69×

Same-machine check against the old revision: I also reran faef711d on this VM with the same harness and settings. Full-handshake throughput below is VG itself (handshakes/s), not a ratio to aws-lc-rs. Values are geometric means across cipher suites after per-scenario medians.

Full handshake Old main, TLS 1.2 / 1.3 Latest main, TLS 1.2 / 1.3 Throughput gain
P-256 client 3,330 / 2,757 5,505 / 4,308 +65% / +56%
P-256 server 17,077 / 10,412 20,098 / 12,371 +18% / +19%
P-384 client (TLS 1.2 only) 665 1,074 +61%
P-384 server (TLS 1.2 only) 6,206 10,538 +70%
Ed25519 client 5,245 / 4,194 9,750 / 6,752 +86% / +61%
Ed25519 server 20,122 / 12,207 22,320 / 13,765 +11% / +13%
RSA-2048 client 6,821 / 5,080 7,942 / 6,089 +16% / +20%
RSA-2048 server 3,083 / 2,728 3,177 / 2,999 +3% / +10%

The same-machine primitive comparison confirms 5.89× / 5.37× for P-521 sign/verify, 2.30× for Ed25519 verification, and 3.36× for RSA-3072 signing.

The direct-library benchmark also shows 1.35–1.45× faster AES-GCM sealing at 16 bytes and 1 KiB, despite broadly unchanged 16 KiB TLS bulk throughput. One adverse result: RSA-2048 private-key loading increased from 269.81 to 315.94 µs (+17% time), but the three-pass ranges overlap (old 268–296 µs; new 274–344 µs), so this is inconclusive rather than an established regression.

Remaining gaps include P-384 verification/ECDH, P-256 ECDH, RSA verification, and bulk AES-GCM. The large-key RSA gain is consistent with #1096 adding the IFMA private-key path for 3072/4096-bit keys; recent P-256/P-384/P-521 and Ed25519 changes are also present. This measures their combined result, not isolated per-PR contributions.

Measurement limits: these are native wall-clock measurements, with current and old revisions run in sequential blocks. Typical TLS scenario variation across samples was about 4–5%; differences below roughly 10% deserve caution. Current RSA-4096 signing varied from 1.69–2.51 ms across its three passes (median 2.26 ms, versus 6.24 ms in the last comment). The benchmark runs completed with their built-in handshake/verification/decryption checks; no separate correctness suite or instruction-count measurement was run.

Copy link
Copy Markdown
Member

Reran the complete benchmark suite against main 3a23aa77dc74fc8721005dfa07bd3c0ae639666f, latest when the run started, with the provider/harness unchanged from this PR at f21934490208b45e6a0aa0f1d2129c0ad2a94117.

Command: BENCH_CPU=2 sh rustls-provider/bench/run.sh 5. All five alternating rounds per provider of the buffered TLS suite, plus three rounds each of provider primitives, direct-library primitives, and the AEAD size sweep completed successfully.

Environment: AMD EPYC 9V74, x86-64 Linux VM, pinned to CPU 2, with IFMA, SHA-NI, VAES and VPCLMULQDQ; Rust 1.99.0 (b940084d7, LLVM 23.1.1); rustls 91aebe5d6d8220f156bd837eb2c269eb87e9f4a0; aws-lc-rs 1.18.1. The harness uses optimized builds with LTO and one codegen unit. No custom target-CPU flags were added.

Ratios are VG speed / aws-lc-rs speed; higher is better. Timing ratios are aws-lc-rs time / VG time. TLS values use the harness's median per scenario, then geometric means across cipher suites. Handshake ranges span TLS 1.2 and 1.3; P-384 is TLS 1.2 only.

On this machine, VG full-handshake throughput is 15–35% higher for P-256 and 39–66% higher for Ed25519 than aws-lc-rs. RSA-2048 is near parity. TLS 1.3 bulk AES-GCM reaches 0.90–0.96× at 16 KiB, and ChaCha20-Poly1305 1.14×. RSA signing and private-key loading remain slower in the primitive measurements.

TLS handshakes

Certificate Full client Full server Mutual client Mutual server Resumed TLS 1.3 Resumed TLS 1.2
P-256 1.15–1.21× 1.34–1.35× 1.19× 1.19–1.21× 1.30–1.45× 1.19–1.47×
P-384 1.22× 1.77× 1.31× 1.35× — 1.17–1.53×
RSA-2048 0.97–1.04× 1.05–1.08× 0.98× 0.98× 1.30–1.45× 1.13–1.69×
Ed25519 1.64–1.66× 1.39–1.44× 1.51–1.53× 1.56–1.76× 1.23–1.37× 1.17–1.50×

Absolute full-handshake throughput (handshakes/s; geometric means across cipher suites):

Certificate / TLS Client aws-lc-rs Client VG Server aws-lc-rs Server VG
P-256 / 1.2 4,509 5,188 14,793 19,841
P-256 / 1.3 3,510 4,234 8,977 12,115
P-384 / 1.2 1,395 1,706 6,295 11,114
RSA-2048 / 1.2 8,549 8,318 3,136 3,296
RSA-2048 / 1.3 5,833 6,090 2,760 2,985
Ed25519 / 1.2 5,790 9,591 15,389 21,407
Ed25519 / 1.3 4,258 6,984 9,674 13,922

TLS 1.3 bulk

Throughput in MiB/s (the harness labels this MB/s); each send/receive value is a separate scenario. Default fragmentation produces 16 KiB records.

Cipher / record size / direction aws-lc-rs VG VG relative speed
AES_128_GCM / 10,000 B / recv 6,936 6,686 0.96×
AES_128_GCM / 10,000 B / send 7,979 6,810 0.85×
AES_128_GCM / 16 KiB / recv 7,461 7,034 0.94×
AES_128_GCM / 16 KiB / send 8,605 7,777 0.90×
AES_256_GCM / 10,000 B / recv 6,456 6,049 0.94×
AES_256_GCM / 10,000 B / send 7,205 6,290 0.87×
AES_256_GCM / 16 KiB / recv 6,771 6,519 0.96×
AES_256_GCM / 16 KiB / send 7,757 6,986 0.90×
CHACHA20_POLY1305 / 10,000 B / recv 2,072 2,195 1.06×
CHACHA20_POLY1305 / 10,000 B / send 2,097 2,217 1.06×
CHACHA20_POLY1305 / 16 KiB / recv 2,099 2,390 1.14×
CHACHA20_POLY1305 / 16 KiB / send 2,090 2,381 1.14×
Provider primitives through rustls traits: all updated values

Median nanoseconds per operation across three passes. Time Δ = (VG − aws-lc-rs) / aws-lc-rs; negative means VG takes less time. The harness warms up and takes an internal median of seven batches for provider primitives or nine batches for direct-library measurements.

Operation aws-lc-rs ns VG ns VG relative speed Time Δ
kx X25519MLKEM768: client start 21,322 18,971 1.12× -11.0%
kx X25519MLKEM768: server start_and_complete 52,760 41,013 1.29× -22.3%
kx X25519MLKEM768: client complete 51,080 36,421 1.40× -28.7%
kx X25519: client start 8,324 6,054 1.37× -27.3%
kx X25519: server start_and_complete 33,818 25,973 1.30× -23.2%
kx X25519: client complete 25,821 20,192 1.28× -21.8%
kx secp256r1: client start 9,669 11,027 0.88× +14.0%
kx secp256r1: server start_and_complete 58,823 59,987 0.98× +2.0%
kx secp256r1: client complete 49,189 49,222 1.00× +0.1%
kx secp384r1: client start 53,157 36,898 1.44× -30.6%
kx secp384r1: server start_and_complete 199,852 231,511 0.86× +15.8%
kx secp384r1: client complete 163,044 204,798 0.80× +25.6%
kx MLKEM768: client start 14,414 12,436 1.16× -13.7%
kx MLKEM768: server start_and_complete 14,833 13,078 1.13× -11.8%
kx MLKEM768: client complete 17,185 15,359 1.12× -10.6%
Rsa2048: load key 171,052 358,056 0.48× +109.3%
Rsa2048: sign (RSA_PSS_SHA256) 256,255 343,459 0.75× +34.0%
Rsa2048: verify (RSA_PSS_SHA256) 19,380 26,439 0.73× +36.4%
Rsa3072: load key 339,295 1,162,893 0.29× +242.7%
Rsa3072: sign (RSA_PSS_SHA256) 755,408 1,130,491 0.67× +49.7%
Rsa3072: verify (RSA_PSS_SHA256) 40,605 52,710 0.77× +29.8%
Rsa4096: load key 528,623 2,311,098 0.23× +337.2%
Rsa4096: sign (RSA_PSS_SHA256) 1,526,148 2,500,826 0.61× +63.9%
Rsa4096: verify (RSA_PSS_SHA256) 68,061 97,344 0.70× +43.0%
EcdsaP256: load key 22,654 12,745 1.78× -43.7%
EcdsaP256: sign (ECDSA_NISTP256_SHA256) 17,448 13,800 1.26× -20.9%
EcdsaP256: verify (ECDSA_NISTP256_SHA256) 56,435 51,505 1.10× -8.7%
EcdsaP384: load key 166,251 36,353 4.57× -78.1%
EcdsaP384: sign (ECDSA_NISTP384_SHA384) 84,593 42,697 1.98× -49.5%
EcdsaP384: verify (ECDSA_NISTP384_SHA384) 201,614 169,313 1.19× -16.0%
EcdsaP521: load key 326,430 80,593 4.05× -75.3%
EcdsaP521: sign (ECDSA_NISTP521_SHA512) 174,025 90,524 1.92× -48.0%
EcdsaP521: verify (ECDSA_NISTP521_SHA512) 378,523 327,959 1.15× -13.4%
Ed25519: load key 41,763 7,591 5.50× -81.8%
Ed25519: sign (ED25519) 9,796 7,589 1.29× -22.5%
Ed25519: verify (ED25519) 38,275 20,474 1.87× -46.5%
TLS13_AES_128_GCM_SHA256 seal 16384 1,563 1,570 1.00× +0.4%
TLS13_AES_128_GCM_SHA256 open 16384 (+copy) 1,724 1,677 1.03× -2.7%
TLS13_AES_128_GCM_SHA256 seal 1024 257 300 0.86× +16.7%
TLS13_AES_128_GCM_SHA256 open 1024 (+copy) 276 248 1.11× -10.1%
TLS13_AES_256_GCM_SHA384 seal 16384 1,804 1,840 0.98× +2.0%
TLS13_AES_256_GCM_SHA384 open 16384 (+copy) 1,989 1,944 1.02× -2.3%
TLS13_AES_256_GCM_SHA384 seal 1024 283 287 0.99× +1.4%
TLS13_AES_256_GCM_SHA384 open 1024 (+copy) 295 244 1.21× -17.3%
TLS13_CHACHA20_POLY1305_SHA256 seal 16384 6,705 6,610 1.01× -1.4%
TLS13_CHACHA20_POLY1305_SHA256 open 16384 (+copy) 7,062 6,418 1.10× -9.1%
TLS13_CHACHA20_POLY1305_SHA256 seal 1024 752 811 0.93× +7.8%
TLS13_CHACHA20_POLY1305_SHA256 open 1024 (+copy) 631 807 0.78× +27.9%
TLS13_AES_128_GCM_SHA256 HKDF extract 54 417 0.13× +672.2%
TLS13_AES_128_GCM_SHA256 HKDF expand (one block) 305 200 1.52× -34.4%
TLS13_AES_128_GCM_SHA256 transcript hash 2.3 KB + fork 1,653 1,592 1.04× -3.7%
TLS13_AES_256_GCM_SHA384 HKDF extract 56 1,597 0.04× +2751.8%
TLS13_AES_256_GCM_SHA384 HKDF expand (one block) 1,141 569 2.01× -50.1%
TLS13_AES_256_GCM_SHA384 transcript hash 2.3 KB + fork 4,524 3,811 1.19× -15.8%
ticket encrypt 200 B 996 209 4.77× -79.0%
ticket decrypt 200 B 445 181 2.46× -59.3%
Direct-library primitives: all updated values

Median nanoseconds per operation across three passes. Time Δ = (VG − aws-lc-rs) / aws-lc-rs; negative means VG takes less time. The harness warms up and takes an internal median of seven batches for provider primitives or nine batches for direct-library measurements.

Direct-library ECDH includes key generation on the aws-lc-rs side, as labeled. VG-only RSA breakdown rows isolate parts of verification and are not equivalent to aws-lc-rs whole verification; their comparative columns are omitted. memcpy is one shared copy measurement. Out-of-place AES-GCM compares VG gathering two slices against aws-lc-rs sealing the same byte count in place.

Operation aws-lc-rs ns VG ns VG relative speed Time Δ
AES-128-GCM seal in place 0 B 94 65 1.45× -30.9%
AES-128-GCM seal in place 16 B 106 68 1.56× -35.8%
AES-128-GCM seal in place 256 B 129 144 0.90× +11.6%
AES-128-GCM seal in place 1024 B 239 187 1.28× -21.8%
AES-128-GCM seal in place 4096 B 494 468 1.06× -5.3%
AES-128-GCM seal in place 16384 B 1,519 1,489 1.02× -2.0%
AES-128-GCM seal out of place 0+1 B 108 117 0.92× +8.3%
AES-128-GCM seal out of place 16+1 B 118 142 0.83× +20.3%
AES-128-GCM seal out of place 256+1 B 158 160 0.99× +1.3%
AES-128-GCM seal out of place 1024+1 B 252 233 1.08× -7.5%
AES-128-GCM seal out of place 4096+1 B 503 515 0.98× +2.4%
AES-128-GCM seal out of place 16384+1 B 1,533 1,586 0.97× +3.5%
AES-256-GCM seal in place 0 B 102 68 1.50× -33.3%
AES-256-GCM seal in place 16 B 113 73 1.55× -35.4%
AES-256-GCM seal in place 256 B 137 166 0.83× +21.2%
AES-256-GCM seal in place 1024 B 260 205 1.27× -21.2%
AES-256-GCM seal in place 4096 B 621 549 1.13× -11.6%
AES-256-GCM seal in place 16384 B 1,869 1,831 1.02× -2.0%
AES-256-GCM seal out of place 0+1 B 124 124 1.00× +0.0%
AES-256-GCM seal out of place 16+1 B 126 146 0.86× +15.9%
AES-256-GCM seal out of place 256+1 B 165 170 0.97× +3.0%
AES-256-GCM seal out of place 1024+1 B 292 261 1.12× -10.6%
AES-256-GCM seal out of place 4096+1 B 610 641 0.95× +5.1%
AES-256-GCM seal out of place 16384+1 B 1,840 1,883 0.98× +2.3%
ChaCha20-Poly1305 seal in place 0 B 173 181 0.96× +4.6%
ChaCha20-Poly1305 seal in place 16 B 182 209 0.87× +14.8%
ChaCha20-Poly1305 seal in place 256 B 285 338 0.84× +18.6%
ChaCha20-Poly1305 seal in place 1024 B 613 684 0.90× +11.6%
ChaCha20-Poly1305 seal in place 4096 B 1,872 1,743 1.07× -6.9%
ChaCha20-Poly1305 seal in place 16384 B 6,772 6,110 1.11× -9.8%
memcpy 16384 B (the ChaCha20 copy into out) — 181 — —
RSA-2048 PSS sign 259,112 322,832 0.80× +24.6%
RSA-2048 load private key 158,610 289,207 0.55× +82.3%
RSA-2048 PSS verify (parse key + verify) 19,501 25,850 0.75× +32.6%
vg RSA-2048 PublicKey::new (precomputes for verify) — 7,719 — —
vg RSA-2048 rsa_pss::verify (precomputed) — 17,188 — —
vg RSA-2048 public_op (precomputed, ADX) — 16,546 — —
RSA-3072 PSS sign 731,933 1,144,252 0.64× +56.3%
RSA-3072 load private key 313,754 1,262,278 0.25× +302.3%
RSA-3072 PSS verify (parse key + verify) 39,731 54,321 0.73× +36.7%
vg RSA-3072 PublicKey::new (precomputes for verify) — 16,725 — —
vg RSA-3072 rsa_pss::verify (precomputed) — 36,963 — —
vg RSA-3072 public_op (precomputed, ADX) — 35,644 — —
RSA-4096 PSS sign 1,604,002 2,247,252 0.71× +40.1%
RSA-4096 load private key 522,228 2,210,205 0.24× +323.2%
RSA-4096 PSS verify (parse key + verify) 66,733 93,869 0.71× +40.7%
vg RSA-4096 PublicKey::new (precomputes for verify) — 29,397 — —
vg RSA-4096 rsa_pss::verify (precomputed) — 63,557 — —
vg RSA-4096 public_op (precomputed, ADX) — 61,880 — —
P-256 keygen (fixed-base [k]G) 9,648 10,556 0.91× +9.4%
P-256 ECDH (aws: keygen + [k]P; vg: [k]P) 55,114 47,313 1.16× -14.2%
P-256 ECDSA sign 16,911 13,571 1.25× -19.8%
P-256 ECDSA verify 53,662 48,749 1.10× -9.2%
X25519 keygen (fixed-base) 8,259 5,671 1.46× -31.3%
X25519 DH (aws: keygen + DH; vg: DH) 34,447 18,153 1.90× -47.3%
Direct-library AEAD size sweep: all updated values

Median nanoseconds per operation across three passes. Time Δ = (VG − aws-lc-rs) / aws-lc-rs; negative means VG takes less time. The harness warms up and takes an internal median of seven batches for provider primitives or nine batches for direct-library measurements.

Operation aws-lc-rs ns VG ns VG relative speed Time Δ
AES-128-GCM seal in place 64 B 111 81 1.37× -27.0%
AES-128-GCM seal in place 128 B 113 115 0.98× +1.8%
AES-128-GCM seal in place 192 B 120 116 1.03× -3.3%
AES-128-GCM seal in place 256 B 135 160 0.84× +18.5%
AES-128-GCM seal in place 384 B 162 185 0.88× +14.2%
AES-128-GCM seal in place 512 B 189 136 1.39× -28.0%
AES-128-GCM seal in place 640 B 206 198 1.04× -3.9%
AES-128-GCM seal in place 768 B 208 159 1.31× -23.6%
AES-128-GCM seal in place 1024 B 234 200 1.17× -14.5%
AES-128-GCM seal in place 1088 B 249 223 1.12× -10.4%
AES-128-GCM seal in place 2048 B 325 289 1.12× -11.1%
AES-128-GCM seal out of place 64+1 B 124 172 0.72× +38.7%
AES-128-GCM seal out of place 128+1 B 128 184 0.70× +43.8%
AES-128-GCM seal out of place 192+1 B 133 228 0.58× +71.4%
AES-128-GCM seal out of place 256+1 B 162 172 0.94× +6.2%
AES-128-GCM seal out of place 384+1 B 173 246 0.70× +42.2%
AES-128-GCM seal out of place 512+1 B 224 196 1.14× -12.5%
AES-128-GCM seal out of place 640+1 B 216 253 0.85× +17.1%
AES-128-GCM seal out of place 768+1 B 231 226 1.02× -2.2%
AES-128-GCM seal out of place 1024+1 B 265 253 1.05× -4.5%
AES-128-GCM seal out of place 1088+1 B 262 285 0.92× +8.8%
AES-128-GCM seal out of place 2048+1 B 340 327 1.04× -3.8%
AES-256-GCM seal in place 64 B 114 83 1.37× -27.2%
AES-256-GCM seal in place 128 B 116 106 1.09× -8.6%
AES-256-GCM seal in place 192 B 121 118 1.03× -2.5%
AES-256-GCM seal in place 256 B 134 160 0.84× +19.4%
AES-256-GCM seal in place 384 B 170 171 0.99× +0.6%
AES-256-GCM seal in place 512 B 193 145 1.33× -24.9%
AES-256-GCM seal in place 640 B 216 201 1.07× -6.9%
AES-256-GCM seal in place 768 B 221 175 1.26× -20.8%
AES-256-GCM seal in place 1024 B 245 208 1.18× -15.1%
AES-256-GCM seal in place 1088 B 259 252 1.03× -2.7%
AES-256-GCM seal in place 2048 B 355 341 1.04× -3.9%
AES-256-GCM seal out of place 64+1 B 127 186 0.68× +46.5%
AES-256-GCM seal out of place 128+1 B 132 189 0.70× +43.2%
AES-256-GCM seal out of place 192+1 B 136 232 0.59× +70.6%
AES-256-GCM seal out of place 256+1 B 167 180 0.93× +7.8%
AES-256-GCM seal out of place 384+1 B 189 265 0.71× +40.2%
AES-256-GCM seal out of place 512+1 B 222 205 1.08× -7.7%
AES-256-GCM seal out of place 640+1 B 233 273 0.85× +17.2%
AES-256-GCM seal out of place 768+1 B 232 231 1.00× -0.4%
AES-256-GCM seal out of place 1024+1 B 260 260 1.00× +0.0%
AES-256-GCM seal out of place 1088+1 B 278 309 0.90× +11.2%
AES-256-GCM seal out of place 2048+1 B 358 361 0.99× +0.8%
ChaCha20-Poly1305 seal in place 64 B 188 213 0.88× +13.3%
ChaCha20-Poly1305 seal in place 128 B 216 246 0.88× +13.9%
ChaCha20-Poly1305 seal in place 192 B 235 285 0.82× +21.3%
ChaCha20-Poly1305 seal in place 256 B 262 329 0.80× +25.6%
ChaCha20-Poly1305 seal in place 384 B 356 386 0.92× +8.4%
ChaCha20-Poly1305 seal in place 512 B 382 497 0.77× +30.1%
ChaCha20-Poly1305 seal in place 640 B 438 560 0.78× +27.9%
ChaCha20-Poly1305 seal in place 768 B 488 595 0.82× +21.9%
ChaCha20-Poly1305 seal in place 1024 B 599 652 0.92× +8.8%
ChaCha20-Poly1305 seal in place 1088 B 620 800 0.78× +29.0%
ChaCha20-Poly1305 seal in place 2048 B 1,031 1,029 1.00× -0.2%
memcpy 16384 B (the ChaCha20 copy into out) — 185 — —

Measurement limits: the PR's current RESULTS.md records 93f54441 on an Intel Xeon; this refresh uses AMD. The provider/harness also changed since the October 7 benchmark comment. Consequently these refreshed values are not isolated software speedups or regressions relative to those older runs. No historical library revision was rerun in this refresh.

Across the TLS samples, the median coefficient of variation was 6.3% for aws-lc-rs and 5.0% for VG; the 90th percentiles were 11.0% and 8.4%. RSA primitive timing also varies: VG provider RSA-2048 signing spans 257–354 µs (median 343 µs), RSA-4096 signing 2.26–2.50 ms (median 2.50 ms), and direct-library RSA-3072 signing 0.82–1.17 ms (median 1.14 ms). Differences around or below 10%, especially near parity, deserve caution. Bulk scenarios repeated across certificate types are pooled as in the existing summarizer. These are native wall-clock measurements; allocation/memory and instruction counts were not measured. The benchmark runs completed with their built-in handshake/verification/decryption checks; no separate correctness suite was run.

@alex
alex force-pushed the claude/cool-dijkstra-o2qo01 branch from f219344 to 42af3cd Compare October 8, 2026 15:05
alex pushed a commit that referenced this pull request Oct 8, 2026
Each of the sixteen entries the AVX2 selection scans took six
instructions to build its mask: combEqMask's four in the general
registers, then vmovq and vpbroadcastq. The static now ends with the
magnitudes 1 to 16, each in every doubleword of 32 bytes; the magnitude
is broadcast to ymm14 once, and each entry's mask is one vpcmpeqd of it
with the static's copy of the entry's magnitude.

The proof is in Proof/Ed25519/X86_64/Ifma/CombSelect.lean (qword_pcmpeqd,
vMagMask_ok, vselMag_ok); combWords is combTblWords ++ combMagWords, and
the literal sizes of the static grow to 40448 bytes.

From the analysis of the rustls provider's handshake signing in #991.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RLVbycsRXKPfaW1swVZejG
alex pushed a commit that referenced this pull request Oct 9, 2026
The AVX2 instance of vg_chacha20_poly1305_seal (and seal_gather, which
calls it) absorbs each 512-byte chunk's ciphertext with the scalar
Poly1305 while the AVX2 ChaCha20 kernel computes the next chunk's
keystream, so out-of-order cores overlap the two (`sealStitched`,
chosen by `sealFor`). Proven correct and constant time against the
existing contracts; no TCB or spec change.

From the rustls provider analysis in #991.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ma2fA9rUTPXEEQjYyCMCRw
All 224 tests against aws-lc-rs 1.18.1 on an AVX-512 IFMA Xeon, with
the IFMA RSA public-key operation: verified-garbage is faster in 214,
and the other 10 are within noise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DAf76RQfGxGymBaZASPY7q
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants