Repository navigation
tls 1.8.2
Fast ChaCha20-Poly1305, and TLS 1.2 records built whole. No API change.
ChaCha20-Poly1305 is the TLS 1.3 suite servers choose for clients without AES hardware. It was 25× slower than AES-GCM in tls; now it runs at Python/OpenSSL's speed on the same benchmark.
Performance (Apple M1 Pro)
| 1.8.2 | 1.8.1 | Python (OpenSSL) | |
|---|---|---|---|
| ChaCha20 alone, 16 KiB | 1,705 MB/s | 40 MB/s | |
| Poly1305 alone, 16 KiB | 2,171 MB/s | 738 MB/s | |
| ChaCha20-Poly1305 seal / open, 16 KiB | ~930 / ~935 MB/s | 37 / 37 MB/s | |
recv loop over TLS_CHACHA20_POLY1305_SHA256 |
735–746 MB/s | ~37 MB/s | 695–732 MB/s (same server) |
- ChaCha20:
- 16 blocks per step on SIMD vectors (lane i holds block i), so the rounds are the scalar code on vectors: add, rotate, xor;
- 4-block steps for the tail keep short records cheap.
- Poly1305: 44-bit limbs with 64×64→128-bit multiplies, two blocks per step (h = (h+m₁)·r² + m₂·r).
- AEAD: AAD, ciphertext and lengths stream into Poly1305 with no MAC-input buffer. Records are sealed and opened in place.
- Portability: portable Mojo with no intrinsics, so the same code runs on ARM and x86 and in software-AES builds.
- TLS 1.2: records are built whole in one buffer, so
send,closeand alerts copy one time less.
Security
- Constant time: only additions, rotations, xors, masks and fixed multiplies.
ct-checkgives t = 0.9 for ChaCha20-Poly1305. - Forged records: opening a record verifies the tag before decrypting, so a forged record writes nothing.
Testing
-
Oracle: the scalar 1.8.1 implementation is kept as a test oracle. The new code is compared against it:
- ChaCha20 at every step boundary, counters near 2^32 wraparound, in place;
- Poly1305 on 2,000 random cases plus extreme limb values;
- the AEAD with AAD of 0–64 bytes, in place, and a forged tag.
This runs on ARM (macOS CI) and x86 (Linux CI).
-
Results:
- 438 tests pass, plus the software-AES job;
- interop passes, including ChaCha20 and KeyUpdate;
- fuzzing is clean;
- live: 24 sites plus 4 bad endpoints correctly rejected, and 55 of 55 in the wide sweep.
-
Dependents: requests, websocket, pg (including SCRAM over a scram-only cluster) and mojo-pkg pass.