Comment le provably fair fonctionne dans Dice: Golden Ticket
Voici comment jouer à Dice: Golden Ticket sur Cloudbet, et comment vérifier que chaque lancer et tirage Golden Ticket est provably fair.
Comment jouer à Dice: Golden Ticket
Dice: Golden Ticket (DGT) se joue comme le jeu Dice classique de Cloudbet, avec une couche supplémentaire : une cible bonus cachée qui peut verser un multiplicateur bonus en plus de votre gain normal.
Jeu de base : choisissez Roll Over (2,00–99,99) ou Roll Under (0,01–98,00), puis placez votre pari. Si le dé tombe de votre côté de la cible, vous gagnez selon le gain que votre cible implique (une cible plus serrée = un multiplicateur plus élevé).
Le bonus Golden Ticket : à chaque manche, une seconde valeur cachée — le Golden Ticket — est également placée sur le plateau, avec son propre multiplicateur bonus compris entre 3x et 200x. Si votre lancer de dé tombe à ±1,75 de la position du Golden Ticket, vous gagnez le paiement bonus à ce multiplicateur, instantanément et automatiquement — aucune mise supplémentaire n'est requise, et cela se cumule avec votre gain habituel.
Vous ne visez pas directement le Golden Ticket — ce n'est pas quelque chose que vous pouvez cibler ou influencer, il se trouve simplement toujours quelque part sur le plateau à chaque manche, et atterrir près de lui est un bonus en plus de votre partie habituelle.
Cloudbet Originals Dice: Golden Ticket
Le DGT de Cloudbet Originals a un RTP de 99 %, un multiplicateur de dé maximal de x6 730, et un gain maximal de 1 000 000 $.
Dice: Golden Ticket (DGT) utilise la même base provably fair que chaque Cloudbet Original — consultez Comment fonctionne le provably fair pour la mécanique générale (Source du serveur, Source du client, Nonce, SHAKE256, échantillonnage par rejet). L'échantillonnage de la valeur du dé fonctionne également de la même façon que dans Dice classique — DGT ajoute simplement la valeur et le multiplicateur du Golden Ticket en plus. Voici comment cette séquence devient spécifiquement votre résultat DGT.
Transformer des nombres aléatoires en résultat de jeu
DGT doit prouver que deux valeurs sont déterminées par un hasard vérifiable : la valeur du dé et la valeur du Golden Ticket.
Le processus est simple : d'abord, un nombre entier entre 0 et 10000 (inclus) est échantillonné pour devenir la valeur finale du dé. Ensuite, un autre nombre entier entre 175 et 9825 (inclus) est échantillonné pour devenir la valeur finale du Golden Ticket. Les deux nombres sont divisés par 100 afin d'avoir chacun deux décimales — allant de 0 à 100 (dé) et de 1,75 à 98,25 (Golden Ticket).
La plage du Golden Ticket est délibérément limitée à 1,75–98,25, et non 0–100, afin que, où qu'il atterrisse, il y ait toujours une « zone dorée » pleine de 3,5 de large autour de lui où la valeur du dé peut tomber et remporter le bonus. Si la plage allait jusqu'aux extrémités (0 ou 100), un Golden Ticket atterrissant près d'un bord aurait une zone dorée plus petite — et de moins bonnes chances — qu'un tirage au milieu.
DGT possède également une particularité : le multiplicateur du Golden Ticket est lui-même généré par un processus provably fair. En termes simples : un troisième nombre aléatoire entre 0 et 1 est tiré, puis converti en un multiplicateur compris entre 3 et 200 à l'aide d'une distribution de Pareto tronquée.

Détails techniques
Les octets aléatoires générés par SHAKE256 sont divisés en entiers non signés de 4 octets, allant de 0 à 2³²-1. Comme la valeur du dé a 10001 résultats possibles (0–10000 inclus), l'échantillonnage par rejet utilise P = 10001 ; la valeur du Golden Ticket a 9651 résultats possibles (175–9825 inclus), donc son P = 9651. (Voir la page provably fair pour comprendre l'importance de cette étape.)
Sélection des valeurs du dé et du Golden Ticket : le nombre aléatoire du dé est pris modulo 10001 pour obtenir sa valeur. La même opération est effectuée pour le nombre aléatoire du Golden Ticket avec 9651, puis le résultat est augmenté de 175 (afin qu'il aille de 175 à 9825). Les deux sont ensuite divisés par 100.
Sélection du multiplicateur du Golden Ticket (quelques notions de statistiques aident ici) : un nombre aléatoire de 32 bits est tiré et divisé par sa valeur maximale possible, produisant un nombre uniformément distribué entre 0 et 1. Cette valeur est transformée selon une distribution de Pareto tronquée (borne inférieure 3, borne supérieure 200, alpha 1,343 — choisi pour que la valeur attendue du multiplicateur soit 9, ce qui respecte l'objectif de RTP de 99 % de DGT), puis arrondie à deux décimales.
Déroulement de la partie
Les valeurs du dé et du Golden Ticket sont toutes deux générées côté serveur et cachées jusqu'à la fin de la manche — elles ne peuvent pas être modifiées sans être détectées une fois la partie commencée. Après avoir placé votre pari, le seuil que vous avez choisi est comparé à la valeur du dé, et la distance entre le Golden Ticket et la valeur du dé est vérifiée par rapport à la « zone dorée » de 1,75 pour déterminer si vous remportez le bonus.
Code pour une vérification indépendante
Correspond exactement à l'implémentation de DGT chez Cloudbet — entrez votre Source du serveur, votre Source du client et votre Nonce pour vérifier vos propres parties. (Pour révéler la Source du serveur d'une partie sur Cloudbet, vous devez déjà être passé à une nouvelle 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 getGameResult(rng) {
// Dice
// Ranges from 0 to 100, with two decimal places
const diceMinValue = 0;
const diceMaxValue = 10000;
let diceValue = sampleFromRange(diceMinValue, diceMaxValue, rng);
diceValue = diceValue / 100; // Now the value ranges from 0 to 100
// Golden Ticket
// Ranges from 1.75 to 98.25 due to fairness
// (If it landed on 99, for example, then the chance of the dice landing near
// it would be smaller than the guarantee of 3.5%)
const gtMinValue = 175;
const gtMaxValue = 9825;
let goldenTicketValue = sampleFromRange(gtMinValue, gtMaxValue, rng);
goldenTicketValue = goldenTicketValue / 100;
// Golden Ticket Multiplier
const multiplier = getRandomNumberTruncatedPareto(rng); // Complicated maths, can be ignored ;)
return { diceValue, goldenTicketValue, multiplier };
}
// Sample a number using the truncated Pareto distribution
function getRandomNumberTruncatedPareto(rng) {
// Get a uniformly distributed number between 0 and 1
let randomInt32 = rng.next().value;
const fraction = randomInt32 / 0xFFFFFFFF;
// Truncated Pareto distribution. The expected value is 9.00
const m0 = 3;
const m1 = 200;
const alpha = 1.343;
const r = Math.pow(m0 / m1, alpha);
const inner = 1 - fraction * (1 - r);
let randomNumber = m0 / Math.pow(inner, 1 / alpha);
randomNumber = Math.round(randomNumber * 100) / 100; // Round to 2 decimal places
return randomNumber;
}
// 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 = 3 * 2; // We need 3 random numbers, however due to rejection sampling we may need more
const rng = createRandomNumberSequence(numbersToGenerate, roundSignature);
const { diceValue, goldenTicketValue, multiplier } = getGameResult(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);
console.log('🎫 Golden ticket landed on:', goldenTicketValue);
console.log('⭐ Multiplier:', multiplier);
})();
