Demo environment — sample data only. This demo resets in 26 minutes.
logo
Jogo Justo

Implementação do Jogo Justo na clou.bet

Na clou.bet, adotamos um método inovador para implementar o jogo Justo em nossa plataforma de jogos online. Compreendendo que as abordagens tradicionais podem ser complexas e potencialmente intimidadoras para novos jogadores, refinamos nosso processo para torná-lo mais acessível e transparente.

Geração Tradicional de Semente do Servidor

Normalmente, os cassinos online produzem uma semente do servidor não hashada, representada como uma string hexadecimal de 64 caracteres. Embora essa abordagem seja segura, ela resulta em uma semente que aparece como uma série complexa de caracteres, dificultando que os jogadores a decifrem e verifiquem.

Exemplo de uma Semente Tradicional do Servidor

g9IiwibWFjIjoiNDljMGEwYzgwOGM0MjYxMjUzOWQxNzE3OGFjZTI4YmE2NmVmNDkwZjg4ZjY2MDZjNDk3MDA0MDc0MmU2NjVjMSIsInRhZyI6IiJ9
                         

O método pioneiro da clou.bet para gerar sementes de servidor.

Para melhorar tanto a acessibilidade quanto a clareza, implementamos um sistema de frase mnemônica de 12 palavras para nossa semente de servidor. Esse método simplifica a aparência da semente, tornando-a mais intuitiva e familiar — especialmente para os usuários acostumados com formatos de carteira de criptomoedas.

Exemplo da Semente do Servidor da clou.bet

fringe father crew abandon lift jar blast awesome knife labor tape common 

Gerando a Frase Mnemônica de 12 Palavras

Nosso processo de geração da semente do servidor começa com a construção de uma frase mnemônica de 12 palavras. Inicialmente, codificamos a entropia em incrementos de 32 bits, e depois derivamos um checksum a partir do hash SHA256 dessa entropia. Os bits combinados de entropia e checksum são, em seguida, utilizados para formar a frase mnemônica.

Cálculo de Entropia e Checksum

CS = ENT / 32
MS = (ENT + CS) / 11

|  ENT  | CS | ENT+CS |  MS  |
+-------+----+--------+------+
|  128  |  4 |   132  |  12  |
|  160  |  5 |   165  |  15  |
|  192  |  6 |   198  |  18  |
|  224  |  7 |   231  |  21  |
|  256  |  8 |   264  |  24  |
                          

Modelo JS de Justiça para Geração de Números em Ponto Flutuante e Inteiros

const byteGenerator = async function* (

    cursor = 0,

    clientSeed: string | null = null,

    serverSeed: string | null = null,

    nonce: number | null = null

  ) {

    // Setup cursor variables

    let currentRound = Math.floor(cursor / 32);

    let currentRoundCursor = cursor;

    currentRoundCursor -= currentRound * 32;



    // Generate outputs until cursor requirement is fulfilled

    while (true) {

      // HMAC function used to output provided inputs into bytes

      const hmac = createHmac(

        'SHA-256',

        clientSeed + ':' + nonce + ':' + currentRound,

        serverSeed

      );

      const buffer = new Uint8Array(str2ab(hmac));

      // Update cursor for next iteration of loop

      while (currentRoundCursor < 32) {

        // The yield keyword is used in a Generator function, similar to JavaScript's function* syntax

        yield buffer[currentRoundCursor];

        currentRoundCursor++;

      }

      currentRoundCursor = 0;

      currentRound++;

    }

  };

  const createHmac = (algorithm: string, text: string, key: string | null) => {


    // eslint-disable-next-line new-cap

    const shaObj = new jsSHA(algorithm, 'TEXT');

    shaObj.setHMACKey(key, 'TEXT');

    shaObj.update(text);

    return shaObj.getHMAC('BYTES');

  };

const generateIntegers = async ({

    cursor = 0,

    count = 1,

    target = 100,

    clientSeed,

    serverSeed,

    nonce = 0,

    floats = [],

  }: IntegerProps) => {

    // Step 1: Generate a series of floats

    floats =

      floats.length > 0

        ? floats

        : await generateFloats({

          cursor,

          count,

          clientSeed,

          serverSeed,

          nonce,

        });

    // Step 2: Positions

    const positions = Array.from({ length: target }, (_, i) => i + 1);



    // Step 3: Get hits

    const hits = floats.map((float, index) => {

      return positions.splice(Math.floor(float * (target - index)), 1)[0];

    });

    return hits;

  };

const generateFloats = async ({

    cursor = 0,

    count = 1,

    range = [0, 1],

    clientSeed,

    serverSeed,

    nonce = 0,

    intOnly = false,

    checkScaledResult = true,

  }: Props) => {

    // Random number generator function

    const rng = byteGenerator(cursor, clientSeed, serverSeed, nonce);

    // Declare bytes as empty array

    const bytes = [];



    // Populate bytes array with sets of 4 from RNG output

    while (bytes.length < count * 4) {

      const item = await rng.next();

      bytes.push(item?.value);

    }

    // Return bytes as floats

    const floats: number[] = [];

    const byteChunks = chunkArray(bytes, 4);

    for (const bytesChunk of byteChunks) {

      let result = 0;

      for (let i = 0; i < bytesChunk.length; i++) {

        const divider = Math.pow(256, i + 1);

        const partialResult = bytesChunk[i] / divider;

        result += partialResult;

      }

      if (checkScaledResult) {

        // Scale the result to the desired range

        const scaledResult = result * (range[1] - range[0]) + range[0];

        let validResult = intOnly ? Math.floor(scaledResult) : scaledResult;

        while (floats.includes(validResult)) {

          validResult++;

          if (validResult > range[1]) {

            validResult = range[0];

          }

        }

        floats.push(validResult);

      } else {

        floats.push(result);

      }

    }



    return floats;

  };
                                

Gerar Semente Binária a partir da Função Mnemônica

Dentro do nosso sistema, convertemos tanto as sementes binárias do cliente quanto as do servidor em números de ponto flutuante. Essa operação é essencial para produzir as sementes binárias que confirmam a justiça dos nossos algoritmos. Ao garantir que a semente mnemônica seja transformada com precisão em formato binário, mantemos a integridade e a transparência de nossos processos.

Além disso, essa função nos permite verificar que a semente mnemônica divulgada está alinhada com a semente binária do servidor, demonstrando claramente que nossos sistemas e algoritmos operam de maneira justa. Gerar uma semente binária a partir da mnemônica fornece um método confiável para assegurar a integridade geral e a justiça dos nossos procedimentos.

import CryptoJS from 'crypto-js';

export const generateBinarySeed = (mnemonic: string): string => {
  const salt = 'mnemonic';
  const iterationCount = 2048;
  const derivedKeyLength = 64;

  const seed = CryptoJS.PBKDF2(mnemonic, salt, {
    iterations: iterationCount,
    keySize: derivedKeyLength / 4, // Key size is specified in words, so divide by 4
    hasher: CryptoJS.algo.SHA512,
  });

  const binarySeed = CryptoJS.enc.Hex.parse(seed.toString());
  const hexStr = binarySeed.toString(CryptoJS.enc.Hex);
  const bin2hex = (s: string) => {
    let i;
    let l;
    let o = '';
    let n;
    s += '';
    for (i = 0, l = s.length; i < l; i++) {
      n = s.charCodeAt(i).toString(16);
      o += n.length < 2 ? '0' + n : n;
    }
    return o;
  };
  const binStr = bin2hex(hexStr);
  const shortBinStr = binStr.slice(0, 64);
  return shortBinStr;
};
                                    

Convertendo a Frase Mnemônica em uma Semente Binária

Para derivar a semente binária a partir da frase mnemônica, empregamos o algoritmo PBKDF2 utilizando HMAC-SHA512. Nesse processo, a frase mnemônica atua como senha, enquanto o salt é a string literal 'mnemonic'.

Conversão Final para uma String Hexadecimal de 64 Caracteres

Em seguida, refinamos a string de 128 caracteres, convertendo-a para o formato hexadecimal convencional de 64 caracteres, tipicamente utilizado para gerar resultados.

Rotacionando Seu Par de Sementes

Sempre que um jogador atualiza sua semente do cliente, nosso sistema rotaciona simultaneamente a semente do servidor. Essa rotação do par de sementes garante que ambas permaneçam sincronizadas e sejam renovadas a cada jogo, reforçando a integridade do nosso processo de geração de números aleatórios.

Nonce

O nonce, que aumenta a cada aposta, opera em conjunto com as sementes do cliente e do servidor para produzir um resultado único para cada jogo. Esse processo garante tanto a justiça quanto a imprevisibilidade de cada aposta.

Conclusão

Esse método inovador para gerar sementes de servidor não só simplifica o processo de verificação dos resultados, mas também o torna mais acessível para os usuários. Ao preservar alta entropia e uma robusta segurança criptográfica — semelhante às técnicas utilizadas em carteiras de criptomoedas —, ele garante a integridade dos nossos jogos e reforça a confiança dos jogadores na justiça e transparência de nossa plataforma de jogos.