# Poly1305: The Authenticator That Pairs With ChaCha20

**Source**: https://quantumsequrity.com/blog/poly1305-explained
**Category**: Cryptography Foundations

---

[← Back to Blog](../../blog) Cryptography Foundations

# Poly1305: The Authenticator That Pairs With ChaCha20

10 min read

When you read about modern authenticated encryption, you see the name "Poly1305" everywhere. ChaCha20-Poly1305 secures TLS 1.3, WireGuard tunnels, Signal messages, and SSH connections. The "ChaCha20" half does the encryption. The "Poly1305" half does something just as important and far less famous: it tells you whether the ciphertext you received is the ciphertext that was actually sent.

Poly1305 is a Message Authentication Code, or MAC. A MAC is a short tag, typically 128 bits, that lets the receiver verify two things at once. First, the message was not tampered with in transit. Second, the message was created by somebody who knew the secret key. If even a single bit of the ciphertext changes, the tag fails to verify and the receiver throws away the message.

This article walks through what Poly1305 actually does, why Daniel J. Bernstein designed it, what makes it different from HMAC, and where its security guarantees come from.

## A Quick Word on Why MACs Exist

A cipher like ChaCha20 or AES-CTR turns plaintext into ciphertext that an eavesdropper cannot read. That is confidentiality. But ciphers alone do not stop an active attacker who can flip bits in the ciphertext while it is in transit.

In a stream cipher, flipping a bit of ciphertext flips the same bit of plaintext after decryption. The receiver cannot tell. They will happily decrypt and act on the corrupted message. If the message is "Send 100 dollars to Alice", an attacker can flip bits to make it say "Send 999 dollars to Eve" without ever knowing the key.

A MAC closes that hole. The sender computes a tag over the ciphertext using a key. The receiver recomputes the tag and compares. Any tampering changes the tag, the comparison fails, and the message is rejected. Authenticated encryption (AEAD) bundles encryption and MAC together so the application cannot accidentally use one without the other.

## How Poly1305 Came to Exist

Daniel J. Bernstein published Poly1305 in 2005 in a paper titled "The Poly1305-AES Message-Authentication Code." The original construction paired Poly1305 with AES, where AES generated a one-time key for each message. The MAC itself was a polynomial evaluation in the prime field GF(2 to the 130 minus 5), which is where the name "Poly1305" comes from. The constant 2 to the 130 minus 5 is the prime modulus.

Poly1305 was designed for one job: be the fastest possible information-theoretically secure MAC under the assumption that the underlying key generator is good. Bernstein proved that if the per-message key is truly random and used only once, an attacker has at most an 8 in 2 to the 106 chance of forging a single message. That is roughly a 1 in 80 billion billion billion chance.

In 2008, Bernstein introduced ChaCha20. The pairing of ChaCha20 (to derive the one-time Poly1305 key) and Poly1305 (to authenticate the ciphertext) became the core of the AEAD construction now standardized as ChaCha20-Poly1305 in IETF RFC 8439.

## How Poly1305 Actually Works

The math is conceptually simple, even if the field arithmetic is finicky. Poly1305 takes a 32-byte key, splits it into two 16-byte halves called r and s, applies a small mask to r, and treats the message as a sequence of 16-byte blocks. Each block is interpreted as a number, with a 1 byte appended.

The MAC tag is computed by evaluating a polynomial. Imagine each message block as a coefficient. The polynomial is evaluated at the point r, modulo the prime 2 to the 130 minus 5, and then s is added modulo 2 to the 128 to mask the result. The output is a 16-byte tag.

In symbols, if the message blocks are c1, c2, c3, and so on, the tag is:

(((c1 times r to the n) plus (c2 times r to the n minus 1) plus ... plus cn times r) mod (2^130 minus 5)) plus s) mod 2^128

The masking by s is critical. Without it, the tag would leak information about r, and an attacker could recover r after seeing enough message-tag pairs.

The function is what cryptographers call a "one-time MAC" or a "Wegman-Carter authenticator." The name comes from the 1981 paper by Mark Wegman and Larry Carter that pioneered universal hash families for authentication.

## The One-Time Key Requirement

Poly1305's headline security proof rests on one assumption that engineers must respect: the (r, s) key pair must never be reused for two different messages. If you ever reuse the same Poly1305 key on two different messages, an attacker can solve a polynomial equation for r and forge any future tag.

This is why Poly1305 is always paired with a stream cipher that derives a fresh key for every message. In ChaCha20-Poly1305, the first 32 bytes of the ChaCha20 keystream (with counter set to zero) become the Poly1305 key. The rest of the keystream encrypts the plaintext. Every nonce-key combination produces a different Poly1305 key, so reuse never happens unless the application reuses a nonce, which would also break ChaCha20 itself.

This is the same nonce uniqueness rule that AES-GCM has. Read more in [AES-256-GCM Explained](aes-256-gcm-explained).

## Why Not Just Use HMAC?

HMAC is the older and more widely deployed MAC, standardized in IETF RFC 2104 (1997) and FIPS 198-1 (2008). HMAC uses a hash function like SHA-256 inside a nested construction. It is unconditionally safe, well understood, and supported in every cryptography library on Earth.

Poly1305 has three advantages over HMAC for AEAD use:

- Speed. Poly1305 runs at roughly 1 to 2 cycles per byte on a 64-bit CPU. HMAC-SHA-256 typically runs at 6 to 8 cycles per byte. For high-throughput tunnels like WireGuard or QUIC, the difference matters.
- Simplicity. Poly1305 is one polynomial evaluation. HMAC is two hash invocations with key padding rituals.
- Security proof tightness. Poly1305 has a clean information-theoretic forgery bound. HMAC's bound depends on the underlying hash function's resistance to differential attacks, which is empirical rather than mathematical.

HMAC remains preferred for message authentication where keys are reused (such as TLS 1.2 record MACs before AEAD became standard). For AEAD with fresh per-message keys, Poly1305 wins.

## Why Not Use GCM Authentication?

AES-GCM uses a different polynomial MAC called GHASH, evaluated in GF(2 to the 128) rather than over a prime field. GHASH is slightly faster on x86_64 with PCLMULQDQ hardware multiplication.

Poly1305 wins where:

- The hardware lacks AES-NI and PCLMULQDQ. Poly1305's prime-field arithmetic runs efficiently in software using ordinary 64-bit multiplications.
- Constant-time implementation matters. Poly1305 has no lookup tables and no data-dependent branches, so it leaks nothing through cache timing.
- Code size matters. Poly1305 fits in a few hundred lines of clean C. GCM with software GHASH (when there is no hardware) needs lookup tables that are slower and consume cache.

In practice, ChaCha20-Poly1305 is the AEAD pair you want on phones, embedded devices, and any environment without AES-NI. Read more in [ChaCha20 vs AES-GCM](chacha20-vs-aes).

## The Field Arithmetic Trick

Poly1305's prime modulus 2 to the 130 minus 5 is special. It is just slightly larger than 2 to the 128, which means a 16-byte block fits inside the field with room to spare.

The number is also a "Mersenne-like" prime. Reduction modulo (2 to the 130 minus 5) can be done with a few additions and shifts, no general division needed. Implementations on 64-bit CPUs typically use a "limb" representation with three or four 64-bit words to hold the 130-bit accumulator. Multiplications and reductions interleave so that the carry chain stays short.

This is why Poly1305 runs at roughly 1 cycle per byte on a 64-bit CPU. The arithmetic is unusually friendly to general-purpose hardware.

## Forgery Probability: The Numbers

Bernstein's original paper proves the following: an attacker who has seen authentic messages and tags, then submits q distinct forgery attempts, succeeds with probability at most:

8 times L times q divided by 2 to the 106

where L is the message length in 16-byte blocks. For a 16-kilobyte message and 1 trillion forgery attempts, the success probability is roughly 1 in 2 to the 70. The number is close enough to "impossible" that no practical adversary can exploit it.

The bound assumes the per-message key is uniformly random. Any biases or correlations in the keystream weaken the bound proportionally.

## Where Poly1305 Lives in the Wild

Poly1305 is everywhere in modern cryptographic infrastructure:

- TLS 1.3 (RFC 8446) supports ChaCha20-Poly1305 as one of three mandatory AEAD modes.
- WireGuard's Noise-based handshake uses ChaCha20-Poly1305 as its sole AEAD.
- Signal Protocol's double ratchet uses HKDF-SHA-256 to derive keys but encrypts payloads with ChaCha20-Poly1305 in many implementations.
- QUIC (RFC 9001) lists ChaCha20-Poly1305 as a recommended cipher suite.
- SSH (RFC 8709 informational) lists chacha20-poly1305@openssh.com as a primary AEAD.
- Age and Magic Wormhole, two file-encryption tools, use ChaCha20-Poly1305.

Anywhere you see ChaCha20-Poly1305, the second word is doing exactly the work this article describes.

## Quantum Resistance

Grover's algorithm halves the effective brute-force security of any cryptographic primitive. For Poly1305 with a 128-bit tag, brute-force forgery drops from 2 to the 128 to 2 to the 64 quantum operations, which is borderline.

But Poly1305 is rarely the limiting factor in a quantum attack. The keys come from a stream cipher (ChaCha20 or another), and Grover's speedup applies to the key recovery side too. With 256-bit cipher keys, the symmetric layer remains safe at roughly 128-bit post-quantum security. Read more in [Grover's Algorithm Explained for Layman](grover-algorithm-explained-layman).

## Implementation Considerations

Poly1305 implementations have to handle a few subtleties carefully. The accumulator value can grow up to 2 to the 130 between reductions, which on a 64-bit CPU spans three 64-bit limbs. Implementations typically use a 26-bit limb representation (five 26-bit values per accumulator) on 32-bit CPUs and a 44-bit limb representation (three 44-bit values) on 64-bit CPUs. The carry chains are short and the multiplication is friendly to general-purpose hardware.

The final reduction modulo 2 to the 130 minus 5, followed by addition of s modulo 2 to the 128, requires a constant-time conditional subtraction. The output is then truncated to 16 bytes. Implementations that leak the carry value (through timing variation in the conditional subtraction) can in principle leak bits of the secret key, although the practical attack surface is small.

Modern implementations (libsodium, the AES-GCM-style Poly1305 in BoringSSL, Monocypher) handle these details correctly. Custom Poly1305 implementations should be carefully audited.

## Standalone vs AEAD Use

The original Poly1305-AES construction in Bernstein's 2005 paper used AES to derive the per-message Poly1305 key. The receiver needed to know the AES key to derive the same Poly1305 key.

Modern AEAD use replaces AES with a stream cipher's keystream prefix. ChaCha20-Poly1305 uses the first 32 bytes of the ChaCha20 keystream (with counter zero) as the Poly1305 key. The remaining keystream encrypts the plaintext. This gives a single key and nonce pair for the entire AEAD operation.

The Poly1305-AES variant is largely historical. The ChaCha20-Poly1305 variant is what you find in TLS, WireGuard, QUIC, and SSH today.

## What QNSQY Uses

QNSQY uses AES-256-GCM as its default AEAD, which is fast on x86-64 processors with AES-NI, and users can choose XChaCha20-Poly1305 instead. The ML-KEM and X25519 shared secrets are combined, and HKDF-SHA3-256 derives the 256-bit file key from the result and a fresh random salt; the AEAD then encrypts the file in chunks under that key. Read more in [Hybrid Encryption](hybrid-encryption) and [ML-KEM Explained](ml-kem-explained).

## FAQ

**Why does Poly1305 use a 130-bit prime instead of 128?**

The extra two bits give room for arithmetic to overflow without wrapping, which simplifies the reduction step. A pure 128-bit prime field would require more careful carry handling.

**Is Poly1305 patented?**

No. Bernstein placed it in the public domain. There are no royalty obligations or licensing concerns.

**Can I use Poly1305 standalone, without ChaCha20?**

Yes, but you must derive a fresh 32-byte key for every message. The original Poly1305-AES construction did this with AES. Standalone use is rare today because AEAD modes bundle the cipher and MAC together.

**Is the 16-byte tag long enough?**

For online authentication of internet messages, yes. The 128-bit forgery bound is far stronger than typical session lifetime requirements. For long-term archival authentication, 256-bit hash-based MACs (like HMAC-SHA-256) are preferred.

**Why isn't Poly1305 a NIST standard?**

NIST standardizes a small set of primitives at a time, prioritizing block ciphers and modes over MACs. Poly1305 is a recommended cipher in IETF protocols (RFC 7539, RFC 8439) and used worldwide, but NIST has not issued a separate FIPS for it. AES-GMAC (the GCM authentication piece used standalone) is the NIST-blessed equivalent.

## Sources

1. Daniel J. Bernstein, "The Poly1305-AES Message-Authentication Code" (2005). https://cr.yp.to/mac/poly1305-20050329.pdf
2. IETF RFC 8439: ChaCha20 and Poly1305 for IETF Protocols. https://www.rfc-editor.org/rfc/rfc8439
3. IETF RFC 7539: ChaCha20 and Poly1305 for IETF Protocols (original, obsoleted by 8439). https://www.rfc-editor.org/rfc/rfc7539
4. IETF RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3. https://www.rfc-editor.org/rfc/rfc8446
5. Mark Wegman and Larry Carter, "New Hash Functions and Their Use in Authentication and Set Equality" (1981). Journal of Computer and System Sciences.
6. NIST FIPS 198-1: The Keyed-Hash Message Authentication Code (HMAC). https://csrc.nist.gov/pubs/fips/198-1/final

## Related Articles

- [ChaCha20 vs AES-GCM](chacha20-vs-aes)
- [AES-256-GCM Explained](aes-256-gcm-explained)
- [Hybrid Encryption](hybrid-encryption)
- [ML-KEM Explained](ml-kem-explained)
- [Grover's Algorithm Explained for Layman](grover-algorithm-explained-layman)

---

### Protect Your Data Before Q-Day Arrives

QNSQY's NIST-standardized post-quantum encryption protects files against both current and quantum-era threats.

[Try QNSQY](../../pricing)
