← Back to blog

· · Updated

Texas Hold’em: Zero-Knowledge Proofs

Zero-knowledge proof verification is now live for default Hold’em. Learn how encrypted cards, player randomness and two proofs let you check a deal on your device while keeping unshown cards private.

After a Hold’em hand, you want to check that the deal was not manipulated. You also want folded cards to remain private. Can verification respect both wishes?

The idea behind an encrypted deck and a verifiable shuffle is to keep cards hidden while sharing evidence that can be checked. A player can check that the deck is complete, that positions follow the agreed deal, and that revealed cards belong at those positions, without receiving the secret that reconstructs the entire plaintext deck.

Updated October 31, 2026: v2 verifiable dealing is now live for default Hold’em, using an encrypted deck, a verifiable shuffle and decryption proofs. This article now describes the current implementation: how players can check a deal while unshown cards stay private. The separate advanced encrypted dealing mode is unaffected by this replacement.

How to verify now: after a default Hold’em hand ends, a player dealt into that hand can open “Verify fairness” from hand history, or visit the Fairness Verifier to select a recent hand or enter its ID. Sign in with the account that played the hand, preferably using the same browser and device. “Fully verified (witnessed on this device)” requires both valid proofs and complete, matching local evidence.

Why not publish the seed and let everyone replay the shuffle?

A random seed is a starting point for replaying a shuffle. In the old default dealing protocol, participants received the server seed after the hand and could reconstruct the whole deck to check it against the commitment made before dealing. That was easy to understand, but it also exposed folded cards that were never shown.

Default dealing now stops publishing the server’s master seed, decryption key and internal deck seed. Instead, it supplies two kinds of proof: one establishes that the encrypted cards form a complete standard deck; the other establishes which card opens at a particular position. Player randomness stays public. The server’s secret for opening the entire deck does not.

Imagine 52 opaque envelopes on the table

The server puts each card of a standard 52-card deck into an opaque envelope, secretly shuffles the envelopes into a row, and publishes a fingerprint of that row. In the protocol, envelopes are ciphertexts and the fingerprint is a hash commitment binding the public key and all 52 ciphertexts.

The server knows what is inside; players do not. Player randomness then determines a public ordering, such as “envelope 17 goes to the first dealing position.” Everyone can check how the envelopes move without seeing the contents of unopened envelopes.

  1. Seal and commit first: the server publishes the encrypted deck commitment before players submit their randomness.
  2. Determine destinations next: player randomness, the hand identifier and the deck commitment determine a public permutation of the ciphertexts.
  3. Open according to the rules: your hole cards go to you; community cards, showdowns and voluntary shows follow their visibility rules.
  4. Verify afterward: on request, your browser checks the deck, positions and cards you may see, then compares them with evidence saved on your device.

If the server alone arranged the envelopes, it could arrange who gets good cards. If everyone publicly shuffled a face-up deck instead, everyone could calculate each other’s hole cards. Combining a hidden deck with a player-influenced allocation addresses both problems.

This requires at least one honest player to contribute randomness the server could not predict, with nobody withholding committed randomness.

Why do players submit randomness in two rounds?

If everyone simply announced a number, the last person could read the others’ numbers and choose a favorable answer. The implementation keeps a two-round exchange: submit a fingerprint of the answer first, then reveal the answer after everyone has committed.

At the start of a hand, a participating human client that supports the protocol generates 32 random bytes using crypto.getRandomValues. This is the cryptographic random-value interface defined by the W3C Web Crypto specification. The client first submits a hash commitment to that value, then reveals the value in the protocol’s reveal round.

After receiving the deck commitment, the browser submits a hash binding its random value to the hand identifier and seat. Round one freezes the roster and hashes. Round two reveals the values, each of which must match its earlier hash. The values are combined in seat order to help determine the public permutation.

A participant can commit and then refuse to reveal. This is withholding. It does not let them silently replace their number, but it can undermine the fairness assumptions, so it must be recorded, disclosed and reflected in verification. Bots do not contribute these player seeds and cannot stand in for the honest participant.

For you, the crucial checks are that your own randomness was included and that nobody withheld. Those checks connect “I helped determine the deal” to this particular hand.

What do the two proofs establish?

ProofWhat it checksWhat it keeps hidden
Verifiable shuffle proofThe 52 output ciphertexts are a permutation and re-encryption of the standard 52 cards, with no missing, extra or duplicate cards.The secret shuffle mapping and unrevealed card faces.
Decryption proofThe ciphertext at a specified position opens to the displayed card under the committed public key.The decryption key and cards at other positions.

The intuition behind zero knowledge is that you can establish a fact without handing over all the secrets used to prove it. Here, we need both “this is a normal deck” and “the ace of hearts just shown really came from the position that should have been opened.”

A verifier cannot accept every input supplied by the server. It must reconstruct the standard starting deck itself, check the committed key and ciphertexts, recompute the permutation from player randomness, and derive card positions from the frozen seating order. Otherwise, a valid proof could be attached to the wrong position.

The implementation reuses the repository’s verifiable re-encryption shuffle and DLEQ decryption proofs, with WebAssembly verification in the browser.

Why keep evidence on the device if the proof checks out?

Verification has two steps: check the server’s proofs, then compare their commitment, player randomness, dealing positions and cards with the records the browser saved during that hand.

Your browser therefore saves its own witness record: the commitment received before dealing, your randomness, the fixed seating order, withholding status, and every card first observed on that device with its position. The proof must match that record. Later records cannot overwrite the original observation.

The browser retains witness records for the latest 500 hands in local storage; full or unavailable storage can prevent records from being saved. Switching devices, clearing browser storage, missing messages during a disconnect or exceeding that limit can leave incomplete evidence. Verification distinguishes these outcomes:

  • Fully verified (witnessed on this device): valid proofs; complete, matching local evidence; a commitment received before dealing; all player seeds matching their commitments; your seed included; no withholding; an opening at the right position and with the right card for every card observed locally; no failed local check.
  • Server record valid, not fully witnessed on this device: the proofs are valid but the device lacks a complete witness record, so the result establishes only the supplied record’s consistency within the protocol.
  • Failed or unverifiable: invalid proofs, unavailable proofs or an existing local failure cannot receive a passing label. A later valid proof cannot erase a contradiction already detected on the device.

Which cards can be checked, and which remain private?

Verification covers community cards, showdown cards and voluntary shows, including showing just one card. You can also verify your own hole cards, but their decryption proofs go only to you. Other players’ unshown folded cards remain encrypted; verification does not automatically turn them face up.

Rabbit hunting shows what might have come next after a hand ends early. Those cards do not affect the result and are not durably stored by the current implementation, so they are outside verification coverage. The verification page explicitly notes this.

Older hands cannot retroactively acquire the new protocol. Hands from the old default dealing protocol are labeled “old version, not verifiable,” and the verification API no longer returns their seeds. This article covers the live v2 default Hold’em protocol. Zha Jin Hua is outside its scope, and the existing advanced encrypted mode is unaffected by this replacement.

Will generating proofs slow down every hand?

The implementation generates proofs on demand. Before dealing, the server encrypts, shuffles and commits. When someone clicks Verify, it reconstructs that hand’s encrypted deck and generates the shuffle proof plus decryption proofs for cards that user may see. The browser checks them locally.

The master seed deterministically reconstructs the same encrypted deck, but proof generation uses fresh operating-system randomness, not repeatedly derived proof randomness. Different requests may produce different proof bytes while proving the same deck and cards.

Proof computation runs on the server’s blocking thread pool. The verification endpoint allows 30 requests per minute per account.

What does the server store and share?

For default dealing, the server holds each hand’s master seed and uses it to reconstruct the key and encrypted deck. Verification provides the deck commitment, player randomness, shuffle proof and decryption proofs for cards that player may see. It does not provide the server’s master seed or decryption key.

The server stores the master seed with the hand record to generate proofs later. The browser keeps witness records for the latest 500 hands to compare those proofs with the messages it received during play.

The live feature lets you check that the cards you saw came from the complete deck committed before dealing and that allocation used the agreed player randomness. Verification opens only cards you are allowed to see; the rest stay encrypted. For context on the existing modes, read Poker Fairness and Card Privacy and Advanced Encrypted Dealing; those earlier articles describe their stated versions of the mechanisms.