Skip to main content

How Fairness Works in Poker

The hardest problem in on-chain poker is dealing cards fairly. If the deck is on-chain, anyone can read it. If it's off-chain, you have to trust the dealer. FALKEN solves this with a commit-reveal entropy system combined with delayed salt revelation — nobody can see or manipulate the cards during play, and anyone can verify fairness after the fact.


The Problem

In physical poker, a dealer shuffles a deck and you trust they're not cheating. On a blockchain, there's no trusted dealer — smart contract storage is public, and any on-chain randomness can be predicted or front-run.

The naive approach (put the deck on-chain) fails immediately: anyone can call a view function, compute the deck, and see all hands before betting.


FALKEN's Solution: Dual-Entropy Commit-Reveal

Both players contribute randomness. Neither can control the outcome alone. Here's the full flow:

Step 1: Entropy Commit

Each player generates a random 32-byte salt and submits its hash on-chain:

commitHash = keccak256("FALKEN_POKER_V5_ENTROPY", matchId, round, playerAddress, salt)

The contract stores the hash but not the salt. At this point:

  • Each player knows their own salt
  • Nobody knows the other player's salt
  • Nobody can compute the deck

Step 2: Private Salt Submission

Players send their actual salts to the referee (off-chain, not on-chain). The referee verifies each salt matches its committed hash, then calls submitPrivateEntropy() on the contract.

This is the critical security property: salts are NOT written to public contract storage during the game. The contract stores them in a way that they're only readable at showdown. During betting, no one — not even someone reading raw contract storage — can derive the deck.

Step 3: Deterministic Deck Generation

The referee combines both salts to compute a seed:

seed = keccak256("FALKEN_POKER_V5", contractAddress, matchId, round, sortedSalts)

This seed is run through a Fisher-Yates shuffle to produce a deterministic 52-card deck. The same inputs always produce the same deck — this is what makes post-game verification possible.

Step 4: Dealing

The referee uses the FISE JavaScript's dealCards() method to allocate cards from the shuffled deck based on the variant:

VariantCards Per PlayerCommunity Cards
5-Card Draw50
Texas Hold'em25 (flop/turn/river)
Omaha45
7-Card Stud3 down + 4 up0

The referee publishes a hand receipt on-chain — a commitment to what was dealt, without revealing the actual cards.

Step 5: Play

Betting rounds proceed normally. During play:

  • Each player only knows their own cards (sent privately by the referee)
  • The referee knows all cards (same as a physical dealer)
  • No on-chain observer can derive the deck (salts aren't in public storage)

Step 6: Showdown

At showdown, salts are revealed on-chain. Now anyone can:

  1. Take both salts
  2. Compute the seed
  3. Shuffle the deck
  4. Verify every card dealt matches what the referee claimed

If the referee lied about any card, the fraud is provable and the evidence is permanent on-chain.


What Can't Go Wrong

AttackWhy It Fails
Player predicts the deckThey'd need the opponent's salt before it's revealed. The commit phase prevents this — changing your salt after seeing the opponent's would break the hash.
Player front-runs with a chosen saltSalts are committed (hashed) before either is revealed. You can't adapt your salt to manipulate the deck after seeing the opponent's commitment.
Referee manipulates the deckThe deck derivation is deterministic from the salts. Post-showdown, anyone can re-derive the deck and prove the referee dealt correctly or didn't.
On-chain observer reads the deckSalts are not stored in public contract storage until showdown. There's nothing to read during the game.
Referee colludes with a playerThe referee can see all cards (like a physical dealer), but cannot change them. Hand receipts are committed on-chain before betting starts. Any discrepancy is provable.

The Trust Model

The referee is a trusted dealer, not a trusted arbiter. Here's the distinction:

  • Trusted dealer — sees the cards, but can't change them (hand receipts lock the deal)
  • Trusted arbiter — decides the outcome with no verification (this is NOT what FALKEN does)

The referee's power is limited to:

  1. Seeing cards during the game (necessary to deal)
  2. Submitting settlement results

It cannot:

  • Change the deck (deterministic from salts)
  • Change the salts (locked by commit hashes)
  • Withhold settlement indefinitely (timeouts exist)

Any misbehavior is detectable post-match by replaying the salts through the shuffle algorithm. The path to removing even this minimal trust is decentralized referees — a network where multiple nodes verify each other.


Verification

After a match, anyone can verify the deal was fair:

  1. Read both revealed salts from the contract
  2. Compute seed = keccak256("FALKEN_POKER_V5", contract, matchId, round, sortedSalts)
  3. Run Fisher-Yates shuffle with the seed
  4. Check that dealt cards match the shuffled deck positions

This requires zero trust and zero special tools — just the public contract data and the open-source shuffle algorithm.