Så fungerar provably fair i Dice

Så här spelar du Dice på Cloudbet, och så kontrollerar du att varje kast är provably fair.

Så spelar du Dice

Dice är ett snabbt spel där du satsar på om ett slumpmässigt genererat tal hamnar över eller under ett mål du väljer. Välj ett måltal och bestäm om du satsar på att resultatet blir Roll Over eller Roll Under det. Ju närmare kanten av intervallet ditt mål ligger, desto mindre är chansen att vinna — men desto större vinst om du gör det. Så snart du placerat din insats visas resultatet direkt.

Cloudbet Originals Dice

Cloudbets egen Originals Dice använder ett målintervall från 0,00 till 100,00, en RTP på 99 %, en maxmultiplikator på x9 800, och tar emot insatser från $0,01 till $10 000. Auto Bet finns tillgängligt för att automatisera flera omgångar.

Den här sidan handlar om hur Dice omvandlar ett verifierat slumptal till ditt kast. För hur själva slumpmässigheten genereras och säkras — server seed, client seed, nonce, hashning — se vår sida om provably fair. Spelar du Dice: Golden Ticket? Det spelet hämtar sitt tärningsvärde på samma sätt som beskrivs här, och lägger sedan till ett Golden Ticket-värde och en multiplikator ovanpå.

Så blir slumptal ett Dice-resultat

Dice resultat måste vara bevisbart kopplat till samma verifierbara slumpmässighet som alla andra Cloudbet Originals. När en omgångs slumptalsföljd har genererats (via SHAKE256 — se processen för provably fair) använder Dice den så här:

Ett heltal mellan 0 och 10 000 (inklusive) hämtas från talföljden och divideras sedan med 100 — vilket ger ett värde mellan 0 och 100 med två decimaler. Det är ditt Dice-resultat.

Så fungerar urvalet

Dice har 10 001 möjliga utfall (0,00 till 100,00 i steg om 0,01), så för det här spelet är P = 10 001.

För att välja rättvist bland dessa 10 001 utfall använder Dice samma rejection sampling-metod som beskrivs i vår guide till provably fair — ett slumpmässigt 32-bitars tal genereras och förkastas och hämtas på nytt om det skulle snedvrida resultatet, tills ett rättvist tal hittas. Det talet körs sedan genom en modulo-operation mot 10 001 för att hamna på ett värde mellan 0 och 10 000, som sedan divideras med 100 för slutresultatet.

Flödesschema över Cloudbets bevisbart rättvisa Dice-beräkning: ett slumptal genomgår rejection sampling och omvandlas till det slutgiltiga tärningsresultatet.

Spelupplägg

Resultatet genereras och låses in på servern innan du placerar din insats — det kan inte ändras eller manipuleras oupptäckt när omgången väl har startat. Efter att du satsat jämförs ditt valda tröskelvärde med detta färdiggenererade tal för att avgöra om din gissning var rätt.

Kod för oberoende verifiering av Dice provably fair

Det här programmet motsvarar Cloudbets Dice-implementation exakt. Ange din Server Seed, Client Seed och Nonce för att verifiera dina egna resultat. Obs: för att avslöja ett spels Server Seed på Cloudbet måste du först rotera till en ny Server Seed.

Beroenden:

npm install js-sha3

Koden:

// 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);
})();

Fler förklaringar av provably fair per spel:

  1. Provably fair Mines
  2. Provably fair Pump
  3. Provably fair Plinko
  4. Provably fair Dice: Golden Ticket
  5. Provably fair Limbo
  6. Provably fair Roulette
  7. Provably fair Keno