Как работает provably fair в Dice
Вот как играть в Dice на Cloudbet и как проверить, что каждый бросок честен (provably fair).
Как играть в Dice
Dice — динамичная игра, в которой вы делаете ставку на то, окажется ли случайно сгенерированное число выше или ниже выбранной вами цели. Выберите целевое число и решите, ставите ли вы на Roll Over (выше) или Roll Under (ниже) этой цели. Чем ближе ваша цель к краю диапазона, тем меньше шанс выигрыша — но тем больше выплата в случае успеха. Как только вы делаете ставку, результат раскрывается мгновенно.
Cloudbet Originals Dice
Собственная игра Cloudbet Originals Dice использует целевой диапазон от 0,00 до 100,00, RTP 99%, максимальный множитель x9800 и принимает ставки от $0,01 до $10 000. Режим Auto Bet позволяет автоматизировать серию раундов.
Эта страница описывает, как Dice превращает проверенное случайное число в ваш бросок. О том, как генерируется и защищается сама случайность — сид сервера, сид клиента, nonce, хеширование — читайте на нашей странице provably fair. Играете в Dice: Golden Ticket? Там значение кубика выбирается тем же способом, что описан здесь, а сверху добавляется значение и множитель Golden Ticket.
Как случайные числа превращаются в результат Dice
Результат Dice должен быть доказуемо связан с той же проверяемой случайностью, что и в любой другой игре Cloudbet Originals. Как только сгенерирована последовательность случайных чисел раунда (с помощью SHAKE256 — см. процесс provably fair), Dice использует ее так:
Из последовательности выбирается целое число от 0 до 10 000 (включительно), которое затем делится на 100 — получается значение от 0 до 100 с двумя знаками после запятой. Это и есть ваш результат Dice.
Как работает выборка
У Dice 10 001 возможный результат (от 0,00 до 100,00 с шагом 0,01), поэтому для этой игры P = 10 001.
Чтобы честно выбрать один из этих 10 001 результатов, Dice использует тот же метод выборки с отбраковкой, что описан в нашем руководстве по provably fair — генерируется случайное 32-битное число, которое отбраковывается и генерируется заново, если оно исказило бы результат, пока не будет найдено честное число. Затем это число делится по модулю на 10 001, чтобы получить значение от 0 до 10 000, которое делится на 100 для получения итогового результата.

Игровой процесс
Результат генерируется и фиксируется на сервере до того, как вы сделаете ставку — его нельзя изменить или подделать незаметно после начала раунда. После того как вы сделали ставку, выбранный вами порог сравнивается с этим заранее сгенерированным числом, чтобы определить, верным ли был ваш прогноз.
Код для независимой проверки честности Dice
Эта программа точно соответствует реализации Dice на Cloudbet. Введите свои Сид сервера, Сид клиента и Nonce, чтобы проверить собственные результаты. Примечание: чтобы раскрыть Сид сервера игры на Cloudbet, сначала нужно перейти на новый Сид сервера.
Зависимости:
npm install js-sha3
Код:
// 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);
})();


