Overview

Implementation

Conversion

Game events

Сalculator

The underlying concept of provable fairness is that players have the ability to prove and verify that their results are fair and unmanipulated. This is achieved through the use of a commitment scheme, along with cryptographic hashing.

The commitment scheme is used to ensure that the player has an influence on all results generated. Cryptographic hashing is used to ensure that the casino also remains honest to this commitment scheme. Both concepts combined creates a trust-less environment when gambling online.

This is simplified in the following representation:

`fair result = operators input (hashed) + players input`

For each bet being checked, we use: client seed, server seed, nonce and cursor as input parameters for the random number generation function.
The function uses the ** HMAC_SHA256 ** cryptographic hash to generate bytes, which are then used as the basis for how we generate reliably random results on our platform.

```
// Random number generation based on following inputs: serverSeed,
// clientSeed, nonce and cursor
function byteGenerator({ serverSeed, clientSeed, nonce, cursor }) {
// Setup cursor variables
let currentRound = Math.floor(cursor / 32);
let currentRoundCursor = cursor;
currentRoundCursor -= currentRound * 32;
// Generate outputs until cursor requirement fullfilled
while (true) {
// HMAC function used to output provided inputs into bytes
const hmac = createHmac('sha256', serverSeed);
hmac.update(`${clientSeed}:${nonce}:${currentRound}`);
const buffer = hmac.digest();
// Update curser for next iteration of loop
while (currentRoundCursor < 32) {
yield Number(buffer[currentRoundCursor]);
currentRoundCursor += 1;
}
currentRoundCursor = 0;
currentRound += 1;
}
}
```

The result of the random number generator (byteGenerator) function is a hexadecimal 32-byte hash. As explained in the cursor implementation, we use 4 bytes of data to generate one game result. Each set of 4 bytes is used to generate floating point values ranging from 0 to 1 (4 bytes are used instead of one to provide a higher level of accuracy when generating floating point numbers.) It is with these generated numbers that we get the formal result of the provable honest algorithm before it is translated into game events.

```
// Convert the hash output from the rng byteGenerator to floats
function generateFloats ({ serverSeed, clientSeed, nonce, cursor, count }) {
// Random number generator function
const rng = byteGenerator({ serverSeed, clientSeed, nonce, cursor });
// Declare bytes as empty array
const bytes = [];
// Populate bytes array with sets of 4 from RNG output
while (bytes.length < count * 4) {
bytes.push(rng.next().value);
}
// Return bytes as floats using lodash reduce function
return _.chunk(bytes, 4).map(bytesChunk =>
bytesChunk.reduce((result, value, i) => {
const divider = 256 ** (i + 1);
const partialResult = value / divider;
return result + partialResult;
}, 0)
);
};
```

Since the random number generation process is universal for all our games, It is at this stage of the generation of the game result that a unique procedure is implemented, allowing you to determine the transfer from a floating point number to game events. A randomly generated result is multiplied by the possible remaining results of a particular game. For example: in a game that uses a deck of 52 cards, this can be done by simply multiplying the number by 52. The result of this equation is then converted to the corresponding game event. For games where multiple game events are required, this process continues every 4 bytes in the result chain, which was generated using the described byteGenerator function.

For games like Keno, Mines, and Video Poker, where the results cannot be duplicated, we use the random shuffling algorithm Fisher Yates .

Game events are the translation of randomly generated numbers into the corresponding game-specific result. This includes everything from the outcome of a roll of dice to the order of the cards in the deck, or even the location of each bomb in Mines. The following is a detailed explanation of how we translate numbers into events for each specific game on our platform.

There are 52 unique possible outcomes in the standard deck of cards:

```
// Index of 0 to 51 : ♦2 to ♣A
const CARDS = [
♦2, ♥2, ♠2, ♣2, ♦3, ♥3, ♠3, ♣3, ♦4, ♥4,
♠4, ♣4, ♦5, ♥5, ♠5, ♣5, ♦6, ♥6, ♠6, ♣6,
♦7, ♥7, ♠7, ♣7, ♦8, ♥8, ♠8, ♣8, ♦9, ♥9,
♠9, ♣9, ♦10, ♥10, ♠10, ♣10, ♦J, ♥J, ♠J,
♣J, ♦Q, ♥Q, ♠Q, ♣Q, ♦K, ♥K, ♠K, ♣K, ♦A,
♥A, ♠A, ♣A
];
// Game event translation
const card = CARDS[Math.floor(float * 52)];
```

When playing Diamonds, there are 7 possible outcomes in the form of diamonds. To achieve this, we multiply each floating-point number by 7, and then translate it into the corresponding diamond:

```
// Index of 0 to 6 : green to blue
const GEMS = [ green, purple, yellow, red, light_blue, pink, blue ];
// Game event translation
const gem = GEMS[Math.floor(float * 7)];
```

Then the player receives 5 diamonds.

In our version of the Dice game, we cover the possible throw spread from 00.00 to 100.00, which has a range of 10,001 possible results. Translation of game events is performed by multiplying the floating point number by the number of possible results, and then divide by 100 so that the resulting number matches the limits of our declared range of dice.

```
// Game event translation
const roll = (float * 10001) / 100;
```

When it comes to Limbo, we use a two-step process. Firstly, we take the number and multiply it by the maximum possible multiplier and by% of the casino advantage. Then, to generate a game event using the probability distribution , we divide the maximum possible factor by the result of the first step to create a game event in the form of a final coefficient.

```
// Game event translation with houseEdge of 0.99 (1%)
const floatPoint = 1e8 / (float * 1e8) * houseEdge;
// Crash point rounded down to required denominator
const crashPoint = Math.floor(floatPoint * 100) / 100;
```

For any Plinko game, the generated result is based on which cell the ball will fall into.

`const bucket = Math.floor(float * (pins + 1));`

Our roulette is taken from the European version of the game, in which the wheel consists of 37 different possible pockets in the range from 0 to 36. A game event is calculated by multiplying the number by 37, and then transferred to the appropriate pocket:

```
/ Index of 0 to 36
const POCKETS = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36 ];
// Game event translation
const pocket = POCKETS[Math.floor(float * 37)];
```

Traditional Keno games require a selection of 10 possible game events in the form of cells on the game board. To achieve this, we multiply each floating-point number by the number of unique squares possible.

```
// Index of 0 to 39 : 1 to 40
const SQUARES = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40 ];
const hit = SQUARES[Math.floor(float * 40)];
```

The implementation of a random Fisher-Yates sequence is used to prevent duplication of possible hits.

Mines consists of 24 separate game events in the form of mines on the playing field. Each number is multiplied by the number of possible unique tiles still remaining on the board. Cell locations are constructed using the grid position from left to right, from top to bottom. The implementation of a random Fisher-Yates sequence is used to prevent duplication of possible hits. Depending on the selected settings, 2 to 24 results of game events are used.

Playing Video Poker includes 52 individual game events in the form of cards in the deck. Each number is multiplied by the number of possible cards remaining in the deck.

```
// Index of 0 to 51 : ♦2 to ♣A
const CARDS = [
♦2, ♥2, ♠2, ♣2, ♦3, ♥3, ♠3, ♣3, ♦4, ♥4,
♠4, ♣4, ♦5, ♥5, ♠5, ♣5, ♦6, ♥6, ♠6, ♣6,
♦7, ♥7, ♠7, ♣7, ♦8, ♥8, ♠8, ♣8, ♦9, ♥9,
♠9, ♣9, ♦10, ♥10, ♠10, ♣10, ♦J, ♥J, ♠J,
♣J, ♦Q, ♥Q, ♠Q, ♣Q, ♦K, ♥K, ♠K, ♣K, ♦A,
♥A, ♠A, ♣A
];
// Game event translation
const card = CARDS[Math.floor(float * 52)];
```

The implementation of a random Fisher-Yates sequence is used to prevent duplication of possible hits.

FAIR

Slide

Slide

FAIR

Double

Double

FAIR

Wheel

Wheel

HOT!

FAIR

Dice

Dice

FAIR

Plinko

Plinko

FAIR

Keno

Keno

FAIR

Diamonds

Diamonds

Live

All

Lucky Winners

Type @**username** to notify user

Statistics

Wins

Losses

Wager

Profit

Help

Earn Wall

Races

Leaderboard

Home

Slide

Double

Wheel

Dice

Plinko

Keno

Diamonds

Evoplay Game

External Game

Games

Chat

Bonus

Notifications

Search Games