Cách provably fair hoạt động trong Dice
Đây là cách chơi Dice trên Cloudbet, và cách kiểm tra xem mỗi lượt tung có phải là provably fair hay không.
Cách chơi Dice
Dice là một trò chơi nhịp độ nhanh, nơi bạn đặt cược xem một số được tạo ngẫu nhiên sẽ nằm trên hay dưới một mục tiêu do bạn chọn. Chọn một số mục tiêu và quyết định xem bạn cược kết quả sẽ Roll Over (cao hơn) hay Roll Under (thấp hơn) mục tiêu đó. Mục tiêu của bạn càng gần rìa của phạm vi, khả năng thắng càng thấp — nhưng phần thưởng càng lớn nếu bạn thắng. Sau khi đặt cược, kết quả được công bố ngay lập tức.
Cloudbet Originals Dice
Dice Originals của Cloudbet sử dụng phạm vi mục tiêu từ 0,00 đến 100,00, tỷ lệ RTP 99%, hệ số nhân tối đa x9.800, và chấp nhận cược từ 0,01 $ đến 10.000 $. Auto Bet cho phép tự động hóa một số lượng vòng chơi nhất định.
Trang này trình bày cách Dice biến một số ngẫu nhiên đã được xác minh thành lượt tung của bạn. Để biết cách tính ngẫu nhiên nền tảng được tạo ra và bảo mật như thế nào — server seed, client seed, nonce, hashing — xem trang provably fair của chúng tôi. Đang chơi Dice: Golden Ticket? Trò chơi này lấy mẫu giá trị xúc xắc theo cùng cách được mô tả ở đây, sau đó cộng thêm một giá trị và hệ số nhân Golden Ticket.
Biến số ngẫu nhiên thành kết quả Dice
Kết quả của Dice phải được liên kết một cách có thể kiểm chứng với cùng tính ngẫu nhiên có thể xác minh như mọi Original khác của Cloudbet. Sau khi chuỗi số ngẫu nhiên của một vòng được tạo ra (qua SHAKE256 — xem quy trình provably fair để biết quy trình này), Dice sử dụng nó như sau:
Một số nguyên từ 0 đến 10.000 (bao gồm cả hai đầu) được lấy mẫu từ chuỗi số, sau đó chia cho 100 — cho ra một giá trị từ 0 đến 100 với hai chữ số thập phân. Đó là kết quả Dice của bạn.
Cách thức lấy mẫu hoạt động
Dice có 10.001 kết quả khả dĩ (từ 0,00 đến 100,00 theo bước 0,01), nên với trò chơi này, P = 10.001.
Để chọn công bằng trong số 10.001 kết quả đó, Dice sử dụng cùng phương pháp rejection sampling được mô tả trong hướng dẫn provably fair của chúng tôi — một số ngẫu nhiên 32 bit được tạo ra, sau đó bị loại bỏ và lấy mẫu lại nếu nó làm sai lệch kết quả, cho đến khi tìm được một số công bằng. Số đó sau đó được tính modulo với 10.001 để có được một giá trị từ 0 đến 10.000, sau đó chia cho 100 để có kết quả cuối cùng.

Cách chơi
Kết quả được tạo ra và khóa lại trên máy chủ trước khi bạn đặt cược — nó không thể bị thay đổi hay can thiệp mà không bị phát hiện sau khi vòng chơi bắt đầu. Sau khi bạn đặt cược, ngưỡng bạn đã chọn được đối chiếu với số đã được tạo sẵn này để xác định xem dự đoán của bạn có đúng hay không.
Mã nguồn để kiểm chứng độc lập tính provably fair của Dice
Chương trình này chính xác với cách triển khai Dice của Cloudbet. Nhập Server Seed, Client Seed và Nonce của bạn để tự kiểm chứng kết quả. Lưu ý: để công bố Server Seed của một ván trên Cloudbet, trước tiên bạn cần làm mới sang một Server Seed mới.
Các thư viện cần cài đặt:
npm install js-sha3
Mã nguồn:
// 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);
})();


