Skip to content

Bench QUIC header protection masks - #3154

Merged
alex merged 1 commit into
mainfrom
quic-hp-bench
Oct 22, 2026
Merged

alex merged 1 commit into
mainfrom
quic-hp-bench

Conversation

@alex

@alex alex commented Oct 22, 2026

Copy link
Copy Markdown
Member

rustls computes a 5-byte header protection mask for every QUIC packet (RFC 9001 §5.4). The rustls provider in #991 does it in one of two ways:

  • AES: one AES-ECB block of the 16-byte sample, under an AesEcb it keeps for the life of the keys.
  • ChaCha20: a fresh ChaCha20 whose counter and nonce are the sample, taking the first five bytes of its keystream.

Nothing benchmarked either shape. The AES-ECB rows expand the key on every call and start at 64 bytes. The ChaCha20 rows start at 64 bytes and have no aws-lc-rs row, because aws-lc-rs exposes ChaCha20 only through aead::quic::HeaderProtectionKey.

This adds bench/benches/primitives/quic_hp.rs, with three groups: quic-hp-aes-128, quic-hp-aes-256 and quic-hp-chacha20. The id is the sample's 16 bytes. Each compares three implementations:

  • verified-garbage, doing exactly what the provider does.
  • aws-lc-rs's HeaderProtectionKey::new_mask, with the key made once.
  • OpenSSL: a reused ECB Crypter for AES, and a fresh ChaCha20 Crypter per mask.

The bench file is new and main.rs gains two lines. It does not touch chacha20.rs, which #3148 extends.

On Neoverse N2 (run 39861905763, this branch alone, default features):

Benchmark verified-garbage OpenSSL aws-lc-rs
quic-hp-aes-128/16 41 ns 23 ns 7 ns
quic-hp-aes-256/16 44 ns 24 ns 8 ns
quic-hp-chacha20/16 137 ns 520 ns 120 ns

Most of the AES time is AesEcb::crypt zeroing a 2 KB scratch array and then wiping it, on every call. The hardware implementations never touch that scratch. Removing both locally on x86-64 takes the mask from 44 ns to 5 ns, against aws-lc-rs's 9 ns. A follow-up PR will prove what each implementation writes of scratch and wipe only that.


Generated by Claude Code

rustls computes a 5-byte header protection mask for every QUIC packet
(RFC 9001 §5.4): one AES-ECB block of a 16-byte sample under a key it keeps,
or the first five bytes of a fresh ChaCha20 whose counter and nonce are the
sample. Nothing benchmarked either shape: AES-ECB's rows expand the key on
every call and start at 64 bytes, and ChaCha20's start at 64 bytes and have
no aws-lc-rs row. Compare both with aws-lc-rs's
aead::quic::HeaderProtectionKey::new_mask and with OpenSSL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FoYWDDEDFq1DFev5X7n2aq
@alex
alex added this pull request to the merge queue Oct 22, 2026
Merged via the queue into main with commit eab2a0f Oct 22, 2026
14 checks passed
@alex
alex deleted the quic-hp-bench branch October 22, 2026 23:03
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.

2 participants