Limbo에서 입증된 공정성이 작동하는 방식

Cloudbet에서 Limbo를 플레이하는 방법과, 모든 배수가 입증된 공정성을 갖추고 있는지 확인하는 방법을 알아보세요.

Limbo 플레이 방법

Limbo는 빠르고 간단한 배수 게임입니다. 매 라운드가 시작되기 전에 목표 배수를 설정합니다. 이는 노리는 당첨 규모를 의미합니다. 베팅을 하면 결과 배수가 생성됩니다. 결과가 목표값과 같거나 그 이상이면 베팅 금액에 목표 배수를 곱한 만큼 당첨됩니다. 목표값보다 낮으면 해당 라운드에서 패배합니다.

목표 배수를 높게 설정할수록 잠재적인 당첨금은 커지지만, 결과가 그 값에 도달할 확률은 낮아집니다. 매 베팅 전에 목표값을 원하는 대로 낮거나 높게 설정할 수 있습니다.

Cloudbet Originals Limbo

Cloudbet 자체 제작 Originals Limbo는 99%의 RTP, 최대 x1,000,000 배수를 제공하며, $0.01~$20,000 사이의 베팅을 받습니다.

Limbo의 무작위 숫자는 다른 모든 Cloudbet Originals와 동일한 검증 가능한 방식으로 생성됩니다. 서버 시드, 클라이언트 시드, 논스가 결합되어 라운드 서명(Round Signature)이 되고, 이것이 SHAKE256을 통해 무작위 숫자 스트림으로 변환되는 과정은 Cloudbet의 입증된 공정성 시스템을 참고하세요. 이 페이지에서는 Limbo에 특화된 부분, 즉 그 무작위 숫자가 어떻게 경쟁 대상이 되는 배수로 바뀌는지를 다룹니다.

배수 계산 방식

Limbo는 SHAKE256으로 생성된 무작위 32비트 숫자에서 시작합니다. 이 숫자는 균등하게 분포되어 있어, 0에서 2³²-1 사이의 모든 값이 나올 확률이 동일합니다.

하지만 이는 우리가 필요로 하는 형태가 아닙니다. 배수는 큰 값보다 작은 값에 훨씬 더 자주 도달해야 합니다. 1.01배가 나올 확률은 100,000배가 나올 확률보다 훨씬 높아야 합니다. 그래서 이 무작위 숫자는 다음과 같은 단계를 거쳐 해당 분포로 재구성됩니다.

  1. 거부 샘플링(rejection sampling)이 사용되지만, 가볍게만 적용됩니다. 이는 곧 1이 더해질 예정인 가장 큰 값 하나만 추출되지 않도록 방지하기 위함입니다.
  2. 숫자에 1을 더합니다(4단계의 나눗셈을 위해 절대 0이 되지 않도록 하기 위함입니다).
  3. 최댓값으로 나누어 0에서 1 사이의 소수로 축소합니다.
  4. 0.99(Limbo의 RTP)를 이 소수로 나눕니다. 이 단계가 균등한 분포를 작은 배수가 큰 배수보다 기하급수적으로 더 흔하게 나타나는 분포로 바꿔주는 핵심 단계입니다.
  5. 결과를 소수점 둘째 자리로 내림합니다.
  6. 마지막으로 Limbo의 유효 범위에 맞게 "고정"됩니다. 1 미만인 값은 모두 1이 되고(최소 베팅 배수가 1.01이므로 1 미만 결과는 모두 패배로 처리됩니다), 1,000,000을 초과하는 값은 모두 1,000,000이 됩니다(Limbo의 최대 배당).

Cloudbet의 증명 가능하게 공정한 Limbo 시스템이 32비트 난수를 단계별로 변환해 해당 라운드의 최종 배율로 만드는 과정을 보여주는 흐름도.

배수가 생성되고 나면 고정되어 숨겨지며, 베팅이 이루어진 이후에는 변경할 수 없습니다. 배수에 도달하기 전에 캐시아웃할지 여부가 라운드의 결과를 결정합니다.

직접 Limbo 게임 검증하기

아래 코드는 Cloudbet의 Limbo 구현과 정확히 일치합니다. 서버 시드, 클라이언트 시드, 논스를 입력해 자신의 결과를 재현해 보세요. 참고: 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           = 0;                  // ✍️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) {
  let randomInt32 = rng.next().value;               // 'randomInt32' ranges from 0 and 4294967295
  while (randomInt32 == 0xFFFFFFFF) { randomInt32 = rng.next().value; } // This can basically be ignored

  const fraction = (randomInt32 + 1) / 0xFFFFFFFF;  // 'fraction' ranges from 0 to 1
  const inverse = 0.99 / fraction;                  // 'inverse' ranges from 0 to (basically) infinity
  let crashPoint = Math.floor(inverse * 100) / 100; // Cut off everything past the second decimal place
  // We force the crashpoint to range from 1 to 1,000,000
  if (crashPoint < 1.0) {
    crashPoint = 1.0;
  }
  if (crashPoint > 1000000) {
    crashPoint = 1000000;
  }

  return crashPoint;
}

// 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, but there is an improbable case we'll need two
  const rng = createRandomNumberSequence(numbersToGenerate, roundSignature);

  const value = 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('⛓️‍💥 Break Point:', value);
})();

더 많은 입증된 공정성 게임 설명:

  1. 입증된 공정성 - Mines
  2. 입증된 공정성 - Pump
  3. 입증된 공정성 - Plinko
  4. 입증된 공정성 - Dice
  5. 입증된 공정성 - Dice: Golden Ticket
  6. 입증된 공정성 - Roulette
  7. 입증된 공정성 - Keno