Skip to main content

Verify a Poker Hand

Every hand we deal is committed to before the cards come out. Once a table's seed is revealed, anyone can re-derive the exact deck, in their own browser, with no login and no trust in us.

How it works

Each poker table publishes a commitment (the SHA-256 hash of a secret server seed) before any hand is dealt. Players can also set a client seed to inject their own randomness. The deck for each hand is shuffled deterministically from those two values plus the hand's nonce:

Server Seedsecret → revealed
+
Client Seedplayers set
+
Noncehand #
HMAC-SHA256combined hash
Fisher-Yates52-card deck
1
Play hands
Note the table's server seed hash (commitment) shown at the table.
2
Reveal the seed
Any seated player can reveal & rotate the table seed, publishing the old server seed.
3
Verify here
Confirm sha256(server_seed) == commitment and re-derive every deck.

Verify

Enter a table ID and hand number. We return the commitment, client seed and nonce for that hand. Once the table seed covering it has been revealed, we also return the server seed and the recomputed deck, and your browser independently re-checks both.

Paste a revealed server seed, the client seed, and the nonce. The deck is recomputed entirely in your browser, so this page never asks our servers for the result. Optionally paste the published commitment to confirm the server seed matches it.

Fully trustless: the hashing (SHA-256 + HMAC-SHA256) and the Fisher-Yates shuffle run locally using your browser's built-in WebCrypto. View source. There's no network call on this tab.

The exact algorithm

So you can re-implement it yourself in any language:

  1. combined = HMAC_SHA256(key=server_seed, message=":"): hex output.
  2. Build an ordered deck: suits [hearts, diamonds, clubs, spades] (outer), ranks [2..10, J, Q, K, A] (inner): 52 cards.
  3. Hash chain: h[0] = combined; h[i] = sha256(h[i-1]) as a hex string, for ceil(52/16)=4 rounds. Concatenate all hex strings → allBytes.
  4. Fisher-Yates: for i = 51 .. 1: j = parseInt(allBytes.substr((51-i)*4, 4), 16) % (i+1); swap deck[i] and deck[j].
  5. Deal order: hole cards one to each seat then a second to each; before each street burn one card (flop = burn + 3, turn = burn + 1, river = burn + 1).
Commitment check: hash the revealed server seed with SHA-256. If it equals the published server_seed_hash, we could not have changed the seed after committing, so we could not have rigged the deck.
Back to Poker