ChaCha20-Poly1305: The Mobile-Friendly AEAD
TLS 1.3's second mandatory cipher suite pairs ChaCha20 encryption with the Poly1305 message authenticator, delivering AES-GCM-equivalent security without needing any special hardware. Here's how the pairing works.
Interactive ChaCha20-Poly1305 Visualizer
🔐 ChaCha20-Poly1305 AEAD
ChaCha20-Poly1305: The Mobile-Friendly AEAD
Introduction
Just as AES-GCM pairs AES encryption with GHASH authentication, ChaCha20-Poly1305 pairs ChaCha20 encryption with a different, purpose-built authenticator called Poly1305 — also designed by Daniel J. Bernstein. Standardized in RFC 8439, this combination is one of exactly two AEAD cipher suites mandated by TLS 1.3 (the other being AES-GCM), and it’s the backbone of the WireGuard VPN protocol. Its defining advantage: excellent, consistent performance in pure software, with no dependency on the specialized AES-NI or PCLMULQDQ hardware instructions that AES-GCM leans on.
Table of Contents
- Why Pair ChaCha20 with Poly1305?
- Deriving the One-Time Poly1305 Key
- How Poly1305 Computes a Tag
- Assembling the AEAD Construction
- A Verified Example
- ChaCha20-Poly1305 vs. AES-GCM
- FAQ
- References
Why Pair ChaCha20 with Poly1305?
ChaCha20 alone only provides confidentiality. Poly1305 is a fast, information-theoretically-grounded message authentication code (MAC) — not a general-purpose hash function, but a purpose-built one-time authenticator, designed specifically to pair efficiently with a stream cipher like ChaCha20. Together they form a complete AEAD construction: ChaCha20 hides the data, Poly1305 proves nobody tampered with it.
Deriving the One-Time Poly1305 Key
Poly1305 requires a fresh, unique 32-byte key for every single message — reusing a Poly1305 key across two different messages breaks its security guarantees entirely. Rather than requiring protocols to manage a second secret key, the ChaCha20-Poly1305 construction elegantly derives it from the same key and nonce already in use: it runs the ChaCha20 block function once, with the block counter fixed at 0, and uses the first 32 bytes of that keystream block as the one-time Poly1305 key. The actual message encryption then proceeds with ChaCha20 starting at counter 1, guaranteeing the Poly1305 key and the encryption keystream never overlap.
How Poly1305 Computes a Tag
The one-time key splits into two 16-byte halves, r and s. r is “clamped” (specific bits forced to zero) to keep the arithmetic well-behaved, and treated as a number for polynomial evaluation modulo the prime 2¹³⁰ − 5 — the prime that gives Poly1305 its name. The message is split into 16-byte blocks; each block, with a single bit appended, is added into a running accumulator, which is then multiplied by r (mod that prime) — repeated for every block. The final accumulator, plus s, mod 2¹²⁸, is the 16-byte authentication tag.
Interactive Visualizer
The visualizer above runs the complete, genuine construction — real ChaCha20 keystream generation for both key derivation and encryption, real Poly1305 polynomial evaluation for the tag — verified against Node.js’s own built-in ChaCha20-Poly1305 implementation before being published here. Try the tamper button to see authentication correctly reject an altered ciphertext.
Assembling the AEAD Construction
The final Poly1305 MAC is computed over a specifically formatted message: the associated data (padded to a 16-byte boundary), the ciphertext (padded to a 16-byte boundary), then 8-byte little-endian lengths of the associated data and ciphertext. This exact padding and length-encoding scheme prevents subtle ambiguity attacks where an attacker might otherwise construct two different (AAD, ciphertext) pairs that hash to the same tag.
A Verified Example
Using a small demonstration case with an all-but-one-byte-zero key:
- Key: 32 bytes, all zero except the last byte set to
01 - Nonce: 12 bytes, all zero except the last byte set to
02 - Associated data: “hello aad”
- Plaintext: “The quick brown fox jumps over the lazy dog”
produces a specific ciphertext and 16-byte tag that the visualizer above reproduces exactly, matching Node.js’s own AEAD implementation byte for byte.
ChaCha20-Poly1305 vs. AES-GCM
Both provide equivalent security guarantees as AEAD constructions. The practical difference is performance profile:
- AES-GCM excels on hardware with AES-NI and PCLMULQDQ instructions — nearly all modern desktop and server CPUs — where it can outperform ChaCha20-Poly1305 substantially.
- ChaCha20-Poly1305 excels in pure software, particularly on mobile and embedded processors that historically lacked (or had inconsistent) AES hardware acceleration, and is naturally resistant to cache-timing side-channels since it uses no table lookups at all.
TLS 1.3 mandates support for both specifically so each side of a connection can negotiate whichever performs best on its own hardware.
FAQ
Why can’t Poly1305 keys be reused?
Poly1305 is a “one-time” authenticator in the cryptographic sense — its security proof depends on each key being used for exactly one message. Reusing a Poly1305 key across two messages can let an attacker solve for the key algebraically and forge tags for arbitrary future messages.
Is ChaCha20-Poly1305 secure?
Yes — it’s one of exactly two AEAD constructions mandated by TLS 1.3, alongside AES-GCM, and has no known practical weaknesses in its standard configuration.
Why does the construction start ChaCha20 at counter 1 instead of 0?
Counter 0 generates the one-time Poly1305 key itself. Starting the actual message encryption at counter 1 guarantees the keystream used to derive the authentication key never overlaps with the keystream used to encrypt data — reusing that block would leak the Poly1305 key.
What does the “1305” in Poly1305 refer to?
The prime modulus 2¹³⁰ − 5, which the algorithm’s polynomial evaluation is computed modulo — 1305 loosely evokes “130-5.”
Does WhatsApp or Signal use ChaCha20-Poly1305?
Signal Protocol implementations commonly use AES-GCM or ChaCha20-Poly1305 for the actual message encryption layer (after the Double Ratchet establishes per-message keys) — see the Signal Protocol guide for the full picture of how those pieces fit together.
References
-
RFC 8439. “ChaCha20 and Poly1305 for IETF Protocols.” IETF, 2018. Available at: https://datatracker.ietf.org/doc/html/rfc8439
-
Bernstein, D. J. “The Poly1305-AES message-authentication code.” FSE 2005 — the original Poly1305 design paper.
-
Langley, A., Chang, W., Mavrogiannopoulos, N., Strombergson, J., and Josefsson, S. “ChaCha20-Poly1305 Cipher Suites for TLS.” RFC 7905, 2016.
-
Donenfeld, J. A. “WireGuard: Next Generation Kernel Network Tunnel.” NDSS 2017.