Provably fair. Check it yourself.
You don't have to trust us, and you don't need any math. Follow 5 steps on any phone. It takes about 2 minutes.
And after any Block Run, you can replay the entire game, move for move.
// THE WHOLE IDEA IN ONE PICTURE
// HOW THE BLOCK SETS THE GAME
The map number starts a number machine. Each time the game has to decide something, it takes the next number from the machine (always between 0 and 1) and checks it against a fixed rule. The rules are the same for everyone. The block only changes the numbers.
Rule: does a new enemy sneak in from the back? Yes if its number is below 0.35. Otherwise it comes straight at you.
Rule: what does a knocked-out enemy drop? Its number picks a row from the loot table below. The rare stuff sits at the top end.
The first wave of Block Run is 3 enemies. Here are their "sneak in from the back?" numbers on two real days:
Two of them sneak in from the back.
All three come straight at you.
Everyone who played on Oct 27 met that same first wave. Nobody could choose it, because nobody knew block 973,314's code until it was mined.
Loot uses a second machine (the dice), started from the same map number. On Oct 27 its first numbers are:
0.502 · 0.990 · 0.952 · 0.766 · …
In a real run on Oct 27, the first enemy went down at 5.8 seconds:
- XP chips0.000–0.638
- Heart0.638–0.730
- 2X XP0.730–0.813
- Magnet0.813–0.874
- Shield0.874–0.916
- Meme coin0.916–0.957
- Zest star0.957–0.988
- LUCKY BLOCK ◂ 0.9900.988–1.000
The shield and the star sometimes sit out (for example while you already have one), which shifts the rows a little. 0.990 lands on the Lucky Block either way.
Every player that day gets the same dice in the same order. What you do decides which enemy gets which number. That part is skill.
// CHECK IT YOURSELF
Find the block
Each day's map comes from one Bitcoin block: the first one mined after midnight (UTC).¹ The game shows it on the menu and on every run. Today's is:
mempool.space is a public Bitcoin website. We don't run it, and nothing there needs a wallet.
Copy its code
On mempool.space, find the block's Hash. It's 64 letters and numbers. Nobody on Earth knew it before the block was mined, us included. Here it is, cut into 8 pieces:
Same code as on mempool.space? Good. On to step 3.
Turn it into one number
Paste the code here and tap MIX IT. The box mixes the 8 pieces together (that's called XOR). Out comes one number: the map number.
Now open the game and tap ⛓ BITCOIN BLOCK · ✓ VERIFY on the menu. It shows the same map number with a ✓.
Block Run mixes in one more fixed number (0x0b10c5ed) so its map isn't the same as the everyday map. Its number today: 1,615,419,572.
Don't trust our box? Use your own calculator ▸
- Open Calculator. On Windows tap ☰ then Programmer. On a Mac pick View, then Programmer.
- Switch it to HEX (Mac: tap 16).
- Type piece 1, tap XOR, type piece 2, tap XOR, and keep going to piece 8. Tap =.
- Switch to DEC (Mac: tap 10). That's the map number.
Replay the whole game
The game saves every tap with the exact moment it happened (60 moments a second). So after a Block Run you can watch the entire game again, move for move. Tap CHECK IT, then ▶ WATCH REPLAY. Your own phone plays every tap again on the same map, and at the end it checks the score.
It works on anyone's run, not only yours. The home page plays the day's best run, or watch it here:
Watch the day's best run ▸ Play Block Run ▸See it locked on Stacks
After midnight (UTC), every run from that day is folded into one code and written once on Stacks, a network that settles on Bitcoin. Change any run later and it won't fit that code.
For now this uses Stacks testnet (test coins, no real money). The code sits in a public contract: fairplay-board on the Hiro explorer ↗
¹ On Oct 23 and Oct 27, 2026 our block reader skipped the very first block after midnight (972,675 and 973,313), because its data source leaves out Bitcoin blocks that carry no Stacks activity. Those two days used the next block instead. Nobody could pick either one. The fix starts Oct 28.
// DUELS
Block Duels
Locked to Bitcoin blocks that don't exist yet when the duel is made. Each round's dice come from its block plus a secret that was locked in (with SHA-256) before that block was mined. After the round the secret is shown, so anyone can rebuild the dice and replay it.
In the game: CHECK IT YOURSELF on any finished Block Duel, then ▶ REPLAY BOTH to replay both players' rounds on your phone.
Blind Duels
Each score is sealed (SHA-256 with a secret random salt) before the other player finishes. Nobody can change a score after seeing the other one.
In the game: 🔍 CHECK IT YOURSELF after both seals open.
// BOT CUP
Bot Cup duels start with seedHash, the SHA-256 of a secret seed. When the duel ends, you get the seed. Check its SHA-256 matches, then replay the duel with the same engine file the server runs. Training Blip's moves come only from the seed and the duel so far, never from your move.
Bot Cup check steps ▸// THE EXACT MATH (BLOCK RUN)
Each day's run uses the first Bitcoin block mined after midnight (UTC). Nobody knows that block's code (its hash) until it is mined, us included.
B = first block with time ≥ 00:00 UTC
Look any block up yourself on mempool.space. See note ¹ for Oct 23 and Oct 27.
The hash is 64 characters. Cut it into 8 pieces, mix them together with XOR, and you get one number. Block Run mixes in one fixed number more: the seed.
seed = h₁ ⊕ h₂ ⊕ … ⊕ h₈ ⊕ 0x0b10c5ed
const fpSeed = h => { let x = 0;
for (let i = 0; i < 64; i += 8) x ^= parseInt(h.slice(i, i + 8), 16);
return x >>> 0; };
const brSeed = hash => fpSeed(hash) ^ 0x0b10c5ed;
Every random thing in the run comes from two number generators, both started from that seed (mulberry32): one for the map, one for the gameplay dice. Same seed, same numbers, on every phone.
map = rng(seed) · dice = rng(seed ⊕ 0x6a3d0f21)
const rng = seed => () => { seed |= 0; seed = seed + 0x6D2B79F5 | 0;
let t = Math.imul(seed ^ seed >>> 15, 1 | seed);
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
return ((t ^ t >>> 14) >>> 0) / 4294967296; };
The game moves in fixed steps, 60 a second. Your phone saves each tap with its step number. CHECK IT plays the taps again from the same seed, on your own phone.
replay(seed, taps) = saved score, steps, ending and final state
If even one number is off, the check fails.
Each run is squeezed into one code. Change one tap and the code changes.
fp = SHA-256("blockrun/v1 | day | block | hash | path | steps | end | score | state | taps")
Anyone can fetch a run by its code and replay it.
Once a day, after midnight (UTC), every fingerprint from that day is folded into one code and written once to Stacks, in a contract anyone can read. One fee a day, not one per run.
root = SHA-256 tree(fp₁, fp₂, … fpₙ)
→ fairplay-board.get-week(day) = { root, entries, top-score, sealed-at }
After that, nobody can swap or change a run from that day, us included. Its fingerprint would not fit the code on the chain.
Stacks is a Bitcoin layer: on Stacks mainnet, blocks settle on Bitcoin. For now we use Stacks testnet (test coins only).
Next: the day's best run saved whole, every tap, so it can be replayed straight from the chain.
// WHAT IT PROVES
- Nobody picked the map. Not players, not us.
- Everyone got the same run that day.
- The score comes from the saved taps. Anyone can replay it.
- A run can't be changed later. Its fingerprint is locked into that day's code on Stacks.
// WHAT IT DOESN'T
- That a human played. A bot can play too. Contests add their own rules for that.
- That one person used one name.
- That a Bitcoin miner never threw a block away to change a map. That costs a whole block reward, far more than any game prize.
// READ THE CODE
- The seed code is open source: fairplay-kit/seed on GitHub. Free to use in your own game.
- The game runs in your browser, so its whole code is in the page at /play.