INVITE ONLY
OBSERVATORY

02 Science — authenticated encryption

Break the seal. Then try to forge it.

Real ChaCha20-Poly1305 runs in this page. Decrypt a message, seal your own, flip one byte — and watch Poly1305 refuse the entire frame.

Real WASM crypto ChaCha20-Poly1305 · RFC 8439

Tap to decrypt.

This is a real ciphertext, sealed with the same primitive family the app ships. Your tap runs the actual open() — the resolve you see is the plaintext arriving.

rerun open() on a corrupted frame

Real ChaCha20-Poly1305 (RFC 8439), compiled from Rust to WebAssembly, running in your browser. Same primitive family as the QERYX protocol; demo build, not the shipped crypto-core module.

Seal your own. Then attack it.

Write anything — it never leaves this page. Seal it under a fresh 256-bit key, decrypt it back, then flip a single byte and watch the authenticator refuse the whole message rather than return a garbled copy.

Sealed and opened entirely in this page. Nothing leaves your browser.

Real ChaCha20-Poly1305 (RFC 8439), compiled from Rust to WebAssembly, running in your browser. Same primitive family as the QERYX protocol; demo build, not the shipped crypto-core module.

Read the construction under your thumb.

Two primitives, one composition: ChaCha20 turns a key and nonce into keystream; Poly1305 makes the ciphertext unforgeable. RFC 8439 fixes how they join.

chacha20 quarter-round — RFC 8439 §2.1
a += b;  d ^= a;  d <<<= 16;
c += d;  b ^= c;  b <<<= 12;
a += b;  d ^= a;  d <<<=  8;
c += d;  b ^= c;  b <<<=  7;

Add, rotate, xor — on a 4×4 state of 32-bit words, 20 rounds per block. Three operations every CPU runs in constant time: no lookup tables, no data-dependent branches, nothing for a timing attack to read.

poly1305 — a one-time authenticator
tag = ( ( m₁·rⁿ + m₂·rⁿ⁻¹ + … + mₙ·r )  mod 2¹³⁰ − 5 ) + s   mod 2¹²⁸

The message is read as coefficients of a polynomial, evaluated at a secret point r over the prime field 2¹³⁰−5, then offset by s. Both r and s are used for exactly one message.

the AEAD composition — RFC 8439 §2.8
(r, s)  = first ChaCha20 keystream block of (key, nonce)
ct      = plaintext ⊕ ChaCha20(key, nonce, counter ≥ 1)
tag     = Poly1305( r, s,  AAD ‖ ct ‖ len(AAD) ‖ len(ct) )

open(): recompute tag, compare in constant time — refuse on any mismatch

The tag covers the ciphertext and the associated data. open() verifies before it decrypts — a tampered frame yields a refusal, never plaintext.

ChaCha20-Poly1305 parameters
ParameterValueSource
Key 256 bits RFC 8439
Nonce 96 bits RFC 8439
Tag 128 bits RFC 8439
Cipher rounds 20 RFC 8439
Poly1305 field prime 2¹³⁰ − 5 RFC 8439

Garbled output leaks structure and invites oracles: an attacker who can watch you process corrupted plaintext learns things. An AEAD returns exactly two outcomes — the true plaintext, or a refusal. The flip-a-byte demo above is that property, live.

Everything. Two messages under the same (key, nonce) share keystream, which exposes their xor — and reuse also exposes the Poly1305 key, enabling forgeries. This is the sharpest edge of the construction; the demo draws a fresh random key and nonce for every seal, and QERYX derives fresh message keys through Q-Ratchet so the pair never repeats.

ChaCha20 runs in constant time on every CPU, with no lookup tables and no special instructions required — the same speed and the same timing profile on a flagship phone and a ten-year-old handset. The AES-256-GCM suite is implemented and reserved as suite 0x0002, staged for rollout.

  • Y. Nir, A. Langley, "ChaCha20 and Poly1305 for IETF Protocols," RFC 8439 (2018)
  • D. J. Bernstein, "ChaCha, a variant of Salsa20" (2008)
  • D. J. Bernstein, "The Poly1305-AES message-authentication code," FSE (2005)

Follow the seal into the protocol.

Every message frame is sealed with ChaCha20-Poly1305 (RFC 8439) under a key that exists for that message alone — Q-Ratchet derives a fresh one each time from the X25519 + ML-KEM-1024 hybrid agreement.

The relay carries the sealed frame and cannot open it: the key never leaves the two devices. What you just did to a tampered byte is what every QERYX client does to a tampered message — refuse it whole.

The honest questions.

Is this demo the app's crypto?

It is real ChaCha20-Poly1305 (RFC 8439), compiled from Rust to WebAssembly and self-tested against the RFC's test vector before first use — the same primitive family as the QERYX protocol, as a demo build rather than the shipped crypto-core module. The label under each demo states exactly this.

No. Key, nonce, plaintext, and ciphertext live and die in this tab. The playground makes no network request of any kind.

The same refusal as a flipped byte: Poly1305 recomputes a tag that cannot match, and open() rejects before a single block is decrypted. Wrong key, wrong nonce, tampered ciphertext, tampered associated data — one indistinguishable refusal for all four.