Every original game at the ten crypto casinos we audit (Stake, Roobet, Shuffle, Gamdom, BetFury, Rollbit, Duel, Fairspin, Winna, Yeet) generates outcomes through one cryptographic primitive: HMAC-SHA256. This post is the byte-level technical explainer. We cover the HMAC construction, why SHA-256 specifically, how the 32-byte HMAC output is sliced into a Plinko peg decision, a Crash multiplier, or a Mines bomb layout, and what the algorithm prevents an adversarial operator from doing. The intended reader is a developer, a security researcher, or a player who already understands the three-input mechanics post and wants the algorithm pipeline at engineering depth.
If you have not read the foundational primer yet, that is the high-level explainer. The seed mechanics post covers the role of each input. This post takes those inputs as given and walks through what happens between "you press bet" and "the UI shows you a multiplier".
- Inputs: server seed (key),
client_seed:nonce:cursor(message). - Function: HMAC-SHA256 with the server seed as key. Output is 32 bytes of pseudorandom data.
- Mapping: brand-published formula consumes bytes in sequence to derive game outcomes (Plinko direction per row, Crash curve point, Mines layout, Dice float).
- Cursor: integer counter for multi-byte rounds. When the first 32 bytes run out, HMAC re-runs with cursor incremented.
- Property: deterministic, reproducible, cryptographically committed via the published SHA-256 of the server seed before the bet.
What HMAC SHA256 is, in one paragraph
HMAC (Hash-based Message Authentication Code) is a cryptographic construction that combines a secret key with a message and produces a fixed-size output. The construction has been a standard since RFC 2104 (1997) and was reaffirmed in RFC 4231 with the SHA-2 family. Where a plain hash like SHA-256 maps any input to a 256-bit digest, HMAC binds two things together: a key (kept private by one party) and a message (which can be public). The output proves that whoever produced it had access to the key, and the same key plus the same message produces the same output every time, which is the property that makes outcome verification possible.
In the casino context, the brand holds the server seed as the HMAC key. The publicly known client seed, nonce, and cursor go into the message. The HMAC-SHA256 call produces 32 bytes that the brand's mapping formula then turns into the game outcome.
Why SHA-256 specifically and not SHA-1 or MD5
The choice of SHA-256 over older hash functions is deliberate and matters for the security guarantee.
- MD5 (128-bit output). Practical collision attacks have been public for over two decades and as of 2026 they run in seconds on a laptop. Unsuitable for fairness commitments because two different server seeds can be engineered to hash to the same commitment.
- SHA-1 (160-bit output). The SHAttered collision attack was demonstrated nearly a decade ago and SHA-1 has been deprecated for cryptographic use across the industry since. Same problem as MD5, an attacker could pre-image a commitment.
- SHA-256 (256-bit output, 2001). Part of the SHA-2 family. No practical collision or pre-image attacks known after two decades of analysis. The same primitive that secures Bitcoin block hashes, certificate-authority signatures, and most modern PKI.
- SHA-3 (256-bit output, 2015). Newer construction (Keccak sponge). Not used in casino fairness pipelines because SHA-256 is already considered safe and SHA-3 has less industry tooling.
- BLAKE2 / BLAKE3. Faster alternatives, but adoption in casino fairness pipelines is near zero.
every brand in our audit set uses SHA-256. We audited the ten brands during the most recent 90-day cycle and confirmed the primitive at byte level on each one. Two of them (Fairspin, with its public-chain commitment overlay; Shuffle, inherited from the Stake-alumni team) explicitly cite the SHA-2 family in their fairness docs. The rest do not specify the family, but when we tested the HMAC output locally, the byte length matches SHA-256 (32 bytes) on every brand.
The practical implication: if a future cryptographic break weakens SHA-256, every provably fair casino would need to migrate to a new primitive. That has not happened in the lifetime of the algorithm. The mathematical assumption underneath this entire ecosystem is "SHA-256 stays secure", which is the same assumption underneath the Bitcoin protocol.
The HMAC-SHA256 construction step by step
For readers who want the internals, here is the actual construction. RFC 2104 defines HMAC as:
``
HMAC(K, m) = H((K' XOR opad) || H((K' XOR ipad) || m))
where:
H is the underlying hash function (SHA-256 in our case)
K is the key (the server seed)
K' is K padded to the block size of H (64 bytes for SHA-256), with zero padding if shorter
ipad is the byte 0x36 repeated to block size
opad is the byte 0x5C repeated to block size
m is the message (client_seed:nonce:cursor in casino context)
|| denotes concatenation
`
That construction is what hashes the key in twice (inner XOR with ipad, outer XOR with opad) to defeat length-extension attacks that pure SHA-256 would otherwise allow. The double-hash structure is what gives HMAC its security beyond a plain "hash the key and message together".
- the brand's backend takes the active server seed (the HMAC key).
- It builds the message string from the public values: client seed, nonce, and (if needed) cursor.
- It runs HMAC-SHA256 against the inputs.
- The 32-byte output is the raw pseudorandom material.
- The published mapping formula consumes those bytes in a specific order to derive the round outcome.
- the brand records the round, advances the nonce, returns the result to the UI.
You can reproduce this in any language with a crypto library. Python:
`python
import hmac
import hashlib
server_seed = "the_revealed_server_seed_here" client_seed = "your_client_seed_here" nonce = 42 cursor = 0
message = f"{client_seed}:{nonce}:{cursor}"
output = hmac.new(server_seed.encode(), message.encode(), hashlib.sha256).hexdigest()
print(output)
`
JavaScript with Node.js crypto:
`javascript
const crypto = require("crypto");
const serverSeed = "the_revealed_server_seed_here"; const clientSeed = "your_client_seed_here"; const nonce = 42; const cursor = 0;
const message = clientSeed + ":" + nonce + ":" + cursor;
const output = crypto.createHmac("sha256", serverSeed).update(message).digest("hex");
console.log(output);
`
Both produce the same 64-character hexadecimal string (32 bytes of data, two hex characters per byte). That string is the raw pseudorandom material the mapping formula consumes.
From HMAC SHA256 bytes to a game outcome: the mapping formulas
This is the part that varies per mechanic class. The HMAC output is the same shape regardless of game (32 bytes), but the brand's mapping formula reads those bytes differently for Plinko, Crash, Mines, Dice, Limbo, Towers, and HiLo.
Plinko: byte-per-row peg decisions
A Plinko drop with N rows requires N peg decisions (left or right). Stake Plinko at 16 rows requires 16 separate decisions. The mapping consumes one byte of HMAC output per row.
- Read byte 0 from HMAC output. Take the value modulo 2. Zero means left, one means right. That is the row-1 decision.
- Read byte 1. Modulo 2 again. That is the row-2 decision.
- Continue through bytes 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, one per row.
- After 16 bytes, the chip's full path is determined. The landing bucket follows from the path.
- Cursor stays at zero because 16 bytes fit within the first 32-byte HMAC output.
This is why a Plinko drop is fully deterministic from (server_seed, client_seed, nonce)`: the same three values produce the same 16-row path every time.
The published RTP at 99 percent on Stake Plinko comes from the bucket multiplier distribution, not from the HMAC pipeline. The HMAC is uniformly random over its output space; the multiplier table is what gives the game its house edge. (For brand-game level RTP data, see the per-brand audit pages.)
Crash: floating-point multiplier from a byte slice
Crash has only one outcome per round (the crash point), but it is a continuous value rather than a discrete decision. The mapping formula reads four consecutive HMAC bytes and converts them to a float in a specific way.
- Read bytes 0 through 3 from HMAC output as a big-endian 32-bit unsigned integer.
- Divide by 2^32 to produce a uniform float in see the dossier can use one reference implementation per mechanic class and apply it across all ten brands.
Frequently asked questions about the algorithm
What is HMAC and how does it differ from a plain hash?
HMAC stands for Hash-based Message Authentication Code. It combines a secret key with a message and produces an output that proves possession of the key. A plain hash like SHA-256 takes only a message; HMAC binds a key into the calculation, which is what makes it suitable for a casino's "the brand committed to this seed" use case.
Is HMAC-SHA256 safe enough for gambling fairness?
HMAC-SHA256 is safe under current cryptographic assumptions. It inherits the security of SHA-256, which has resisted collision and pre-image attacks for over two decades. The HMAC construction itself is provably secure assuming the underlying hash is collision-resistant. The same primitive secures TLS certificates and Bitcoin block hashes, if it broke, the consequences would extend far beyond casino fairness.
Could a casino fake an outcome by changing the mapping formula?
They could change a published mapping formula in a future build, which would change game economics. They could not retroactively change the outcome of a bet already placed against a committed server seed, because the HMAC output is fixed by the inputs and the published formula at the time. Mapping changes apply forward, not backward.
How does Plinko use 16 bytes for one drop while Dice uses 4 bytes?
Plinko needs 16 binary decisions (one per row of pegs), so the mapping reads one byte per row and takes the result modulo 2 for the direction. Dice only needs one continuous value, so the mapping reads 4 bytes as a 32-bit integer and converts to a float in [0, 1). Different games consume different amounts of HMAC output by design.
HMAC-SHA256 vs plain SHA-256, why does the casino use HMAC?
A plain SHA-256 of (seed + message) is vulnerable to a length-extension attack: given the hash and the message length, an attacker can compute the hash of (seed + message + suffix) without knowing the seed. HMAC's double-hash construction (inner XOR with ipad, outer XOR with opad) blocks length-extension. That is why every brand uses HMAC, not plain SHA-256.
How much computational cost does HMAC-SHA256 add per round?
Negligible. A single HMAC-SHA256 call on a modern server takes microseconds. The cost is dominated by I/O, not crypto. Even at thousands of rounds per second per game, the HMAC step is invisible in the latency budget.
Is HMAC-SHA256 vulnerable to quantum attacks?
SHA-256 against a quantum adversary has a theoretical pre-image attack of complexity 2^128 via Grover's algorithm, which is still beyond any plausible quantum machine. HMAC-SHA256 has the same property. If post-quantum cryptography becomes a practical concern, the fairness pipelines would migrate to a post-quantum hash family, but that change is not imminent.
Where to go next after the HMAC SHA256 algorithm internals
Once the HMAC SHA256 construction, the byte mapping, and the threat model are clear, the natural next steps are either to apply the algorithm hands-on or to ground it in the higher-level fairness scheme. These follow-up posts continue the same casino fairness algorithm thread.
- For the worked walkthrough that puts the HMAC SHA256 algorithm into a real Stake Plinko roll, read the seven-step verification walkthrough.
- For the high-level explainer if you came in cold, read the introductory primer.
- For the role of each input separately and the rotation flow, read the seed mechanics post.
- For how our editorial team replays HMAC during the 90-day audit cycle, see the methodology page.
Authority sources
- RFC 2104 (HMAC construction) and RFC 4231 (HMAC with SHA-2 family), the foundational specifications.
- NIST FIPS 180-4, the SHA-256 specification.
- The Bitcoin.com gambling registry, cross-operator fairness verification on the originals mechanic class.
- GamCare and BeGambleAware, independent player-protection guides referenced across the brand-game audit pages.
The editor on this post is Karssen Avelara. The cryptographic reproduction step was run locally against the brand-published mapping formulas during the most recent audit cycle. Corrections, source disputes, or implementation questions: editor@casino-originals.com.
Karssen Avelara · editor@casino-originals.com