Fairness
Every shuffle and spin on JustPoker is committed to before you play and can be reproduced by you afterwards, and every Crash point and every Live Roulette and Live Baccarat round is fixed by a published hash chain. This page explains the mechanism, publishes the exact algorithms and lets you verify any hand or game in your browser.
In a conventional online card room you have to trust that the shuffle was random and that the operator did not look at your cards or the dealer's before deciding anything. A provably fair shuffle replaces that trust with arithmetic you can check. It works in three moves, known as commit–reveal.
We generate a secret server seed and publish only its SHA-256 hash. The hash pins the seed down without disclosing it — like sealing a prediction in an envelope and handing you the envelope.
Each deck is derived from our secret seed plus a client seed you control and a hand counter. Because your input arrives after the commitment, neither side can steer the result alone.
When the seed is retired we reveal it. You hash it, confirm it matches the commitment you saw, and recompute every deck it produced. If any card differs, the proof fails.
The algorithm below is frozen: the code that deals your hands, the verifier on this page and the reference vectors all implement it byte for byte. Any change would invalidate every previously published hand.
Before a server seed can be used, we generate 32 random bytes, write them as a 64-character hex string and publish SHA-256 of that string on your Fairness & Seeds page. The seed itself stays secret. Because SHA-256 is one-way and collision-resistant, we cannot later swap in a different seed that produces the same hash.
Your client seed is combined with our server seed on every hand. You can change it whenever no hand is in progress, and the seed you choose is applied to a server seed whose hash was already published — so we cannot pick a server seed with your client seed in mind.
The nonce is a counter that starts at 0 for a seed pair and increases by one per hand. The HMAC message is clientSeed:nonce:round, so every hand with the same pair gets a different, fully determined deck. Your hand history records the hash, client seed and nonce for each hand.
HMAC-SHA256 with the server seed as key produces 7 blocks of 32 bytes. Every four bytes form one float in [0, 1). A Fisher–Yates shuffle walks the deck from position 51 down to 1, swapping each position with floor(float × (i + 1)). Exactly 51 floats (204 bytes) are consumed, in order.
Positions 0 and 1 are your hole cards, 2 and 3 the dealer's, 4 to 6 the flop, 7 the turn and 8 the river. There are no burn cards, so the deck alone determines the whole hand. The dealer's cards are held server-side until showdown.
When you rotate your seed pair, the old server seed is revealed and the pre-committed next seed becomes active. Paste the revealed seed, your client seed, the nonce and the published hash into the verifier below: it recomputes the hash and the entire deck in your browser and shows the cards that must have been dealt.
// 1. Commitment — published before the seed is ever used
serverSeedHash = SHA256( utf8(serverSeed) ) // serverSeed: 64 hex chars
// 2. Byte stream — 7 HMAC rounds of 32 bytes each
for i in 0 .. 6:
block[i] = HMAC_SHA256( key = utf8(serverSeed),
message = utf8(`${clientSeed}:${nonce}:${i}`) )
bytes = block[0] ‖ block[1] ‖ … ‖ block[6] // first 204 bytes are used
// 3. Floats — 4 bytes each, 51 floats in [0, 1)
f[k] = bytes[4k] / 256 + bytes[4k+1] / 256² + bytes[4k+2] / 256³ + bytes[4k+3] / 256⁴
// 4. Fisher–Yates shuffle
deck = [0, 1, …, 51]
for i = 51 down to 1: // k = 51 − i
j = floor( f[k] × (i + 1) )
swap deck[i], deck[j]
// 5. Card encoding
rank = card mod 13 // 0 = Two … 8 = Ten, 9 = Jack, 10 = Queen, 11 = King, 12 = Ace
suit = floor(card / 13) // 0 = ♠ spades, 1 = ♥ hearts, 2 = ♦ diamonds, 3 = ♣ clubs
// 6. Deal order — no burn cards
player = deck[0], deck[1]
dealer = deck[2], deck[3]
flop = deck[4], deck[5], deck[6]
turn = deck[7]
river = deck[8]Every card and wheel game on the site is driven by the same commit–reveal scheme and the same HMAC-SHA256 byte stream; Crash, a round shared by every player, uses a hash chain instead (below). Two games extend the byte stream without changing it.
Blackjack uses your own seed pair exactly like Ultimate Texas Hold'em, but the Fisher–Yates shuffle runs over 312 positions instead of 52, consuming 311 floats (39 HMAC rounds). Each position is a card from one of the 6 physical decks. The shoe is derived anew for every round with the next nonce and never persists, so there is no card-counting edge for anyone — including us. The dealer's hole card is position 3 of the shoe; it stays on our server until the dealer's turn.
At a shared table up to five players receive cards from one deck, so the deck cannot depend on a single player's seed. Each table has its own committed server seed, published as a hash before it is used and rotated every 200 rounds. The client seed for a round is the SHA-256 of the round id and the client seeds of every seat that was dealt in, in seat order. The round id itself is the table id, the table seed hash and the round counter — all public before the deal — so nothing about the shuffle is left for the operator to choose once the players are known. Your hand history records the seed inputs and the combined seed for every live round you played.
// Blackjack — a 6-deck shoe from the SAME byte stream, only the shuffle is longer
n = 52 × 6 = 312 // 311 floats = 1244 bytes = 39 HMAC rounds
shoe = [0, 1, …, 311]
for i = 311 down to 1: j = floor( f[k] × (i + 1) ); swap shoe[i], shoe[j]
card(v) = v mod 52, physicalDeck(v) = floor(v / 52)
deal: shoe[0] player, shoe[1] dealer up, shoe[2] player, shoe[3] dealer hole,
then every hit, double, split card and dealer draw from shoe[4] onwards
A fresh shoe is derived for EVERY round (nonce + 1), so nothing carries over.
// Live table — one deck for up to 5 seats, from the TABLE's committed seed
roundId = tableId + ":" + tableSeedHash + ":" + nonce // derived, never chosen
combinedClientSeed = SHA256( roundId + ":" + seatClientSeeds.join(":") ) // seats dealt in, ascending
deck = deriveDeck( tableServerSeed, combinedClientSeed, nonce )
seat k : deck[2k], deck[2k+1] dealer : deck[2n], deck[2n+1]
flop : deck[2n+2 .. 2n+4] turn : deck[2n+5] river : deck[2n+6]
The table seed rotates every 200 rounds: the old seed is revealed, the next hash was already shown.Both use your own seed pair and the next nonce, exactly like the card games. A spin or a coup is decided by the request that places your bets: the result is derived, settled and stored at once, and the animation at the table only presents it.
The winning number is the first float of the same HMAC stream (round 0, the first four bytes) multiplied by 37 and rounded down. The float has 2³² equally likely values, so every pocket from 0 to 36 comes up with a probability within 10⁻⁸ of 1/37. Your bets never enter the calculation: the number is fixed by the seeds and the nonce before the ball is shown.
Baccarat shuffles 416 positions with the same Fisher–Yates procedure as the blackjack shoe and deals from the front: Player, Banker, Player, Banker, then any third cards the fixed tableau calls for, the Player's first. Nobody makes a decision during a coup, so the first four to six cards of the shoe decide the whole round, and the verifier shows which of them were used.
// Roulette — ONE float from round 0 of the same byte stream
bytes = HMAC_SHA256( utf8(serverSeed), utf8(`${clientSeed}:${nonce}:0`) )[0..3]
f = b0/256 + b1/256² + b2/256³ + b3/256⁴ // in [0, 1)
number = floor( f × 37 ) // 0–36, single-zero wheel
Bias: each number is hit by 2³² ÷ 37 of the 2³² floats, ±1 → below 10⁻⁸.
// Baccarat — a fresh 8-deck shoe every round, dealt from the front
shoe = the blackjack shuffle over 416 positions // 415 floats = 52 HMAC rounds
card(v) = v mod 52; points: A = 1, 2–9 face value, 10/J/Q/K = 0; total = sum mod 10
Player shoe[0], shoe[2] Banker shoe[1], shoe[3]
then the fixed tableau: Player third card (if drawn), then Banker third card (if drawn)The daily case of the rewards programme is drawn like a roulette spin: from your own seed pair and its next nonce. The case value and the published table are fixed, and shown to you, before you open it, and the moment you open it changes nothing about the draw.
Opening the case takes the next nonce of your active seed pair, the same counter your Ultimate Texas Hold'em, blackjack, roulette and baccarat rounds use, so no two draws ever share their inputs. The first four bytes of round 0 of the HMAC stream give a float in [0, 1), and the roll is that float times 10,000, rounded down: every roll from 0 to 9,999 is equally likely, to within 10⁻⁹. The server seed's hash was published before you could choose your client seed, exactly as for the games.
A case is worth 5% of the house edge on your bets since your last case (at most the last 24 hours), rounded down to the cent, up to 10¢. It comes only from bets already settled and recorded, and it is stored with the open before the draw. The case opens once its value reaches 4¢, once per UTC day. A refused open (a limit, a pause, the site-wide cap) uses up no nonce and reveals no roll.
The prize is the case value times the multiplier of the row the roll lands on, rounded down to the cent. A published table never changes; a new one would be a new version.
| Row | Rolls | Chance | Multiplier |
|---|---|---|---|
| 0 | 0–3,999 | 40% | ×0.25 |
| 1 | 4,000–6,999 | 30% | ×0.5 |
| 2 | 7,000–8,699 | 17% | ×1 |
| 3 | 8,700–9,499 | 8% | ×2 |
| 4 | 9,500–9,899 | 4% | ×5 |
| 5 | 9,900–9,999 | 1% | ×10 |
The expected multiplier is ×0.88, and prizes are rounded down to the cent, so on average a case pays at most ×0.88 of its value: at most 4.4% of the house edge that set it. The top prize is $1.00, ×10 of a 10¢ case.
The server seed of your active pair stays secret while it can still draw, so a case can be checked once you rotate your seed pair on Fairness & Seeds. After that, each case in your rewards history links to the verifier below with the revealed server seed, your client seed, the nonce, the case value and the table version filled in. Until then it reads "Verifiable after you rotate your seed pair".
Commitment
SHA-256 of the revealed server seed equals the hash shown on your Fairness & Seeds page before the case was opened, so the seed was fixed before you chose your client seed.
Roll
The first four bytes of HMAC-SHA256(serverSeed, clientSeed:nonce:0) give a float, and the roll is floor(float × 10,000): the roulette derivation with 10,000 outcomes instead of 37.
Row
The roll lands on the first row of the published table whose cumulative weight is greater than it.
Prize
With the case value shown before the open, the prize is floor(value × multiplier) in cents, the amount your statement shows for the case.
// Daily case — round 0 of YOUR seed pair's byte stream, at the next nonce
bytes = HMAC_SHA256( utf8(serverSeed), utf8(`${clientSeed}:${nonce}:0`) )[0..3]
f = b0/256 + b1/256² + b2/256³ + b3/256⁴ // in [0, 1)
roll = floor( f × 10000 ) // 0–9999, exact
row = the first row whose cumulative weight > roll // table version 1
prize = floor( V × multiplierBps / 10000 ) // in cents
// The case value V — fixed, and shown to you, before you open it
revenue = the house edge on your bets since your last case, at most the last 24 h
(your fee share in Coinflip and Jackpot, your rake share at Hold'em)
V = min( floor( revenue × 5% ), 10¢ ) // floored to the cent
the case opens once V ≥ 4¢; one case per UTC dayconst { createHmac } = require("node:crypto");
const u32 = createHmac("sha256", serverSeed).update(`${clientSeed}:${nonce}:0`).digest().readUInt32BE(0);
const roll = Math.floor((u32 / 2 ** 32) * 10000);
const table = [[4000,2500],[3000,5000],[1700,10000],[800,20000],[400,50000],[100,100000]];
let row = 0, sum = table[0][0];
while (sum <= roll) sum += table[++row][0];
console.log(roll, row, Math.floor((valueCents * table[row][1]) / 10000));Crash is one round shared by every player, so it cannot use your seed pair. Instead, the crash points of a whole chain of games are fixed before the first of them is played, and a public value nobody controls is mixed in afterwards. Your bets and cash-outs never enter the calculation.
We draw a secret random seed and hash it with SHA-256 over and over, once per game in the chain, and publish only the last hash: the terminating hash. The games use the chain backwards, so game 1 uses the hash just before the terminating hash, game 2 the one before that, and so on. SHA-256 cannot be reversed, so nobody can work out the next game from the ones already revealed, and every revealed game hash leads forward to the terminating hash in exactly its game number of steps.
When a chain is committed we announce a future Bitcoin block, and its terminating hash and that block are published below at once, even while an earlier chain is still being played. The block's hash, which nobody can know until the block is mined, becomes the chain's salt. The salt did not exist when the chain was fixed, so we could not have searched for a chain that favours the house. A chain is never played before its salt is recorded.
Each game's crash point is derived from HMAC-SHA256 of the salt, keyed with the game hash: the first 52 bits give a number X between 0 and 1, and the multiplier is (100 − edge) / (1 − X) hundredths, rounded down and never below 1.00x. The house edge is stored with the chain. A cash-out target x is reached with probability (1 − edge) / x, so every auto cash-out target returns the same share of the stakes on average, 1 − edge. A cash-out by hand returns slightly less, because the server pays it only while the round is still running. A game hash is revealed only after its round has crashed.
46696ec2bd158b3e8deb23481f4bf08b705faa7840aa53e89e5976eb3e2c84f700000000000000000001fafa061ec8eae19be6bea9f93c03910c7cba5ae83045Round numbers at the table are this chain's game numbers, the number the verifier asks for.
// Chain — committed before its first game
h[0] = 32 random bytes as 64 hex chars // the secret seed
h[i+1] = SHA256( utf8(h[i]) ) // hex string in, hex string out
terminatingHash = h[L] // published first; L = chain length
gameHash(n) = h[L − n] // game n = 1 … L: the chain backwards
check: SHA256 applied n times to gameHash(n) = terminatingHash
// Crash point — salt = the hash of a Bitcoin block announced at commitment
h = HMAC_SHA256( key = utf8(gameHash), message = utf8(salt) )
r = parseInt( h[0..12], 16 ) // first 13 hex = 52 bits
X = r / 2^52 // in [0, 1)
crashX100 = max( 100, floor( (100 − edge) / (1 − X) ) ) // edge in percent, stored with the chain
multiplier = crashX100 / 100
P(multiplier ≥ x) = (1 − edge / 100) / x // for every cash-out target xAt Live Roulette and Live Baccarat everyone bets on the same round, so no player's seed can decide it. Each table plays its own pre-committed hash chain, salted with a future Bitcoin block exactly like Crash, and the round's game hash goes into the same frozen derivation as the single-player wheel and shoe. Your bets never enter the calculation.
Each table has an independent chain: a secret random seed hashed with SHA-256 once per game, of which only the last hash, the terminating hash, is published, together with the Bitcoin block whose hash will become the salt. Games use the chain backwards, so every revealed game hash leads forward to the terminating hash in exactly its game number of steps, and nobody can work out the next one. Round numbers continue from one chain to the next; the game number within the chain is shown with every round.
The game hash is used as the server seed, the salt as the client seed and the nonce is always 0. A Live Roulette number is the first float of that HMAC stream times 37, rounded down, exactly like a single-player spin; a Live Baccarat coup is dealt from the front of a fresh 8-deck shoe, exactly like a single-player coup. The outcome is computed at "No more bets", when no stake can change any more, and the game hash is published with the result.
Chain
SHA-256 applied to the round's game hash as many times as its game number within the chain gives the published terminating hash. The game was therefore fixed before any game of the chain was played, and before the salt existed.
Salt
The chain's salt is the hash of the Bitcoin block announced when the chain was committed: compare it on any block explorer. A development salt, used only outside production, is labelled as such.
Outcome
The winning number is floor(f × 37) for the first float of HMAC-SHA256(gameHash, salt:0:0); the coup is dealt from the front of the 8-deck shoe shuffled with the floats of HMAC-SHA256(gameHash, salt:0:i). These are the single-player derivations, unchanged.
Settlement
Every ticket is settled from that outcome by the single-player engine with the same payouts, and your hand history re-settles your bets from the stored round each time it is read.
We hold each chain's seed, so we know every future outcome; the commitment means we cannot choose them. The salt did not exist when the chain was fixed, so we could not search for a chain that favours the house, and the order of the games is fixed. The one lever left would be cancelling rounds by restarting the server while bets are open. A cancelled round debits nothing, and every voided round's game hash and would-be result is published below, so a pattern would be visible to anyone.
// Chain — one per table, committed before its first game (the Crash scheme)
h[0] = 32 random bytes as 64 hex chars // the secret seed
h[i+1] = SHA256( utf8(h[i]) ) // hex string in, hex string out
terminatingHash = h[L] // published first; L = chain length
gameHash(g) = h[L − g] // game g = 1 … L of the chain
roundNumber = baseGame + g // continues across a table's chains
salt = hash of the Bitcoin block announced at commitment
check: SHA256 applied g times to gameHash(g) = terminatingHash
// Live Roulette — the single-player spin, serverSeed = gameHash, clientSeed = salt, nonce 0
bytes = HMAC_SHA256( key = utf8(gameHash), message = utf8(salt + ":0:0") )[0..3]
f = b0/256 + b1/256² + b2/256³ + b3/256⁴ // in [0, 1)
number = floor( f × 37 ) // 0–36
// Live Baccarat — a fresh 8-deck shoe every coup, the same three inputs
f[k] = floats of HMAC_SHA256( utf8(gameHash), utf8(salt + ":0:" + i) ) // 415 floats
shoe = Fisher–Yates over 0 … 415; card(v) = v mod 52
coup = Player shoe[0], shoe[2] · Banker shoe[1], shoe[3] · then the fixed tableauconst { createHash, createHmac } = require("node:crypto");
let h = gameHash; for (let i = 0; i < chainGame; i++) h = createHash("sha256").update(h).digest("hex");
console.log(h === terminatingHash);
const k = createHmac("sha256", gameHash).update(`${salt}:0:0`).digest().readUInt32BE(0);
console.log(Math.floor((k / 2 ** 32) * 37));2552424f3afa694e0b850df536b43511539a4c8d483cf47ae5378e0bd4431cda00000000000000000000b98b89d38a790b7dc4a952b97384ece9b477f777f7bdRound numbers at the table are this chain's game numbers, the number the verifier asks for.
1 round has been voided by a restart while bets were open: nothing was debited. It is listed with the result each would have had.
966cb402…373be62d244baee6ad59ce2322c0c3da92c64698422f602cfb0f3208936da3d2cea9a500000000000000000000b98b89d38a790b7dc4a952b97384ece9b477f777f7bdRound numbers at the table are this chain's game numbers, the number the verifier asks for.
1 round has been voided by a restart while bets were open: nothing was debited. It is listed with the result each would have had.
756798e6…800f78Games of the published test chain of the Crash vectors below (100 hashes, its seed public because it is never played), salted with the Bitcoin genesis block hash. Each game hash hashes forward to the terminating hash 79c72c9b3706a559536454b9e12185a390fb5f63b2b7d30150527ef02e03bfab in exactly its game number of steps. Game 19 lands on zero.
| # | Game | Game hash | HMAC, first 8 hex | Float | Number | Action |
|---|---|---|---|---|---|---|
| 1 | 1 | 8509059441…521b78 | 15329830 | 0.082803260535 | 3 Red | Verify |
| 2 | 2 | 51bc667c67…48d513 | c370c85e | 0.763439677190 | 28 Black | Verify |
| 3 | 19 | d90f2fb65d…9997e0 | 05403637 | 0.020511043957 | 0 Green | Verify |
| 4 | 38 | 5b49ee55cc…641fc9 | de7d31db | 0.869097820250 | 32 Red | Verify |
| 5 | 99 | 0fdef169ef…b1f857 | bbc98a75 | 0.733544019284 | 27 Red | Verify |
Games of the same test chain: every coup size, a natural, a coup where both sides draw, and a Tie. The shoe hash covers all 416 raw values of the game's fresh shoe.
| # | Game | Game hash | First six cards | Player · Banker | Shoe hash | Action |
|---|---|---|---|---|---|---|
| 1 | 1 | 8509059441…521b78 | 3h Ac 9d 3h Jh 3d | 3h 9d Jh (2) · Ac 3h (4)Banker wins · 5 cards | 76b60ac8cc…874371 | Verify |
| 2 | 2 | 51bc667c67…48d513 | Jd 4h 8c 5s Kc Jh | Jd 8c (8) · 4h 5s (9)Banker wins · 4 cards | 55a3d3bd4b…91fb5c | Verify |
| 3 | 3 | db182f415a…d37ab8 | Qc 8c 7h 9c 8s 8d | Qc 7h (7) · 8c 9c (7)Tie · 4 cards | aaee00b430…c3159a | Verify |
| 4 | 6 | 29ed2dc830…1eeec9 | 5s 2d 6d 2s 6d 7h | 5s 6d 6d (7) · 2d 2s 7h (1)Player wins · 6 cards | 2aeb10aeb8…b26283 | Verify |
In Coinflip and Jackpot you play other players. The house is never a party: it takes 5% of the pot and nothing else. Each result comes from a server seed committed when the game opens and a round of drand, a public randomness beacon, that is fixed when the entries close and published a few seconds later. Nobody, us included, can know a result while a stake can still change.
Every flip and every jackpot round gets its own secret server seed when it is created. Its SHA-256 hash is shown at once in the lobby or on the round, and the seed itself is revealed only when the game has ended. We cannot change the seed afterwards without the hash giving it away.
The moment a flip is joined, or a jackpot countdown ends, the server fixes a round of drand quicknet, the public randomness beacon of the League of Entropy: 2 rounds after the latest published one, so it appears 3 to 6 seconds later. A drand value is a signature that a threshold of independent nodes produce together; nobody, the operator included, can know it before they do. The game settles from it as soon as it appears.
HMAC-SHA256, keyed with the server seed, over the game's number, the round and its randomness (Jackpot adds the entries hash) gives 48-bit numbers. The first one below a limit that is a multiple of the number of outcomes decides, so every outcome has exactly the same chance. Coinflip takes it modulo 2: 0 is heads, 1 is tails. Jackpot takes it modulo the pot in cents: one ticket per cent, so each player wins with exactly their share of the pot.
Commitment
SHA-256 of the revealed server seed equals the hash published when the game opened, before anyone could join or deposit.
Entries hash
Jackpot only: the entries, hashed in seq order, give the hash published at the close. The ticket table was fixed before the beacon value existed.
Timing
The beacon round was published 3 to 6 seconds after the entries closed (the check allows 1 s of slack), so it did not exist when the last stake was accepted.
Beacon
The randomness is SHA-256 of drand's signature, and the signature verifies against drand quicknet's public key. The verifier checks the signature in your browser; you can also open the round on any drand relay.
Result
HMAC-SHA256 keyed with the server seed over the game number, the round and its randomness (and the entries hash) gives the face or the winning ticket, and with it the winner and the payout.
// Commitment — when the flip is created / the round opens
S = 32 random bytes as 64 hex chars // the server seed, secret until the game ends
commitment = SHA256( utf8(S) ) // published at once
// Beacon round — fixed in the transaction that closes entries (the join; the end of the countdown)
R = beaconRoundAt(closedAt) + 2 // appears 3–6 s after the close
publish(R) = (1692803367 + (R − 1) × 3) × 1000 ms // drand quicknet's schedule
ρ = randomness of drand quicknet round R // = SHA256(signature bytes)
// Jackpot — the ticket table, hashed and published at the close (before ρ exists)
entriesHash = SHA256( "1:alice:500|2:bob:1500|…" ) // seq:username:amountCents, seq order
tickets = [0, a1), [a1, a1 + a2), … // one ticket per cent, seq order
// uniformInt(key = S, message, n) — exactly uniform, no modulo bias
B[i] = HMAC_SHA256( key = S, message + ":" + i ) // i = 0, 1, 2, …
u = the next 48-bit big-endian chunk of B[i] // 5 per block
limit = 2^48 − (2^48 mod n)
result = u mod n, for the first u < limit
coinflip: face = uniformInt(S, "coinflip:" + number + ":" + R + ":" + ρ, 2) // 0 heads, 1 tails
jackpot: ticket = uniformInt(S, "jackpot:" + number + ":" + R + ":" + ρ + ":" + entriesHash, pot)
winner = the entry whose [from, to) contains ticketconst { createHash, createHmac } = require("node:crypto");
const sha = (s) => createHash("sha256").update(s, "utf8").digest("hex");
function uniformInt(key, message, n) {
const N = BigInt(n), R = 2n ** 48n, limit = R - (R % N);
for (let i = 0; ; i++) {
const b = createHmac("sha256", key).update(`${message}:${i}`).digest();
for (let c = 0; c < 5; c++) {
const u = BigInt("0x" + b.subarray(c * 6, c * 6 + 6).toString("hex"));
if (u < limit) return Number(u % N);
}
}
}
// Coinflip vector #1
const S = "3f9a1c8e6b2d4f7a9c0e1b3d5f7a9c2e4b6d8f0a1c3e5b7d9f1a3c5e7b9d0f2a";
const rho = "b22aad4794f7451896f7a371aa46106fd84d919f3f569acd5b2fddf1d1440af3";
console.log(uniformInt(S, `coinflip:1:1000000:${rho}`, 2)); // 0 = heads
// Jackpot vector #1
const J = "3f9a1c8e6b2d4f7a9c0e1b3d5f7a9c2e4b6d8f0a1c3e5b7d9f1a3c5e7b9d0f2a";
const eh = sha("1:alice:500|2:bob:1500");
console.log(uniformInt(J, `jackpot:1:1000000:b22aad4794f7451896f7a371aa46106fd84d919f3f569acd5b2fddf1d1440af3:${eh}`, 2000)); // 238 = aliceIn a game against the house, the house is already the other side. Here it must stay neutral, so the case that matters is an operator playing through an account of its own, knowing every secret on the server.
We pick the server seed after seeing who plays.
Its SHA-256 is published when the game opens. Any other seed would not match it.
An account of ours joins only the flips it would win.
When the last stake is accepted, the value that decides the result does not exist yet: drand publishes it 3–6 seconds later. Knowing the seed tells nobody the result, us included.
A last-second jackpot deposit sized to win.
Same answer: the result does not exist yet. A late deposit buys its share at the same price as any other, and the countdown never extends.
We reorder the jackpot tickets after the draw.
The entries hash is published at the close, before the beacon value exists, and it is part of what is hashed into the result.
We cancel a game, or restart the server, after seeing a bad result.
A game whose beacon round is fixed is never voided, not even by a restart: it waits for its round and settles. The only refund of such a game is an audited admin action after 10 minutes without the round, and it stays on the public list of refunded games with its round number, so anyone can check whether drand had published it.
We claim the entries closed earlier, to reuse a value already published.
The round comes from the moment the close was processed, and the verifier checks that it was published a few seconds after the recorded close.
Someone fakes the beacon value (a hijacked relay, DNS or network).
Every value carries drand's BLS signature, checked against drand quicknet's public key by the server and by this verifier.
A player cancels after someone joined, or two players join one flip.
Every change is one database transaction that only succeeds while the game is still open. A joined flip cannot be cancelled.
That a threshold of the drand nodes, run by independent universities and companies, does not conspire with us. Nothing else: the seed is committed, the round is in the future when entries close, the entries are hashed before the value exists, and the arithmetic is public. The house never plays and takes 5% of the pot; every player's expected return is 95% of what they put in, whatever their share.
If drand is unreachable, joins and deposits pause and games already drawing wait for their round: nothing is lost and no result is chosen by us.
A game still waiting for its round can only be refunded by an audited admin action after 10 minutes. Every such refund stays listed, newest first, with its beacon round to check on drand.
Every refunded flip and roundA new round every 3 seconds since 2023-08-23. Each value is a BLS12-381 signature of the round number (bls-unchained-g1-rfc9380); its randomness is SHA-256 of the signature.
52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e97183cf0f2896adee7eb8b5f01fcad3912212c437e0073e911fb90022d3e760183c8c4b450b6a0a6c3ac6a5776a2d1064510d1fec758c921cc22b0e17e63aaf4bcb5ed66304de9cf809bd274ca73bab4af5a6e9c76a4bc09e76eae8991ef5ece45aThe creator stakes an amount on heads or tails; a joiner stakes the same amount on the other side. The join fixes the beacon round, and the face decides: the winner takes the pot less the fee.
0fdef169ef…b1f857 is shown in the lobby.b22aad4794…440af3.coinflip:1:1000000:b22aad4794f7451896f7a371aa46106fd84d919f3f569acd5b2fddf1d1440af3.70b9780c8d9c: the first chunk is 123,941,885,349,276. For two outcomes every chunk is accepted.Every finished flip has a Verify link, in the lobby's results, on the flip stage and in your history. It opens the verifier below with every value filled in from the flip: the seed, its commitment, the beacon round with its signature, the creator's side and the time it was joined. You can also type the values yourself, or load any finished flip by its number: flips are numbered in order across the whole lobby, and every finished one can be checked by anyone.
Frozen inputs and outputs, recomputed by an independent implementation in our tests. #1 uses a real drand round; the others use the development beacon (development beacon (predictable; local testing only)) so they cover both faces and both winners.
| # | Flip | Beacon round | Creator | First chunk | Face | Winner | Action |
|---|---|---|---|---|---|---|---|
| 1 | 1 | 1,000,000drand | Heads | 123,941,885,349,276 | Heads | Creator | Verify |
| 2 | 2 | 32,689,921dev | Tails | 198,758,594,205,578 | Heads | Joiner | Verify |
| 3 | 123 | 32,690,000dev | Heads | 208,522,163,183,032 | Heads | Creator | Verify |
| 4 | 4,096 | 33,000,000dev | Tails | 234,010,210,058,384 | Heads | Joiner | Verify |
| 5 | 1,000,000 | 40,000,000dev | Heads | 182,386,310,906,645 | Tails | Joiner | Verify |
Every cent deposited is one ticket, numbered in deposit order. When the countdown ends the entries are hashed and the beacon round is fixed; one ticket wins the pot less the fee, so your chance is exactly your share of the pot.
2e330b18c2…33a5b5 is published, and drand round 1,000,000 is fixed.Every finished round has a Verify link, on the round strip and in your history: it fills in the seed, its commitment, the beacon round and its signature, every entry and the entries hash, and the close time. The verifier draws the ticket line with every entry's range and marks the winning ticket. A round holds at most 25 players and 125 entries.
#1 uses the same real drand round as Coinflip #1. #5 has a pot far beyond any real round (140,737,488,355,329 cents) so that chunks are rejected: it shows the rejection step at work.
At the Hold'em cash tables you play other players; the house only deals the cards and takes the rake, and never plays a hand. Every hand is dealt from one deck, so it uses the shared-table scheme of the live table above: a table seed committed before its first hand, and a client seed every player dealt in contributes to. Nothing about the shuffle is left to choose once the players are known.
Each table has its own secret server seed. Its SHA-256 hash is shown at the table and in the lobby before the seed deals a hand, and the hash of the next seed is already public too. A seed deals at most 100 hands, or for 6 hours once it has dealt one, and is then retired between two hands, also at a table that has stopped playing. The nonce of a hand is the seed's hand counter at the deal.
The hand id is the table id, the seed hash and the nonce, so it is fixed before the deal. The client seed of the hand is the SHA-256 of the hand id and the client seeds of every seat dealt in, in ascending seat order. You can change your client seed on your Fairness & Seeds page at any time; it counts from your next hand. Because each player adds entropy the operator does not choose, no deck can be prepared for known seeds.
The deck is the single-player shuffle with the table seed, the combined seed and the nonce. The k-th dealt seat in seat order gets positions 2k and 2k + 1, and the board follows: the flop, the turn and the river, with no burn cards. Board cards are fixed at the deal but sent only as they are dealt. A hand interrupted by a server restart is voided and refunded; its nonce is used up and the hand stays listed in the table's history.
A retired table seed is revealed no sooner than 1 hour after its last hand and no later than 1 hour after it is retired, not at once. A revealed seed lets anyone with a hand's inputs re-derive its whole deck, so an immediate reveal would show the cards of a seed's last hands to players who are still at the table. A hand can therefore be verified at most 100 hands or 6 hours, plus 1 hour, after it was dealt, even when the table stops playing. The table's Fairness tab shows the last revealed seed and when the next retired one is revealed.
Before the reveal, hole cards go only to their owner, and other players see them only when they are shown: an all-in that ends the betting, the first hand shown and every pot winner at showdown, or a player who chooses to show. Folded and mucked hands are never sent to anyone and never appear in other players' histories. After the reveal, anyone who has a hand's inputs (they are shown at the table and in its players' hand histories) can work out every card of the hand, folded and mucked ones included. A deal that can be checked cannot keep them secret for ever; the rules and the Terms say so.
Commitment
SHA-256 of the revealed table seed equals the hash shown at the table before the hand, so the seed was fixed before any card of the hand was dealt.
Hand id
The hand id is tableId:serverSeedHash:nonce, all public before the deal. It is part of the combined seed, so an id chosen at deal time would have been a free input; a derived one leaves exactly one deck.
Combined seed
SHA-256 of the hand id and the client seeds of every seat dealt in, in ascending seat order, equals the combined seed shown with the hand. Your hand history lists those seeds: your own is among them.
Deal
The deck from deriveDeck(tableSeed, combinedSeed, nonce) gives each dealt seat its two cards and the board from fixed positions, with no burn cards. They are the cards of the hand.
// Table seed — committed before its first hand
serverSeedHash = SHA256( utf8(tableServerSeed) ) // shown at the table and in the lobby
nonce = the seed's hand counter at the deal // 0 … 99
// Hand id and combined client seed — both fixed before the deal
handId = tableId + ":" + serverSeedHash + ":" + nonce // derived, never chosen
combinedClientSeed = SHA256( handId + ":" + seatClientSeeds.join(":") ) // dealt seats, ascending
// Deck — the single-player shuffle, unchanged
deck = deriveDeck( tableServerSeed, combinedClientSeed, nonce )
// Deal — n dealt seats in ascending seat order, no burn cards
seat k : deck[2k], deck[2k+1] // k = 0 … n−1
flop : deck[2n .. 2n+2] turn : deck[2n+3] river : deck[2n+4]
// Rotation and reveal
retired after 100 hands, or once 6 hours old (also at an idle table; never mid-hand)
revealed no sooner than 1 hour after its last hand and no later than 1 hour after it is retired; the next seed's hash is already publicconst { createHash, createHmac } = require("node:crypto");
const sha = (s) => createHash("sha256").update(s).digest("hex");
const handId = `${tableId}:${sha(serverSeed)}:${nonce}`;
const combined = sha(`${handId}:${seatClientSeeds.join(":")}`);
const bytes = Buffer.concat([0, 1, 2, 3, 4, 5, 6].map((i) =>
createHmac("sha256", serverSeed).update(`${combined}:${nonce}:${i}`).digest()));
const deck = [...Array(52).keys()];
for (let i = 51, k = 0; i >= 1; i--, k++) {
const f = bytes.readUInt32BE(4 * k) / 2 ** 32;
const j = Math.floor(f * (i + 1));
[deck[i], deck[j]] = [deck[j], deck[i]];
}
const n = seatClientSeeds.length;
console.log(handId, combined);
console.log(deck.slice(0, 2 * n), deck.slice(2 * n, 2 * n + 5));Re-derive any round from its seeds and nonce. Pick the game: the single-player deck (commitment, 52-card order, the nine cards dealt and both hands evaluated), the blackjack shoe (commitment, opening deal, the first sixteen cards and the full 312-card shoe with its hash), a roulette spin (commitment, the four bytes, the float and the winning number), a baccarat coup (commitment, both hands dealt from the 8-deck shoe with every third-card rule, and the winner), a daily case open (commitment, the four bytes, the float, the roll, the row of the published table and, with the case value, the prize), a live-table round (commitment, combined seed, every seat's cards, the dealer and the board), a Hold'em cash-table hand (commitment, the derived hand id, the combined seed, every dealt seat's hole cards and the board), a Crash game (the crash point and its place in the chain), a Live Roulette or Live Baccarat round (the winning number or the coup, and its place in the table's chain), or a Coinflip or Jackpot game (the commitment, the beacon round with its timing and drand signature, and the face or the winning ticket). Hand history and round "Verify" links open the right mode with the fields filled in.
Choose the game, then copy the values from the hand's detail page or from a revealed seed. Everything is computed in your browser.
Results appear here.
You will see whether the table seed matches its commitment and the hand id was derived from it, every dealt seat's hole cards, the board and the full deck — and, if you add the seat client seeds, whether the combined client seed was built from them. A table seed is revealed no sooner than 1 hour after its last hand and no later than 1 hour after it is retired. Use Load example to try it with a published test vector.
These inputs and outputs never change. They are checked by our automated tests on every release, and an independent implementation of the algorithm must reproduce them. Each row opens in the verifier.
| # | Server seed | Client seed | Nonce | First nine cards | Deck hash | Action |
|---|---|---|---|---|---|---|
| 1 | 3f9a1c8e6b…9d0f2a | justpoker | 0 | 5c 8c 5h 7s 6s Ts Ks As 3c | b971417169…f39c5e | Verify |
| 2 | 3f9a1c8e6b…9d0f2a | justpoker | 1 | 6h 5h 7h 3h 4h 2s Tc 8d 7d | 486e5b7015…b2d62f | Verify |
| 3 | c0ffee00de…abcdef | player-client-seed_01 | 12345 | Ad As Tc 5h 7h 5s 8d Kc 6s | b65678656a…1df056 | Verify |
| 4 | 0000000000…000000 | a | 0 | 8d Qc 6s 5h 3d Ts 6c 2s 4d | 24a4549278…cede1c | Verify |
The first sixteen cards in deal order (card identity only) and SHA-256 of the whole shoe's raw values.
| # | Server seed | Client seed | Nonce | Decks | First sixteen cards | Shoe hash | Action |
|---|---|---|---|---|---|---|---|
| 1 | 3f9a1c8e6b…9d0f2a | justpoker | 0 | 6 | 8d Jc Tc 4h Ts 9d 3s 3h Ah Th 8d Jc Qs 5s 6d Kc | 3d289d102e…d0f20a | Verify |
| 2 | c0ffee00de…abcdef | player-client-seed_01 | 12345 | 6 | 7d Ah Jh Tc 5h 9h Ah 3s Qh Td 8c 4s 5d 7c 8c 6s | e7195dab0b…b8ee72 | Verify |
| 3 | 0000000000…000000 | a | 7 | 8 | 3s Td 6s Qd 4c 7d Qd Js 5c 8h 4d 9h Ts 6d 2h Qh | 761e669147…f30842 | Verify |
The float from the first four bytes of round 0 and floor(float × 37). The last vector lands on zero.
| # | Server seed | Client seed | Nonce | Float | Number | Action |
|---|---|---|---|---|---|---|
| 1 | 3f9a1c8e6b…9d0f2a | justpoker | 0 | 0.829814557917 | 30 Red | Verify |
| 2 | 3f9a1c8e6b…9d0f2a | justpoker | 1 | 0.252318835817 | 9 Red | Verify |
| 3 | c0ffee00de…abcdef | player-client-seed_01 | 12345 | 0.894200468669 | 33 Black | Verify |
| 4 | 0000000000…000000 | a | 0 | 0.434974659700 | 16 Red | Verify |
| 5 | 0123456789…abcdef | roulette | 2 | 0.025302330265 | 0 Green | Verify |
The first six cards of the shoe, the two hands they deal and the winner: a natural, a coup where both sides draw, and a Tie. The shoe hash covers all 416 raw values.
| # | Server seed | Client seed | Nonce | First six cards | Player · Banker | Shoe hash | Action |
|---|---|---|---|---|---|---|---|
| 1 | 3f9a1c8e6b…9d0f2a | justpoker | 0 | Ks 6d Qs 3c Th Ts | Ks Qs (0) · 6d 3c (9)Banker wins | 1c3f715ca0…c9d81c | Verify |
| 2 | c0ffee00de…abcdef | player-client-seed_01 | 4 | 2s Ah Ts Ad Ts 3c | 2s Ts Ts (2) · Ah Ad 3c (5)Banker wins | ed8065f851…0c8974 | Verify |
| 3 | 0000000000…000000 | a | 6 | 2c 7s Ac Kd 4c 4s | 2c Ac 4c (7) · 7s Kd (7)Tie | 0bee2d259a…344c97 | Verify |
The float from the first four bytes of round 0, the roll floor(float × 10,000), the row it lands on and the prize for the case value shown. One vector lands on each row of the table.
| # | Server seed | Client seed | Nonce | Float | Roll | Row · value · prize | Action |
|---|---|---|---|---|---|---|---|
| 1 | 3f9a1c8e6b…9d0f2a | justpoker | 1 | 0.252318835817 | 2,523 | 0 · ×0.25 · 4¢ → 1¢ | Verify |
| 2 | c0ffee00de…abcdef | player-client-seed_01 | 0 | 0.563436162192 | 5,634 | 1 · ×0.5 · 7¢ → 3¢ | Verify |
| 3 | 0123456789…abcdef | daily-case | 2 | 0.755016283365 | 7,550 | 2 · ×1 · 10¢ → 10¢ | Verify |
| 4 | 3f9a1c8e6b…9d0f2a | justpoker | 8 | 0.918215087149 | 9,182 | 3 · ×2 · 5¢ → 10¢ | Verify |
| 5 | c0ffee00de…abcdef | player-client-seed_01 | 13 | 0.964259204688 | 9,642 | 4 · ×5 · 9¢ → 45¢ | Verify |
| 6 | 0123456789…abcdef | daily-case | 125 | 0.990645141341 | 9,906 | 5 · ×10 · 6¢ → 60¢ | Verify |
These vectors pin the combined-seed hash and the seat deal order. Their round ids are free-form test values; at a real table the round id is always tableId:tableSeedHash:nonce.
| # | Table seed | Round id · seat seeds | Nonce | Seats | Dealer · board | Deck hash | Action |
|---|---|---|---|---|---|---|---|
| 1 | 3f9a1c8e6b…9d0f2a | round-0001alice, bob, carol | 0 | 4c Qc · 3d Td · Qh 9s | Ts 7s · 6d 3h 8c 9d 6c | 9f3978fdde…8e95d8 | Verify |
| 2 | c0ffee00de…abcdef | 7b1f0c3e-2d4a-4f6b-8e9d-0a1b2c3d4e5fjustpoker, player-client-seed_01, x, seat-4, Zz_- | 199 | Ac 5d · Js 3s · Qh Jd · Kc Kd · 9s 7s | 8h 2d · Kh Ad Ks Qd 9c | d0a3c10485…702b97 | Verify |
These vectors pin the derived hand id, the combined seed of the dealt seats' client seeds, each dealt seat's hole cards and the board. Seats are numbered from 0; the last vector deals all nine seats of a full table.
| # | Table seed | Hand id · seat seeds | Dealt seats | Hole cards | Board | Deck hash | Action |
|---|---|---|---|---|---|---|---|
| 1 | 5e2b8c41d7…20c95a | nl10:b79a92…ed27:0alice, bob-2, Carol_3 | 0, 2, 5 | 4d Kh · Jh Jd · Js Ks | 7c 6d 2c 5d 8s | 4221646eed…96c015 | Verify |
| 2 | a7c3e9f1b5…1b3d5e | hu50:854407…2056:99heads, up | 0, 1 | 8d 9d · Jc 2c | 6d 3h Js 9h 8c | a6de162f75…9341d1 | Verify |
| 3 | 0123456789…abcdef | nine-max:a8ae6e…7c8e:42s0, s1, s2, s3, s4, s5, s6, s7, s8 | 0, 1, 2, 3, 4, 5, 6, 7, 8 | Qh 8s · Th 9s · 4c 5s · Ah 2c · Qd Qc · 3h Kh · Tc 3s · Qs 4h · 5c 5d | Jc 2h 7s 9h Jh | 38d3398b22…ea9e45 | Verify |
Games from a published test chain of 100 hashes, salted with the Bitcoin genesis block hash, at a 2% edge. Its seed is public because it is never played: 3f9a1c8e6b2d4f7a9c0e1b3d5f7a9c2e4b6d8f0a1c3e5b7d9f1a3c5e7b9d0f2a. Every game hash hashes forward to its terminating hash 79c72c9b3706a559536454b9e12185a390fb5f63b2b7d30150527ef02e03bfab in exactly its game number of steps.
| # | Game | Game hash | HMAC, first 13 hex | r | Crash point | Action |
|---|---|---|---|---|---|---|
| 1 | 1 | 8509059441…521b78 | 60f4e053b03bf | 1705677629883327 | 1.57x | Verify |
| 2 | 2 | 51bc667c67…48d513 | bd7e65196d4e4 | 3333608955106532 | 3.77x | Verify |
| 3 | 6 | 29ed2dc830…1eeec9 | f79d2aca1fb8f | 4356070397049743 | 29.91x | Verify |
| 4 | 38 | 5b49ee55cc…641fc9 | 06a88b76f5706 | 117135425623814 | 1.00x | Verify |
| 5 | 99 | 0fdef169ef…b1f857 | 0874b1539e623 | 148756548412963 | 1.01x | Verify |
The deck is a pure function of three inputs: the server seed, your client seed and the nonce. The server seed is fixed the moment its hash is published, which happens before you can influence anything. If we altered the seed afterwards, SHA-256 of the revealed seed would no longer match the hash you were shown, and the verifier would report a mismatch.
We also cannot choose a favourable seed in advance, because your client seed — which we do not know when the server seed is committed — changes every deck. Nothing in the algorithm depends on the bets you place or the decisions you make during the hand.
A revealed server seed lets anyone compute every future deck for that pair, including the dealer's hole cards. That is why a seed is only revealed once it is retired. Rotation retires the active seed, activates the next seed (whose hash you have already seen) and immediately commits a fresh next seed, so there is always a published commitment waiting.
Rotation is refused while a hand is in progress, because revealing the seed mid-hand would expose the dealer's cards.
Your client seed is your contribution to the randomness. Setting your own value after the server seed hash is published proves that the deck could not have been pre-selected: we would have needed to know your seed in advance. The default is random; typing something of your own makes the guarantee personal rather than a matter of trust in our generator.
Changing the client seed never creates a new server seed. The nonce keeps counting and each hand records the client seed it was dealt with.
Yes. Every hand in your hand history stores the server seed hash, the client seed and the nonce it was dealt with. Once the seed pair has been rotated, the hand's detail page links straight to this verifier with the values filled in — in the right mode for a blackjack round, a roulette spin or a baccarat coup. Hands dealt with the currently active pair can be verified as soon as you rotate.
Live-table hands are dealt from the table's own seed rather than yours. Their detail page shows the table seed hash, every seated player's client seed and the combined seed, and links to the live-table verifier once the table seed has dealt its 200 rounds and been revealed.
A Crash bet links to the Crash verifier as soon as its round has crashed, with the game hash, the salt and the chain's terminating hash filled in.
A Live Roulette or Live Baccarat bet links to its table's verifier once the round's result is shown, with the game hash, the salt, the terminating hash and the game number within the chain filled in.
A Hold'em cash-table hand's detail page shows the table seed hash, the hand id, the nonce, every dealt player's client seed and the combined seed, and links to the Hold'em verifier. The table seed is filled in once it is revealed, no sooner than 1 hour after its last hand and no later than 1 hour after it is retired.
A daily case is listed in your rewards history with its nonce. Once you rotate the seed pair it was drawn from, it links to the daily case verifier with the revealed seed, the case value and the table version filled in.
Everyone at the table bets on the same spin or coup, and players join and leave between rounds, so the result cannot depend on one player's seed, and mixing in everyone's seeds would let the last player to join steer it. Each table instead plays a hash chain fixed before its first round and salted afterwards with the hash of a Bitcoin block, as Crash does.
Bets are only reserved while betting is open and are debited at "No more bets", the moment the outcome is computed from the round's game hash. The game hash is published with the result, and the verifier re-derives the number or the coup and checks the hash against the table's published chain.
Every player shares one Crash round, so no single player's seed can decide it, and mixing in the seeds of everyone who bet would let the last player to bet steer the result. Instead, every game of a chain is fixed by the hash chain before the first of them is played, and the salt (the hash of a Bitcoin block nobody could know in advance) is fixed after the chain was published.
Each game hash is revealed when its round crashes. The verifier re-derives the crash point from it and checks that it hashes forward to the published terminating hash, which proves the game was part of the chain all along.
The house does not play: there is no bot, and it only takes its fee. Even an account we controlled could not know a result in advance. We hold each game's server seed, but the result also depends on a drand round that is fixed only when the entries close and published a few seconds later, by a network of independent organisations. When the last stake is accepted, that value does not exist anywhere yet.
The verifier checks that the round really was in the future at the recorded close, and that its value carries drand's signature. Because that close time comes from our server's clock, the server also checks its clock against drand's newest round, and while it finds the clock behind real time, joins and deposits stay closed.
While the beacon cannot be reached, joins and deposits pause. A game whose round is already fixed waits for that round and then settles from it, also after a restart: such a game is never voided automatically.
Only if its round still cannot be fetched after 10 minutes may an administrator refund it. That action is audited, and the game's round number stays public, so anyone can check whether drand had in fact published it. The one other refund after the close is a Jackpot round whose recorded entries no longer match the entries hash published at its close: it can never be drawn, and after the same wait an administrator may refund it, audited with the problem found.
Before the close, while a flip is open or a Jackpot round is open or counting down, an administrator may also cancel it and refund every stake, for example to stop abuse; nobody can know the result then, because the beacon round is not fixed yet.
Not at the table, and not in their hand histories. Your hole cards are sent only to you. Other players see them only when they are shown: when an all-in ends the betting with your hand still in, when you show first or win a pot at showdown, or when you choose to show them. A folded or mucked hand is never sent to anyone else.
The deal stays checkable, and that has one price. Once a table seed is revealed, no sooner than 1 hour after the last hand it dealt, anyone who has a hand's inputs (they are shown at the table and in its players' hand histories) can re-derive the whole deck, folded and mucked cards included. The delay keeps a seed's last hands from exposing the cards of players who are still at the table. The rules and the Terms say the same.
No. The verifier runs entirely in your browser using the same open code that runs on our servers. Nothing is transmitted or stored. The "Copy verification link" option simply places the values you typed into the page address so you can share or bookmark the check.
Yes. The algorithm above is fully specified and uses only standard SHA-256 and HMAC-SHA256. Any language with those primitives can reproduce a deck in a few lines. The reference vectors on this page are fixed; an independent implementation must reproduce them exactly.
If a verification ever fails and you believe the inputs are correct, email compliance@justpoker.example with the hand reference.
See your active server seed hash, set a client seed of your own, rotate to reveal past seeds and verify every hand you have played.