INVITE ONLY
OBSERVATORY

04 Science — the ratchet

The key that only turns forward.

A real derivation chain runs in this page. Step it with your thumb, watch a fresh key seal fresh bytes — then try to turn it backward.

Real WASM derivations SHA3-256 · ChaCha20-Poly1305

A chain where every link devours the last.

Each chain key births exactly two things: one message key, and the next chain key. Then it is destroyed. Hold the newest link and every older one is already gone — the chain gives you the future and burns the past.

The arrow is a hash function. Following it costs one call; reversing it costs a preimage search. That asymmetry is the whole machine.

Step it. Then try to go back.

Every press runs a real SHA3-256 derivation and seals a fresh message under the new key — while the old keys are zeroized in memory. Then tap an older link: the live key runs a real open() on it, and the seal refuses.

CHAIN HEAD · CK0awaiting entropy ············
derive message key 1 and seal a message under it

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. The chain steps are real SHA3-256 derivations under distinct labels — demo build, real derivation; the shipped Q-Ratchet advances its symmetric chain with HKDF-SHA-512.

Forward secrecy is a hash you cannot invert.

Compromise of the chain at time t does not reveal messages before t: every derivation flows forward only, under labels that separate chain keys from message keys, and per-message keys are zeroized immediately after use.

the derivation the bench computes
mk_n    = SHA3-256( "MESSAGE-DERIVE" ‖ ck_n )
ck_n+1  = SHA3-256( "CHAIN-ADVANCE"  ‖ ck_n )

forward:  one hash call
backward: a preimage search — ≈2²⁵⁶ work

Two distinct labels split one chain key into a message key and the next chain key — a leaked message key never reveals the chain, and the chain never reveals past message keys. The bench prefixes its labels with QX-DEMO-RATCHET/ so demo output can never collide with a protocol derivation.

the shipped chain — crypto-core/src/quadruple_ratchet.rs
ChainKey.advance():
    new_ck  = HKDF(ck, "CHAIN-ADVANCE",  info = "CHAIN-KEY",   32)
    msg_key = HKDF(ck, "MESSAGE-DERIVE", info = "MESSAGE-KEY", 32)

Same shape, production primitive: the shipped symmetric chain advances with HKDF-SHA-512 (RFC 5869) under the same two-label split, and intermediate key copies are explicitly zeroized before drop.

The four parallel chains of Q-Ratchet
ChainPrimitiveCadence
1 — Classical DH X25519 every message
2 — Post-quantum KEM ML-KEM-1024 every 100 messages
3 — Symmetric chain HKDF-SHA-512 every message
4 — Entropy injection certified QRNG every 5 messages (text)

What you stepped above is chain 3’s principle in isolation. The other three exist so that compromise of any one chain leaves the others standing — the full construction is in the Q-Ratchet paper.

Each step is a full hash of the previous key. Running SHA3-256 backward is a preimage search — FIPS 202 puts it at 2²⁵⁶ work for a 256-bit digest, beyond any published attack, classical or post-quantum. The bench’s refusal is that mathematics wearing a button.

Everything after the theft, nothing before it — until the chain heals. The symmetric chain alone reads forward from the stolen state; in the full Q-Ratchet the next ML-KEM-1024 epoch and the next QRNG injection re-key from material the thief never had, cutting the forward view off as well. That healing property is post-compromise security, specified in the paper.

It is one of its four chains, on the demo primitive: real SHA3-256 derivations and real ChaCha20-Poly1305 seals in the browser WASM build, where the shipped chain runs HKDF-SHA-512 inside crypto-core. The one-way property you just pressed is the same. The label under the bench states exactly this.

  • NIST FIPS 202, "SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions" (2015)
  • RFC 5869 — HMAC-based Extract-and-Expand Key Derivation Function (HKDF) (2010)
  • RFC 8439 — ChaCha20 and Poly1305 for IETF Protocols (2018)
  • QERYX Protocol Specification §6 — docs/SPEC/04-q-ratchet.md; implementation crypto-core/src/quadruple_ratchet.rs

Follow the chain into the protocol.

Every message you send rides a key that existed for that message alone. The Q-Ratchet derives it the way the bench does — forward only, distinct labels, immediate zeroization — from the X25519 + ML-KEM-1024 hybrid agreement, and advances four parallel chains so no single compromise opens the conversation.

A device seized today holds today’s chain head. The messages behind it were sealed under keys that no longer exist anywhere — and that the seized state cannot re-derive, for the reason your thumb just verified.

The honest questions.

Is the derivation real?

Yes. The chain steps are SHA3-256 and the seals are ChaCha20-Poly1305 (RFC 8439), compiled from Rust to WebAssembly and self-tested against the RFC’s vector before first use — on any mismatch the bench refuses to run. The keys are demo keys, born in your browser from crypto.getRandomValues; the derivations on them are real.

No. Chain keys, message keys, nonces, and ciphertext live and die in this tab. The bench makes no network request of any kind.

Because a one-way chain protects the past, and only the past. An attacker holding the live state reads forward until the chain re-keys from fresh material — so the Q-Ratchet folds in a new ML-KEM-1024 encapsulation every epoch and fresh QRNG entropy every few messages. And no ratchet defends an unlocked device in an attacker’s hands; the limitations page names that plainly.