Skip to main content

Provably Fair - Implementation

Updated today

Generating Random Numbers for Instant Games

Overview

The process for generating random numbers in instant games involves two main steps:

  1. Generate a 512-bit (64-byte) random array using:

    RandomBytes = HMACSHA512(Active_Server_Seed, Active_Client_Seed:Nonce:Cursor)
  2. Extract the needed value—either an integer or a floating point number—from the generated bytes.

📌 Note: This process differs from how random numbers are generated for scheduled games.


Generating Random Bytes

The core function is generateRandomBytes(). Here is the pseudocode:

byte[] byteGenerator(serverSeed, clientSeed, nonce, cursor) {
// 1. Create an HMAC512 hasher with server seed as the key
let hasher = HMAC512(serverSeed)

// 2. Format the message as: clientSeed:nonce:cursor
let message = clientSeed:nonce:cursor

// 3. Hash the message
let randomBytes = hasher.Hash(message)

// 4. Increment the cursor
cursor = cursor + 1

// 5. Return the random bytes
return randomBytes
}

These randomBytes are then passed into either:

  • generateDouble() → for floating point numbers

  • NextPositiveInt32() → for integers


Generating Floating Point Numbers

Floating Point Structure (IEEE 754 - 64-bit double):

  • 1 bit: Sign (positive/negative)

  • 11 bits: Exponent

  • 52 bits: Mantissa/Fraction

The mantissa controls the precision for values between 0 and 1.

Algorithm

  1. Generate 7 random bytes

  2. Combine into a 56-bit number

  3. Mask to keep the lowest 52 bits

  4. Divide by 2^52 → Gives a uniform value between 0 (inclusive) and 1 (exclusive)

Pseudocode:

double generateDouble() {
bytes = generateRandomBytes(7)

bits = 0
for each byte in bytes:
bits = (bits << 8) OR byte

masked = bits AND (2^52 - 1)
randomDouble = masked / 2^52

return randomDouble
}

✅ This ensures maximum precision and equal probability for all outcomes in the range [0, 1).


Generating Integers

Unlike some operators who derive integers from floats (which can cause bias), this method directly generates uniform integers, ensuring fairness and accuracy.

Why This Matters:

  • Mapping floats to integers (e.g., floor(float * N)) introduces rounding issues

  • This method uses rejection sampling to avoid bias

How It Works:

  1. Draw a 32-bit random unsigned integer (value)

  2. Define a rejection limit:

    limit = MAX_UINT32 - (MAX_UINT32 % maxExclusive)
  3. If value < limit, use:

    result = value % maxExclusive
  4. If not, discard and draw new bytes

🛑 Rejection Sampling ensures perfectly uniform results in [0, maxExclusive)


Pseudocode:

int NextPositiveInt32(maxExclusive) {
if maxExclusive not provided:
maxExclusive = MAX_UINT32

limit = MAX_UINT32 - (MAX_UINT32 mod maxExclusive)
byteCount = HashingBitSize / 8

loop forever:
bytes = GenerateNextBytes(byteCount)

for i from 0 to bytes.length - 4 step 4:
value = convert 4 bytes at i to unsigned int

if value < limit:
return value % maxExclusive
}


Overview

We will refer to the concept of a “Scheduled Event” to mean the lifetime of one round, i.e.:

  • the time from which the event starts and the player can place bets (this is called the preamble),

  • the time the player can cash out or play (this is called in-play),

  • and the time the event closes (i.e., bets get settled and the event is declared as closed).

The process by which random numbers are generated in scheduled games (e.g., slide, crash) is very similar to instant games, but has two key differences:

1. Client Seed Collection

The client seed is captured by choosing the bet with the highest dollarised stake value.
The highest bidding player's client seed is then used as the client seed.

We refer to this as the Active_Client_Seed.

This ensures that the player always has full influence over the seed decision, removing the risk of tampering.

2. Server Seed Generation

Every event generates a new server seed.
We refer to this as the Active_Server_Seed.

This seed is kept secret during the lifetime of the event but is made public at the time of event closure. While the server seed is only made public at the time of event closure, players are still able to verify that the server seed was not tampered with by using the server hash, which is shared at the beginning of the event.


Random Number Generation Formula

The formula used to generate the random bytes is as follows:

  1. Generate a random 512-bit (64-byte) array using the formula:

    RandomBytes = HMACSHA512(Active_Server_Seed, Active_Client_Seed)
  2. Extract the random number according to whether an integer or a float is needed.


Please note that the way floats and integers are generated is identical to the method used in Instant Games.

Did this answer your question?