How the deal is proved fair
The claim is narrow and it is checkable: every deal is decided before the round starts, and neither the game nor the app can change it afterwards.
Card and dice games have a credibility problem, and it is earned. Read the reviews of any popular one and you will find the same sentence in a hundred variations: the computer gets the good hands. Most of the time it is not true. There is no way for the player to find out, which is exactly why the suspicion never goes away.
This game answers it with a method borrowed from online gambling regulation, where the same problem had to be solved for money. It is called commit-reveal.
The three steps
1. Before the game: the commitment
The app generates a random server seed and immediately shows you
SHA-256(server seed) — a fingerprint of it. The seed itself stays
hidden. A fingerprint cannot be reversed, so it tells you nothing about the deal; but
it is fixed, so the app cannot change the seed later without the fingerprint changing.
2. During the game: your own seed
You may supply a client seed of your own — any text. It is mixed into every draw. Because you chose it after the commitment, the app could not have tailored the seed to it. If you leave it alone a default is used, and the guarantee is weaker but the method is the same.
3. After the game: the reveal
The app shows the server seed. You check that its fingerprint matches the one you were given at the start, and you recompute every card from it. If they match, the game could not have chosen them as it went along.
How a card is derived
The stream is HMAC-SHA256(server seed, "client seed:n"), with n
counting up. Bytes are taken from that stream and turned into numbers by
rejection sampling: a value that falls outside the usable range is thrown
away rather than folded back with a remainder. Folding it back with % would
make the low numbers very slightly more likely — a bias too small to notice and too real to
leave in a game whose whole claim is that it is not biased.
The position in the stream is stored as a byte offset, not a counter of draws. That means a game closed halfway through resumes on exactly the same card, and it means anyone checking the result does not need to know how many bytes each draw happened to consume.
What this does and does not prove
| It proves | It does not prove |
|---|---|
| The deal was fixed before play started | That the game is fun, or that the opponent is strong |
| Nothing was changed once play began | That the random source is unpredictable to someone who has the seed |
| The opponent had no advance knowledge | Anything about a game you did not check |
The point is that you do not have to take our word for it. The check is arithmetic anyone can repeat, and the app shows you every number it used.
The rule behind it
There is one rule this whole project is built on: a harder opponent plays better, it never gets better cards. The levels differ in how far ahead they look and nothing else. That is not a promise in a marketing page — the test suite refuses to build if any part of the opponent can see the random source, and it checks over tens of thousands of games that the levels get the same distribution.