ChaCha20-Poly1305 Nonce Reuse Validator | Audit AEAD nonces for reuse
Paste a list of ChaCha20-Poly1305 (12-byte) or XChaCha20-Poly1305 (24-byte) nonces and this tool flags every duplicate, every wrong-length entry, and the birthday-collision risk in one view. Built to catch the one bug that breaks AEAD outright: a nonce reused under the same key.
💡 About this tool
In AEAD ciphers like ChaCha20-Poly1305, the nonce is a "number used once" for a reason. Reuse one with the same key and you leak the ChaCha20 keystream as the XOR of two messages, and worse, you expose the one-time Poly1305 authentication key, which lets an attacker forge ciphertexts. This isn't a textbook edge case; it's a recurring real-world incident born from generation bugs, stateless senders, and container restarts that reset counters.
The painful part is that nonce reuse rarely shows up in code review. Random, counter-based, and timestamp-derived schemes all look fine locally, then collide across instances. This validator takes the messy reality instead: paste nonces straight out of your logs or audit export, and it lists the exact duplicated values and counts entries that don't match the expected 12- or 24-byte length separately, since a wrong length usually means a parsing or extraction bug rather than reuse.
It also computes the birthday bound under a random-nonce assumption: P(collision) ≈ q² / 2ⁿ⁺¹. You get the collision probability for your current count plus the safe message ceiling where probability stays under 2⁻³² and 2⁻⁶⁴. That's the number people actually argue about on threads: with a 96-bit nonce, random generation crosses meaningful collision risk near 2³² messages per key, which is exactly why stateless senders are nudged toward 192-bit XChaCha20.
🧐 Frequently Asked Questions
Is a nonce secret? Is it safe to paste here? No, the nonce is a public value sent in the clear alongside the ciphertext, not the key. It's still operational data from your logs, so this tool processes everything inside your browser tab and sends nothing out. Close the tab and the pasted data is gone.
ChaCha20-Poly1305 vs XChaCha20-Poly1305, what's the actual difference? Nonce size. RFC 8439 ChaCha20-Poly1305 uses a 96-bit (12-byte) nonce. XChaCha20-Poly1305 runs an extra HChaCha20 derivation to support a 192-bit (24-byte) nonce. At 192 bits, random generation effectively never collides, which is why it's the go-to for senders that can't keep a counter.
When does an entry get flagged as "wrong length"? When the hex digit count doesn't match the selected variant (24 hex chars for ChaCha20, 48 for XChaCha20) or contains non-hex characters. AEAD implementations reject these outright, so a wrong-length hit usually points at an extraction or logging bug worth chasing down.
Can I paste nonces with 0x prefixes or colons?
Yes. Leading 0x, colons, whitespace, and hyphens are stripped automatically, and comparison is case-insensitive. Dump your log lines in as-is.
What does the "safe message count" actually tell me? For randomly generated nonces, it's the maximum number of messages you can send under one key before the collision probability crosses the target. For 96-bit nonces, the 2⁻³² ceiling lands near 2³² messages. Past that, rotate the key rather than trusting randomness.
Does this work for counter-based (sequential) nonces? Duplicate detection and length checks work exactly the same. The birthday bound assumes random generation, so under a strict counter scheme treat the probability field as informational and focus on confirming zero duplicates.
📚 Fun Facts
The most cited nonce-reuse failures are the GCM collision bugs found across TLS stacks and homegrown protocols, and because ChaCha20-Poly1305 is the same AEAD shape, it inherits the same trap. That's exactly why Google's QUIC deployment pairs ChaCha20-Poly1305 with strict counter-managed nonces rather than leaving it to chance.
The "X" in XChaCha20 stands for extended: an HChaCha20 step stretches the usable nonce to 192 bits. libsodium popularized it, and it quietly became the default answer whenever someone on a forum asks "how do I use ChaCha20 safely without managing a counter." Throwing 192 random bits is simply less error-prone than babysitting a 96-bit sequence.