Introduction
Provable fairness in single-player games relies on combining a Player Seed with a pre-committed Toshi Bet Seed. Thanks to our Cryptographic Commitment, players can independently verify that game outcomes are fair and have not been tampered with by the casino.
Generating Hash Buffer
For each single-player Round, subsequent hashes used for extracting random numbers are generated with the following formula:
where Hash Index is incremented for as many extractions as the Round requires (see: General Concepts / Hash Buffer).
Server seed
The server seed is a generated 64-character hexadecimal string created by our system. Before placing any bets, players are provided with an encrypted hash of this server seed. This ensures the server seed cannot be altered by the us, and that players cannot predict the results in advance.
To reveal the server seed from its hashed version, players must rotate the seed, prompting the system to generate a new one. At this point, you can verify that the hashed server seed matches the un-hashed version. This verification can be done by hashing the seed as a value ( HASH_SHA256($SERVER_SEED) ).
Client seed
The client seed is a string with up to 64 characters controlled by the player, ensures that players have an influence on the randomness of the outcomes. Without it, the server seed would solely determine the outcome of each bet. We encourage players to regularly change their client seed to create a new sequence of random outcomes. This process gives players control over the result generation, similar to cutting the deck in a brick-and-mortar casino.
During the first authentication, a client seed is automatically created to provide a seamless initial experience. While this randomly generated client seed is adequate, we strongly recommend choosing your own to incorporate your influence into the randomness.
Nonce
The nonce is a number that increments with each new round. Because of the nature of the SHA256 cryptographic function, this ensures a completely new result is generated every time, without the need to create new client and server seeds. The use of a nonce allows us to remain committed to your existing client and server seed pair while still generating unique results for each round.
Implementation
Single-player Random (Node.js)
Single-player Random (Browser)
Multiplayer
Provable fairness in multiplayer games relies on combining a players' Seed with a Hash from a pre-generated casino Hash Chain. This Hash Chain is created before the game room is instantiated.
To ensure transparency we commit to the Hash Chain by revealing its Last Hash to the community of players. Once the Last Hash is shared, players' Seed is set for the players, ensuring that the Hash Chain could not have been manipulated in a way that benefits us.
Generating hash buffer
Given the multiplayer draw's Hash and Seed, the Hash Buffer is generated with the following formula:
where Hash Index is incremented for as many extractions as the Draw requires (see: General Concepts / Hash Buffer).
Hash
NOTE: it can be confusing that term Hash has a different meaning in context of Hash Chain and Hash Buffer. Hashes from the Chain are used to create Hmac generating the Hash Buffer for the given draw.
We pre-generate a long sequence (usually 1-10 million long) of SHA256 hashes. Starting from random 32-bytes hex string and then using the formula:
Last hash from this Hash Chain is not used for random numbers generation (it's intended for publishing to the players), but then each multiplayer Draw will consume the next Hash in a backwards fashion. I.e. the first Draw of the multiplayer Room will use the Hash that was used to produce the very Last Hash, the second draw will use the one before and so on.
Due to the nature of hashing algorithms (SHA256 in this case) - even if the current hash is revealed to the players, noone is able to decode which one was used to generate it and predict the next round RNG output.
On the other hand, once the Hash is revealed after the Draw is finished, everyone is able to apply SHA256 calculus and verify that this Hash was indeed the one to produce the one used for previous Draw, thus ensuring Hash Chain consistency and our initial Hash Chain commitment.
Seed
The players' Seed is a string with up to 64 characters that can be set in the Back-Office for a given multiplayer Room. It can only be set once the Hash Chain is generated.
Implementation
Multiplayer Random (Node.js)
Multiplayer Random (Browser)
General concepts
Algorithms described in this section apply to both single-player and multiplayer random numbers generation.
Hash Buffer
Both Single-player Round and Multiplayer Draw can require multiple random numbers to generate the gameplay. To make this possible while providing ways to prove fairness, each Round and Draw is provided a Hash Buffer (which is theoretically infinite). Both these game modes use different techniques for generating Hash Buffer, but the technique of consuming numbers from this buffer is common.
Integers extraction
Games use 4 bytes from the Hash Buffer to generate each requested random number. Since SHA256 provides 32 bytes, we can return 8 32-bit unsigned integers from each hash. Bytes are interpreted as unsigned integers in a Big Endian order.
Cursor and hash index
The cursor is incremented every time new random number is requested, as well as when the random number requires re-rolling (see: Generating number under a limit). When the game requests more than 8 numbers in a single round/draw (32 bytes / 4 bytes) we will increment hashIndex and generate new hash.
Generating number under a limit
It is quite common that a game needs to get a random number under a specified limit (e.g. under 100 so [0-100) ). Multiplying integer by a float can generate a random number within a range, but it may introduce bias when converting the floating-point result to an integer.
The unbiasedRandomInteger function ensures a truly uniform distribution by carefully managing the range and using the modulo operation.