Overnight.Bet · provably fair demo
How this demo's provably-fair dice works
A code-level explanation for developers who want to verify the scheme rather than take it on faith: a real round played over curl, and an independent recomputation. Play-money, 18+.
Play-money only 18+ No account needed
This is play money. Overnight.Bet is a free, play-money product. There are no deposits, no payouts and no real-money wagering. Nothing on this page is a purchase, a stake or a prize, no balance is created and nothing is credited to anyone. The numbers below are an illustration of a single round.
18+. This demonstration of a gambling mechanic is intended for adults only. If play stops being entertainment, see responsible play.
No account, nothing stored. This page needs no registration and no login. It writes nothing: no account row, no bet row and no counter. It sets no cookie, and the process serving it never receives your IP address. The ordinary web-server and reverse-proxy logging described in the privacy notice applies here as on every page.
The commit: a hash published before you choose anything
Every round starts at the demo page, which mints a round id and derives a server seed from a per-process key held only in memory — not a stored value. Quoted verbatim from Product/demo/server.mjs:
const MASTER = crypto.randomBytes(32);
const serverSeedFor = (roundId) =>
crypto.createHmac('sha256', MASTER).update(`ob-demo-round:${roundId}`).digest('hex');
The page shows sha256(server_seed) — the commitment — and withholds the seed until you play. By the time you choose a client seed, the server has already locked in its secret, and you hold a receipt to check it against later.
The formula, as implemented
This is not a description of the scheme — Product/demo/fair.js and Product/demo/games/dice.js are byte-identical to the casino's own server/fair.js and server/games/dice.js, verified against the hashes of the files running inside the live casino container. SHA-256 of the two files this page runs: fair.js = b9b00806427eeee4058f552a35bcb32649ea0f67336b2b015a30caa65c46410d, games/dice.js = a8f5fa330f478629eda01bb6c23887e320099a52585011145be2e2080bb9a906.
export function* byteStream(serverSeed, clientSeed, nonce) {
let round = 0;
while (true) {
const buf = crypto
.createHmac('sha256', serverSeed)
.update(`${clientSeed}:${nonce}:${round}`)
.digest();
for (const b of buf) yield b;
round++;
}
}
export function floats(serverSeed, clientSeed, nonce, count) {
const stream = byteStream(serverSeed, clientSeed, nonce);
const out = [];
for (let i = 0; i < count; i++) {
let v = 0;
for (let j = 0; j < 4; j++) v = v * 256 + stream.next().value;
out.push(v / 2 ** 32);
}
return out;
}
export function roll(serverSeed, clientSeed, nonce) {
const [f] = floats(serverSeed, clientSeed, nonce, 1);
return Math.floor(f * 10001) / 100; // 0.00 – 100.00
}
Concretely: take HMAC_SHA256(key = server_seed, message = "<clientSeed>:<nonce>:0"), read its first four bytes as a big-endian uint32, divide by 2**32, multiply by 10001, floor it, divide by 100. The house edge lives in one constant: the payout multiplier is 99 / chance, not 100 / chance.
A worked example, played live over curl
No account, no cookie, no browser — one real round played against this demo:
$ curl -s "https://overnight.bet/demo/provably-fair?format=json"
{ "round": "0ca73e9fe9c1d9f59aab6c70f74bb91c",
"serverSeedHash": "02b3e9764434b106becb9930103a3e13964e2ec83f64ee55307d3ce43285e332", ... }
$ curl -s "https://overnight.bet/demo/provably-fair/play?round=0ca73e9fe9c1d9f59aab6c70f74bb91c\
&clientSeed=ArticleOB17verify&nonce=3&mode=under&target=25.75&format=json"
{ "serverSeed": "86cfc8d66e9793750bf62e5d5d53fd8173434b7ed9af2b32163f81ae85b49b6e",
"serverSeedHash": "02b3e9764434b106becb9930103a3e13964e2ec83f64ee55307d3ce43285e332",
"hmacMessage": "ArticleOB17verify:3:0", "roll": 8.08, "chance": 25.75, "multiplier": 3.8446, "win": true }
Neither request set or received a cookie. The commitment was published before the client seed existed anywhere, and the revealed seed hashes to exactly that commitment.
Independent verification, standard library only
A from-scratch reimplementation, not the demo's own code, run locally against the round above:
import hashlib, hmac
server_seed = "86cfc8d66e9793750bf62e5d5d53fd8173434b7ed9af2b32163f81ae85b49b6e"
client_seed = "ArticleOB17verify"
nonce = 3
commitment = "02b3e9764434b106becb9930103a3e13964e2ec83f64ee55307d3ce43285e332"
assert hashlib.sha256(server_seed.encode()).hexdigest() == commitment
digest = hmac.new(server_seed.encode(),
f"{client_seed}:{nonce}:0".encode(),
hashlib.sha256).digest()
roll = int(int.from_bytes(digest[:4], "big") / 2**32 * 10001) / 100
assert roll == 8.08
print("commitment OK, roll OK:", roll) # -> commitment OK, roll OK: 8.08
Or skip trusting either implementation and ask the live casino's own public verifier, a different process on a different host running the real game's code:
$ curl -s "https://overnight.bet/api/fair/verify?game=dice\
&serverSeed=86cfc8d66e9793750bf62e5d5d53fd8173434b7ed9af2b32163f81ae85b49b6e\
&clientSeed=ArticleOB17verify&nonce=3"
{"serverSeedHash":"02b3e9764434b106becb9930103a3e13964e2ec83f64ee55307d3ce43285e332","roll":8.08}
What this proves, and what it does not
| Proves | The server fixed its secret before your input existed and cannot change it afterward without the reveal failing the hash check. The roll is a deterministic function of seed, client seed and nonce that anyone can recompute. |
|---|---|
| Does not prove | That the server seed was drawn fairly in the first place — the scheme checks the seed was not changed after commitment, not how it was generated. |
| Does not prove | That the odds are fair in some absolute sense — the house edge (the constant 99, not 100) is a documented, deliberate design choice the hash scheme does not check or hide. |
| Is not | Real money, a licensed product, or account behavior. This is a play-money, no-account demo that reveals its seed immediately because nothing is at stake; an account round instead reveals on rotation, so a whole range of nonces can be checked at once. |
Play a round yourself
Head back to the guest demo and play your own round — no account, no cookie. Add ?format=json to either route to drive it from a script instead of a browser.