Visão geral

Resolvendo o problema de confiança com jogos de azar online

O conceito subjacente de justiça comprovável é que os jogadores têm a capacidade de provar e verificar que seus resultados são justos e não manipulados.

O esquema de compromisso é usado para garantir que o jogador tenha influência em todos os resultados gerados.

Isso é simplificado na seguinte representação:
resultado justo = entrada dos operadores (hashed) entrada dos jogadores

Implementação

Geração de número aleatório

Para cada aposta verificável, uma semente de cliente, uma semente de servidor, um nonce e um cursor são usados ​​como parâmetros de entrada para o geração de números aleatórios função. HMAC_SHA256 para gerar bytes que são então usados ​​como base para como geramos resultados aleatórios comprovadamente justos em nossa plataforma.


// Geração de números aleatórios com base nas seguintes entradas: serverSeed, clientSeed, nonce e cursor
function byteGenerator({ serverSeed, clientSeed, nonce, cursor }) {

// Configura as variáveis ​​do cursor
let currentRound = Math.floor(cursor / 32);
deixe currentRoundCursor = cursor;
currentRoundCursor -= currentRound * 32;

// Gera saídas até que o requisito do cursor seja preenchido
enquanto (verdadeiro) {

// Função HMAC usada para gerar as entradas fornecidas em bytes
const hmac = createHmac("sha256", serverSeed);
buffer const = hmac.digest();

// Atualiza o cursor para a próxima iteração do loop
while (currentRoundCursor < 32) {
rendimento Number(buffer[currentRoundCursor]);
currentRoundCursor = 1;
}

currentRoundCursor = 0;
atualRodada = 1;
}
}


Semente do servidor

A semente do servidor é gerada pelo nosso sistema como uma string hexadecimal aleatória de 64 caracteres.

Para revelar a semente do servidor de sua versão com hash, a semente deve ser rotacionada pelo jogador, o que aciona a substituição por uma recém-gerada.

A partir deste ponto, você pode verificar se a semente do servidor com hash corresponde à semente do servidor sem hash.

Semente do cliente

A semente do cliente pertence ao jogador e é usada para garantir que o jogador também tenha influência na aleatoriedade dos resultados gerados.

Todos os jogadores são livres para editar e alterar sua semente de cliente regularmente para criar uma nova cadeia de resultados aleatórios futuros.

Durante o registro, uma semente do cliente é criada para você pelo seu navegador, para garantir que sua experiência inicial com o site seja ininterrupta.

Você pode fazer isso por meio do modal de justiça.

Semente do cliente

O nonce é simplesmente um número que aumenta à medida que cada nova aposta é feita.

A implementação do nonce garante que permaneçamos comprometidos com seu par de sementes de cliente e servidor, enquanto geramos novos resultados para cada aposta feita.

Semente do cliente

Usamos 4 bytes de dados para gerar um único resultado de jogo e, como o SHA256 é limitado a 32 bytes, utilizamos essa implementação de um cursor para nos dar a capacidade de criar mais eventos de jogo sem ter que modificar nosso algoritmo justo comprovado.

O cursor só é iterado quando o jogo que está sendo jogado requer a geração de mais de 8 (32 bytes / 4 bytes) resultados possíveis.

O cursor começa como 0 e aumenta em 1 toda vez que os 32 bytes são retornados pela função HMAC_SHA256.

Jogos com mais de 1 número incremental:
  • Hilo (Ilimitado para cobrir a quantidade necessária de cartões)
  • Keno (2 incrementos para cada jogo devido a 10 resultados possíveis)
  • Minas (3 incrementos por jogo para 24 locais de bombas possíveis)
  • Plinko (2 incrementos por jogo para cobrir 16 decisões possíveis)
  • Blackjack (Ilimitado para cobrir a quantidade necessária de cartas)
  • Video Poker (7 incrementos para gerar 52 cartas possíveis em um baralho completo)
  • Diamond Poker (2 incrementos para cobrir 10 diamantes: 5 por jogador/dealer)
  • Slots (o número incremental é utilizado apenas para rodadas de bônus)
Jogos com apenas 1 número incremental (representado como valor padrão 0):
  • Dados
  • Limbo
  • Roda
  • bacará
  • Roleta
  • diamantes

Conversas

Bytes para Flutuantes
A saída da função Random Number Generator (byteGenerator) é um hash hexadecimal de 32 bytes.

// Converte a saída hash do rng byteGenerator para floats

função gerarFloats ({ serverSeed, clientSeed, nonce, cursor, count }) {

//Função geradora de números aleatórios

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

// Declara bytes como array vazio

const bytes = [];

// Preenche o array de bytes com conjuntos de 4 da saída RNG
enquanto (bytes.comprimento < count * 4) { bytes.push(rng.next().value);
}
// Retorna bytes como floats usando a função lodash reduce

retornar _.chunk(bytes, 4).map(bytesChunk =>

bytesChunk.reduce((resultado, valor, i) => {

const divisor = 256 ** (i 1);

const parcialResultado = valor / divisor;

retornar resultado parcialResultado;

}, 0)
);
};
Flutua para eventos de jogo
Onde o processo de geração de saídas aleatórias é universal para todos os nossos jogos, é neste ponto da geração do resultado do jogo que um procedimento exclusivo é implementado para determinar a tradução de floats para eventos de jogo.

O float gerado aleatoriamente é multiplicado pelos possíveis resultados restantes do jogo específico que está sendo jogado.

Embaralhamento de Eventos de Jogo
Para jogos como Keno, Mines e Video Poker, onde os resultados não podem ser duplicados, utilizamos o algoritmo de embaralhamento de Fisher-Yates.

Por exemplo, no vídeo pôquer, existem inicialmente 52 cartas disponíveis no baralho completo e, portanto, o primeiro evento do jogo é traduzido pela multiplicação do float por 52. Uma vez distribuída esta carta, restam apenas 51 cartas no

No que diz respeito a Minas e Keno, trata-se simplesmente de implementar o mesmo processo explicado no videopôquer, mas alterá-lo para peças ou locais no tabuleiro ou grade, garantindo que cada evento de jogo gerado não tenha sido feito anteriormente

Eventos do jogo
Os eventos do jogo são a tradução dos flutuadores gerados aleatoriamente em um resultado relacionável que é específico do jogo.

Abaixo está uma explicação detalhada de como traduzimos floats em eventos para cada jogo diferente em nossa plataforma.

Vinte-e-um, Hilo
Em um baralho de cartas padrão, existem 52 resultados únicos possíveis.

// Índice de 0 a 51 : ♦2 a ♣A

const CARTÕES = [

♦2, ♥2, ♠2, ♣2, ♦3, ♥3, ♠3, ♣3, ♦4, ♥4,
♠4, ♣4, ♦5, ♥5, ♠5, ♣5, ♦6, ♥6, ♠6, ♣6,
♦7, ♥7, ♠7, ♣7, ♦8, ♥8, ♠8, ♣8, ♦9, ♥9,
♠9, ♣9, ♦10, ♥10, ♠10, ♣10, ♦J, ♥J, ♠J,
♣J, ♦Q, ♥Q, ♠Q, ♣Q, ♦K, ♥K, ♠K, ♣K, ♦A,
♥A, ♠A, ♣A
];

// Tradução do evento do jogo

const cartão = CARDS[Math.floor(float * 52)];

O único fator de diferenciação envolvido com esses jogos é que com hilo e vinte-e-um existe um cursor de 13 para gerar 52 eventos de jogo possíveis para os casos em que uma grande quantidade de cartas é necessária para ser distribuída ao jogador, enquanto que quando se trata de bacará só precisamos de 6 eventos de jogo gerados para cobrir a maior quantidade possível de cartas jogáveis.

pôquer diamante
Ao jogar Diamond Poker, existem 7 resultados possíveis na forma de joias.

// Índice de 0 a 6: verde para azul

const GEMS = [verde, roxo, amarelo, vermelho, ciano, laranja, azul];

// Tradução do evento do jogo

const gem = GEMS[Math.floor(float * 7)];

Tanto o dealer quanto o jogador recebem 5 gemas cada, o que significa que um jogo completo de Diamond Poker requer a geração de 10 eventos de jogo.