Cómo funciona provably fair en Dice
Así se juega a Dice en Cloudbet, y así puedes comprobar que cada tirada es provably fair.
Cómo jugar a Dice
Dice es un juego rápido en el que apuestas a si un número generado aleatoriamente quedará por encima o por debajo de un objetivo que tú eliges. Elige un número objetivo y decide si apuestas a que el resultado será Roll Over (por encima) o Roll Under (por debajo). Cuanto más cerca esté tu objetivo del extremo del rango, menos probable es que ganes, pero mayor será tu premio si aciertas. En cuanto realizas tu apuesta, el resultado se revela al instante.
Dice de Cloudbet Originals
El Dice propio de Cloudbet Originals usa un rango objetivo de 0,00 a 100,00, un RTP del 99 %, un multiplicador máximo de x9800 y acepta apuestas de 0,01 $ a 10 000 $. Auto Bet está disponible para automatizar una serie de rondas.
Esta página explica cómo Dice convierte un número aleatorio verificado en tu tirada. Para saber cómo se genera y protege esa aleatoriedad subyacente —semilla del servidor, semilla del cliente, nonce, hashing—, consulta nuestra página de provably fair. ¿Juegas a Dice: Golden Ticket? Ese juego toma el valor del dado de la misma forma descrita aquí, y después añade un valor de Golden Ticket y un multiplicador extra.
Convertir números aleatorios en un resultado de Dice
El resultado de Dice tiene que estar ligado de forma comprobable a la misma aleatoriedad verificable que el resto de los Cloudbet Originals. Una vez generada la secuencia de números aleatorios de una ronda (mediante SHAKE256; consulta el proceso de imparcialidad comprobable), Dice la utiliza así:
Se toma un número entero entre 0 y 10 000 (ambos incluidos) de la secuencia y se divide entre 100, lo que da un valor entre 0 y 100 con dos decimales. Ese es tu resultado de Dice.
Cómo funciona el muestreo
Dice tiene 10 001 resultados posibles (de 0,00 a 100,00 en pasos de 0,01), así que para este juego P = 10 001.
Para elegir de forma justa entre esos 10 001 resultados, Dice utiliza el mismo método de muestreo por rechazo descrito en nuestra guía de provably fair: se genera un número aleatorio de 32 bits, y se rechaza y vuelve a muestrear si sesgaría el resultado, hasta encontrar uno justo. Ese número pasa después por una operación de módulo con 10 001 para obtener un valor entre 0 y 10 000, que se divide entre 100 para el resultado final.

Jugabilidad
El resultado se genera y se fija en el servidor antes de que hagas tu apuesta; no se puede cambiar ni alterar sin ser detectado una vez que comienza la ronda. Después de apostar, tu umbral elegido se compara con este número pregenerado para determinar si acertaste.
Código para verificación independiente de la imparcialidad comprobable de Dice
Este programa es fiel a la implementación de Dice de Cloudbet. Introduce tu Semilla del servidor, Semilla del cliente y Nonce para verificar tus propios resultados. Nota: para revelar la Semilla del servidor de una partida en Cloudbet, primero debes rotar a una nueva Semilla del servidor.
Dependencias:
npm install js-sha3
El código:
// 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);
})();


