Mazal uses a commit/reveal system built on HMAC-SHA256. The server commits to a hidden seed before the bet, then reveals it after settlement so the draw can be matched back to the original hash.
Every random draw is generated from a committed server seed, client seed, nonce, and round index.
A house that wanted to cheat would have to look at your bet and then change the outcome. The commit/reveal construction makes that impossible:
server_seed is fixed before your bet — its SHA-256 hash is published in advance and can't be edited after the fact.client_seed is yours. The house can't choose it, so it can't steer the result.Every draw comes from these three lines. The inputs are the committed server seed, your client seed, the bet's nonce, and the round index — nothing else feeds the roll.
message = `${clientSeed}:${nonce}:${roundIndex}`
digest = HMAC_SHA256(serverSeed, message)
roll = first_8_bytes_as_uint64(digest) / 2^64Reference implementation — byte-for-byte what the server runs:
// HMAC-SHA256(server_seed) of "client_seed:nonce:round_index"
// First 8 bytes -> uint64 -> divide by 2^64 -> uniform in [0, 1)
function rollFloat(serverSeed, clientSeed, nonce, roundIndex = 0) {
const mac = createHmac('sha256', serverSeed)
.update(`${clientSeed}:${nonce}:${roundIndex}`)
.digest();
let n = 0n;
for (let i = 0; i < 8; i++) n = (n << 8n) | BigInt(mac[i]);
return Number(n) / Number(1n << 64n);
}Every settled draw is recomputed from its committed hash and revealed seed. The terminal below shows the verification format in motion — each entry pairs a published hash with the draw it produced and confirms they match.
The algorithm above is the entire specification. If it ever changes — even a single character — the version bumps and the reference-implementation hash changes with it. There is no other code path and no hidden randomness. Bookmark this URL; it is the authoritative document.