Comment le provably fair fonctionne dans Dice
Voici comment jouer à Dice sur Cloudbet, et comment vérifier que chaque lancer est provably fair.
Comment jouer à Dice
Dice est un jeu rythmé où vous pariez sur le fait qu'un nombre généré aléatoirement se retrouvera au-dessus ou en dessous d'une cible que vous choisissez. Choisissez un nombre cible et déterminez si vous pariez que le résultat sera Roll Over (au-dessus) ou Roll Under (en dessous). Plus votre cible est proche du bord de la plage, moins vous avez de chances de gagner — mais plus votre gain sera important si c'est le cas. Une fois votre pari placé, le résultat est révélé instantanément.
Cloudbet Originals Dice
Le Dice de Cloudbet Originals utilise une plage cible de 0,00 à 100,00, un RTP de 99 %, un multiplicateur maximal de x9 800, et accepte des mises de 0,01 $ à 10 000 $. Le mode Auto Bet permet d'automatiser un certain nombre de manches.
Cette page explique comment Dice transforme un nombre aléatoire vérifié en votre résultat. Pour savoir comment le hasard sous-jacent est lui-même généré et sécurisé — source du serveur, source du client, nonce, hachage — consultez notre page provably fair. Vous jouez à Dice: Golden Ticket ? Il échantillonne la valeur du dé de la même façon que décrit ici, puis ajoute une valeur et un multiplicateur de Golden Ticket.
Transformer des nombres aléatoires en résultat de Dice
Le résultat de Dice doit être lié de façon vérifiable au même hasard démontrable que chaque autre Cloudbet Original. Une fois la séquence de nombres aléatoires d'une manche générée (via SHAKE256 — voir le processus provably fair pour ce processus), Dice l'utilise ainsi :
Un nombre entier entre 0 et 10 000 (inclus) est échantillonné à partir de la séquence, puis divisé par 100 — ce qui donne une valeur entre 0 et 100 avec deux décimales. C'est votre résultat de Dice.
Comment fonctionne l'échantillonnage
Dice a 10 001 résultats possibles (de 0,00 à 100,00 par pas de 0,01), donc pour ce jeu, P = 10 001.
Pour choisir équitablement parmi ces 10 001 résultats, Dice utilise la même méthode d'échantillonnage par rejet décrite sur notre guide provably fair — un nombre aléatoire de 32 bits est généré, puis rejeté et rééchantillonné s'il biaisait le résultat, jusqu'à en trouver un équitable. Ce nombre passe ensuite par une opération modulo sur 10 001 pour obtenir une valeur entre 0 et 10 000, qui est divisée par 100 pour le résultat final.

Déroulement de la partie
Le résultat est généré et verrouillé sur le serveur avant que vous ne placiez votre pari — il ne peut pas être changé ou altéré sans que cela soit détecté une fois la manche commencée. Après votre pari, le seuil que vous avez choisi est comparé à ce nombre prégénéré pour déterminer si votre prédiction était correcte.
Code pour une vérification indépendante de l'équité provably fair de Dice
Ce programme correspond exactement à l'implémentation de Dice chez Cloudbet. Entrez votre Source du serveur, votre Source du client et votre Nonce pour vérifier vos propres résultats. Remarque : pour révéler la Source du serveur d'une partie sur Cloudbet, vous devez d'abord renouveler la Source du serveur.
Dépendances :
npm install js-sha3
Le code :
// If you are running this yourself, then you can input your own data here
// You can then compare:
// 1) Cloudbet's provided Commitment to the Commitment outputted here. This proves that the Server Seed was not altered during gameplay.
// 2) Cloudbet's provided game outcome to the game outcome outputted here. This proves that your game's outcome was determined solely by the pre-game seeds and was not altered afterwards.
let myServerSeed = 'your_server_seed'; // ✍️YOUR_INPUT✍️: Enter your (unhashed) Server Seed here
let myClientSeed = 'your_client_seed'; // ✍️YOUR_INPUT✍️: Enter your Client Seed here
let myNonce = 1; // ✍️YOUR_INPUT✍️: Enter your Nonce here
const usingCustomData = false; // Change this to true if you are using your own data
// Load libraries
const crypto = require('crypto');
const { sha3_256, shake256 } = require('js-sha3');
// Step 1: Generate a Server Seed and Commitment
// And generate a Client Seed - either by player input or by the player's browser
function generateServerSeed() {
let seed = crypto.randomBytes(32).toString('hex');
if (usingCustomData) { seed = myServerSeed; }
const commitment = sha3_256(seed);
return { 'serverSeed': seed, 'commitment': commitment };
}
function getClientSeed() {
let seed = crypto.randomBytes(32).toString('hex');
if (usingCustomData) { seed = myClientSeed; }
return seed;
}
// Step 2: Create a Round Signature with SHA3 using a Server Seed, Client Seed and Nonce
function createRoundSignature(serverSeed, clientSeed, nonce) {
return sha3_256(`${serverSeed}:${clientSeed}:${nonce}`);
}
// Step 3: Create a SHAKE256 stream generator from a Round Signature.
// To simplify this example program, this function doesn't create a stream, but instead a sequence of custom length.
function* createRandomNumberSequence(numbersToGenerate, roundSignature) {
const numOfBytes = 4 * numbersToGenerate; // 4 bytes (32 bits) per random number we generate
const byteStream = shake256.create(8 * numOfBytes); // shake takes bits as input
byteStream.update(roundSignature); // Use the Round Signature to seed the generator
const buf = Buffer.from(byteStream.digest()); // The Buffer class lets us package every 4 bytes into one 32-bit integer
for (let i = 0; i < numbersToGenerate; i++) {
yield buf.readUInt32BE(i * 4); // Read buf in 4-byte steps
}
throw new Error("No more numbers in the random number sequence! Fix: make 'numbersToGenerate' larger.");
}
// Step 4: Draw from the random number sequence to calculate the game result
function getDiceResult(rng) {
const diceMinValue = 0;
const diceMaxValue = 10000;
let number = sampleFromRange(diceMinValue, diceMaxValue, rng);
number = number / 100; // So that the dice's value ranges from 0 to 100
return number;
}
// Sample a number between 'min' to 'max' (inclusive) using Rejection Sampling
function sampleFromRange(min, max, rng) {
const P = max - min + 1
const maxAcceptable = Math.floor(0x100000000 / P) * P;
// Rejection sampling
let rand;
do {
rand = rng.next().value;
} while (rand >= maxAcceptable);
// Modulo operation
const sampled_number = rand % P;
return sampled_number + min;
}
// Example usage
(function main() {
let nonce = 1;
if (usingCustomData) { nonce = myNonce; }
const { serverSeed, commitment } = generateServerSeed();
const clientSeed = getClientSeed();
const roundSignature = createRoundSignature(serverSeed, clientSeed, nonce);
const numbersToGenerate = 1 * 2; // We need 1 random number, however due to rejection sampling we may need more
const rng = createRandomNumberSequence(numbersToGenerate, roundSignature);
const diceValue = getDiceResult(rng);
console.log('📝 Commitment (shown before the game):', commitment);
console.log('🔒 Server Seed (revealed after the game):', serverSeed);
console.log('🎲 Client Seed:', clientSeed);
console.log('🔢 Nonce:', nonce);
console.log('🔁 Round Signature (can be verified after the game):', roundSignature);
console.log('🎯 Dice landed on:', diceValue);
})();


