Docs

QuantMask, end to end.

A fixed-denomination zero-knowledge pool on Robinhood Chain, whose splits and schedules are sampled from real qubit measurements, and whose notes are sealed with post-quantum keys.

Pools

Three contracts, one per denomination: 0.1, 0.01 and 0.001 ETH. Each holds a Poseidon Merkle tree of depth 20 (1,048,576 leaves) with a history of the last 100 roots, and a set of spent nullifier hashes.

mask(uint256 commitment) payable            // msg.value == denomination
unmask(a, b, c, root, nullifierHash, recipient, relayer, fee)
getLastRoot() · isKnownRoot(root) · isSpent(nullifierHash)

Notes

A note is two field elements: nullifier and secret. The commitment is Poseidon(nullifier, secret); the nullifier hash is Poseidon(nullifier). Text form:

qmask-<pool>-<nullifier hex 62>-<secret hex 62>     pool ∈ p100 | p10 | p1

64 bits of the quantum slice are XORed into the nullifier's random bytes before reduction mod the field, on top of the browser's CSPRNG.

Circuit

Circom 2, Groth16 over BN254. Public inputs: root, nullifierHash, recipient, relayer, fee. Private: nullifier, secret, 20 path elements, 20 path indices. 11,335 constraints. The trusted setup is a single-party Powers of Tau (2¹⁴) plus a phase-2 contribution; the files are in the repo so anyone can run the verifier against them.

Quantum split

A job is 8 qubits put in superposition with a Hadamard on each and measured 128 times on IBM Quantum hardware: 1,024 bits. The public record lives at /quantum/latest.json. Each mask takes a 64-bit slice at a rotating offset.

parts   = greedy(amount) over [0.1, 0.01, 0.001]
for each part larger than the smallest pool, while parts ≤ tier.maxParts:
    1 bit → shatter into 10 of the next pool
Fisher-Yates over parts, 6 bits per swap
for each part: delay = round(6 bits / 63 × tier.maxDelay) minutes, de-duplicated

Deterministic: the receipt (job id, offset, amount, tier) replays to the same plan.

Post-quantum key file

The app generates an ML-KEM-768 key pair (FIPS 203) and downloads it as .qmask-key. Notes are sealed into .qmask envelopes: encapsulate → HKDF-SHA256 → AES-256-GCM. Nothing is uploaded.

Relayer

The relayer receives proofs bound to a recipient and a fee, verifies them off-chain, submits those that are due and queues the rest until their quantum delay elapses (a cron releases them every minute). It cannot alter a proof. If it is unavailable, submit the proof yourself: it is valid from any wallet.

POST /api/relay  { pool, a, b, c, root, nullifierHash, recipient, fee, delayMin }
GET  /api/relay?id=<job>

Tiers

Free · Holder (≥ $20) · Pro (≥ $100) · Whale (≥ $1,000) in $QMASK on Robinhood Chain. Tiers change the shatter cap, the flight window and the masks per day. They never change the pool, the circuit or the keys.

What QuantMask does not protect against

Spending the unmasked ETH in a way that identifies you. Reusing the same fresh address across masks. A pool so empty that you are the only depositor. Losing your key file. Read the receipts, use the tiers, and give the pool time.