zkShuffle v2 · mental poker, live in your browser
How it works, in one hand
Three players (simulated below, each with its own secret key your browser never shares between them): they aggregate a table key, each one shuffles and re-encrypts the deck themselves, then each hole card is decrypted only by its owner using the other players' decryption shares · and each of those shares is proven correct and checked by the contract on-chain. Watch the log: no party other than the owner ever holds a readable card.
The last step of the lab is the post-hoc audit: every player opens their permutation and randomness, the whole chain is recomputed and any tampering is attributed to the exact stage that did it. Press the cheat button and watch it happen. At a live table that audit is the belt, not the braces · see the next section for what actually guards a real hand.
What a real hand proves, and where
- Verified by the contract, during the hand: every player's Schnorr key proof (a rogue key cannot join and the aggregate table key is formed on-chain); every Chaum–Pedersen decryption share, checked against the committed ciphertext and that seat's per-hand key; and that the shares decrypt to exactly the card being claimed ·
B − Σd == (card+1)·G. A forged share or a lied-about card reverts, so the coordinator cannot put a card on the felt that the cryptography did not produce. A per-deal bitmask also rejects the same card value appearing twice. - Verified by every client, during the hand: the shuffles. Each player's shuffle carries a Wikström zero-knowledge proof that the output deck is a permutation plus re-encryption of the input, with nothing opened afterwards. Every other client fetches the whole transcript and checks all of it (and pins its own stage inside it) before it will hand over a single decryption share, and the deal commits the keccak of that transcript on-chain, so anyone holding it can re-verify the shuffle forever. That is stage R2 of the spec, and it is live · the "at least one honest shuffler" assumption is no longer load-bearing.
- Enforced on-chain when someone vanishes: a missing decryption share becomes an on-chain accusation naming the exact card. The accused client can answer it within a rescue window, which also delivers the withheld share; only an unanswered accusation forfeits that player's committed chips, pro-rata to the other players in the hand and never to the operator.
- Not done: the shuffle argument itself is verified by clients and by the coordinator, not inside a contract · the chain holds its commitment, not its verification. There is no third-party audit yet. And undealt cards are never decrypted at all: only the 2k + 5 ciphertexts actually in play are committed, as hashes with the points passed in calldata, which is what keeps the coordinator's gas at roughly 0.086 STT per completed heads-up hand and 0.14–0.16 STT at four players (measured on Somnia at its fixed 6 gwei base fee; a player's own action costs about 0.001 STT).