Shielded Quest

Docs / How it works

How it works

Three parts: your browser does the cryptography, the web app stores public hunt files, and the signer watches and pays out prize pots on the Zcash testnet.

 your browser                    the site                 the signer              Zcash testnet
 ─────────────                   ────────                 ──────────              ─────────────
 answers → Argon2id   ─────────▶ stores the hunt file ──▶ watches the pot     ──▶ shielded pool
 stages ↔ AES-GCM                (ciphertext only)        sweeps it on a claim
 makes the prize key             (viewing key only)

1. Locking a hunt

A hunt has stages. Each stage has an answer. Your browser turns each answer into a key:

k₁ = Argon2id(answer₁, hunt id ‖ 1 ‖ 000…0)
k₂ = Argon2id(answer₂, hunt id ‖ 2 ‖ k₁)
kₙ = Argon2id(answerₙ, hunt id ‖ n ‖ kₙ₋₁)

Argon2id is deliberately slow and memory-hungry (64 MiB, 3 passes), so every guess costs real work. Each key also depends on the one before, so the last stage can't be attacked without solving every earlier one first.

Stage i is the next clue (or, for the last stage, the prize pot's seed phrase) encrypted with kᵢ using AES-256-GCM. Every stage is padded to the same size, so nobody can tell which one holds the prize or how long the clues are.

Answers are forgiving: case, accents, punctuation and extra spaces are ignored, so "The Eiffel-Tower!" and "the eiffel tower" give the same key.

2. The prize pot

When you create a hunt, your browser makes a brand-new Zcash wallet just for the prize (the pot): a 24-word seed phrase that never leaves your device. It sends the signer only the pot's viewing key, which can see the balance but can't spend. Your browser then seals the phrase into the last stage and gives you a backup.

The backup step tells you which side made the pot. Green, "Made in your browser", is the normal case. If your browser can't run the key module, the box is orange, "Made by the server": the signer makes the pot and hands you the phrase once.

You fund the pot like any Zcash address. The viewing key is published on the hunt page, so anyone can confirm the prize is there.

3. Solving

The hunt page downloads the public hunt file. Each guess is run through Argon2id and tried against the current stage, entirely in your browser. A wrong guess fails to decrypt; a right one reveals the next clue. Nothing about your guesses is sent anywhere.

4. Claiming

The final answer reveals the pot's seed phrase. Then either:

  • Claim with one click. Your browser sends the phrase and your shielded address to the signer, which moves the whole pot to you in one shielded transaction and locks the pot so a second claim fails.
  • Sweep it yourself. Restore the phrase in any Zcash wallet and send the funds to yourself. Nothing is sent to the site.

The one-click claim is built so the published viewing key can't decrypt where the prize went (the sweep discards its outgoing viewing key). Everyone sees the pot empty; nobody reading the chain sees the winner. With the one-click claim the site sees the address you paste, to send the prize; if you sweep it yourself, it doesn't.

Built with

Zcash's librustzcash crates (wallet sync, Sapling/Orchard/Ironwood shielded pools, proving) in a Rust signer; Next.js for the site; hash-wasm Argon2id and the browser's WebCrypto AES-GCM for the stages. Source and tests are in the repository.