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.