O truque, em um parágrafo
Um hash criptográfico transforma qualquer entrada em uma impressão digital de tamanho fixo com duas propriedades importantes aqui: você não pode voltar da impressão digital para a entrada, e não pode encontrar duas entradas com a mesma impressão digital. Então, se alguém te mostra a impressão digital de um segredo hoje e o segredo amanhã, você pode gerar o hash do segredo e conferir se ele bate. Se bater, o segredo que te mostraram é o mesmo que tinham ontem. Não poderiam tê-lo trocado no meio do caminho, porque um segredo diferente teria uma impressão digital diferente, e não poderiam ter escolhido o segredo para se encaixar na impressão digital, porque isso significaria reverter o hash.
Isso é um esquema de compromisso (commitment scheme), e é todo o conteúdo criptográfico do “provably fair”. A casa gera uma server seed, publica seu hash SHA-256, joga as rodadas derivadas dessa seed e revela a seed quando o par é aposentado. Todo o resto é encanamento.
VERIFICADO PELO MOTOR_shared/seedApi.ts: getRandomKey retorna {serverSeedHashed, clientSeed, nonce}; renewRandomKey retorna um novo par junto com previousServerSeed e previousServerSeedHashed, a revelação. _shared/SeedPanel.tsx rotula o campo como “server seed (compromisso sha-256)”. _shared/rng.ts: sha256Hex() calcula a impressão digital e hmacSha256Utf8() o hash por rodada, com o comentário de que o motor de demonstração “GERA resultados com as mesmas primitivas que o verificador usa para CONFERI-los — uma única implementação, para que a demo nunca possa divergir do que o verificador aceita”.
Três coisas que ele prova
| AFIRMAÇÃO | POR QUE SE SUSTENTA | A CONFERÊNCIA |
|---|---|---|
| A server seed foi fixada antes das suas apostas | Qualquer mudança na seed mudaria seu hash, e o hash foi mostrado antes da primeira rodada | Anote o compromisso no painel de seeds antes de jogar |
| A seed revelada é a seed comprometida | Uma seed diferente não pode produzir a mesma impressão digital SHA-256 | Gere o hash da seed revelada; compare com o compromisso que você anotou |
| Cada resultado decorre do par de seeds e do número da rodada | O resultado é HMAC-SHA256(server seed, “client seed-nonce-cursor”) passado pela derivação publicada do jogo | Recalcule a rodada no seu navegador a partir das quatro entradas; o painel faz isso por você |
Todas as três conferências são locais: precisam da seed revelada, da sua client seed, do nonce e do código de derivação, e nada da casa no momento da conferência.
A terceira afirmação é a que faz o trabalho pesado para o jogador, e depende de a derivação ser pública. Um hash da seed não te diz nada sobre como a seed virou uma jogada de dado ou uma carta. Aqui essa função vem embutida no cliente, o mesmo código que a demo usa para gerar resultados e que o verificador usa para conferi-los, de modo que uma rodada recalculada é uma recomputação real, e não um pedido ao servidor para que ele confirme a si mesmo.
VERIFICADO PELO ENGINE_shared/demoLocal.ts: uAt() deriva o número de cada rodada como u64(hmacSha256Utf8(serverSeed, `${clientSeed}-${nonce}-${cursor}`)), descrito como equivalente a RandomUtils.generateHash no servidor; _shared/rng.ts transforma os primeiros sete bytes do HMAC em um número uniforme em [0, 1) “equivalente ao arredondamento Long→Double do servidor, bit a bit”. O módulo de derivação de cada jogo então mapeia esse número para um resultado de dado, uma carta ou um multiplicador.
O passo a passo de verificação executa as três etapas em uma rodada real. Se você nunca fez isso, faça uma vez; o ponto do esquema não é que você verifique todas as rodadas, mas que você poderia verificar qualquer uma delas, e a casa não pode saber de antemão qual.
Três coisas que ele não pode provar
Não pode provar que a seed foi aleatória. Um comprometimento fixa uma seed; não diz nada sobre como a seed foi escolhida. Se a casa soubesse seu client seed quando gerou o server seed, ela poderia, em princípio, gerar seeds até encontrar uma cujas primeiras rodadas lhe agradassem, e se comprometer com essa. O hash bateria perfeitamente. A defesa padrão é a ordenação: o server seed é comprometido primeiro, e o client seed é definido depois, de modo que, seja qual for a seed com a qual a casa se comprometeu, ela não sabia com o que seria combinada.
Essa ordenação é onde o painel deste site tem um limite que vale a pena declarar claramente. Definir um client seed aqui não deixa o server seed atual em vigor; ele rotaciona o par, e o novo server seed é gerado pela mesma requisição que carrega seu novo client seed. Do lado do cliente, não é possível mostrar que a nova seed foi fixada antes de a requisição ser lida. Se o servidor pré-gera a próxima seed, como alguns operadores fazem publicando o próximo comprometimento com antecedência, isso não é visível na API do cliente, e não há campo de “hash da próxima server seed” para conferir. Isso já foi levantado com a equipe do jogo, e a correção é pequena: comprometer a próxima server seed antes de aceitar o client seed com o qual ela será pareada, e mostrar esse comprometimento no painel.
VERIFICADO PELO ENGINE_shared/seedApi.ts: setClientSeed(clientSeed) chama renewRandomKey com o novo client seed e retorna um novo par com nonce 0; rotate() chama o mesmo endpoint sem seed. IHouseSeed carrega serverSeedHashed, clientSeed e nonce, além do par anterior na rotação; não há comprometimento de próxima seed presente no tipo.
Até que isso mude, a versão prática da defesa é a mesma que o esquema já oferece em todos os outros aspectos: a revelação. Uma casa que ficasse testando seeds contra seu client seed ainda teria que revelar cada seed na rotação, e cada rodada sob ela pode ser recalculada. O que esse limite significa é que uma sequência suspeita nas primeiras rodadas após uma troca de seed não pode ser descartada apenas pelo hash; ela só pode ser examinada, rodada por rodada, após a revelação.
Não pode provar que o jogo é justo no outro sentido. "Provably fair" significa que a aleatoriedade foi honesta, não que as chances são equilibradas. Um jogo de dados pode ser perfeitamente verificável e ainda assim retornar 99% por design; a vantagem da casa está na tabela de pagamentos, que é um número publicado e uma promessa separada. A ética da vantagem da casa trata dessa promessa. O comprometimento é silencioso sobre isso.
Não prova nada sobre rodadas que ninguém verifica. O esquema é um dissuasor, não uma garantia. Uma rodada que você nunca recalcula é uma rodada que você aceitou por confiança, exatamente como faria em qualquer outro lugar; o que muda é que a confiança é opcional, e a casa não pode saber quando você vai exercê-la. Isso é uma grande melhoria em relação a uma máquina de embaralhar que você não pode ver por dentro, e uma melhoria menor do que a palavra "prova" sugere.
O hash é um recibo da aleatoriedade. Não é um certificado do jogo.a frase para lembrar
O que provaria mais
- Uma próxima seed pré-comprometida. Publicar o hash da próxima server seed antes que qualquer client seed possa ser pareado com ela fecha a lacuna de ordenação mencionada acima. É a única mudança que permitiria ao painel provar que a seed foi fixada antes que sua entrada fosse conhecida.
- Uma fonte pública de aleatoriedade. Misturar um beacon que ninguém controla, como a rede drand, elimina completamente a questão de quem escolheu a seed; dentro do drand descreve como isso funciona e quanto custa.
- Uma derivação publicada, mantida pública. Já é o caso aqui, e a parte mais facilmente perdida quando um cliente é reescrito. O verificador só é tão honesto quanto o código que executa.
Nada disso muda o que é um hash. Isso muda do que o hash é uma impressão digital, e quando. O esquema é simples o suficiente para que seus limites também sejam simples, e um jogador que conhece as três coisas que ele prova está em melhor posição do que alguém a quem disseram que ele prova tudo.
FAQ
O que é um comprometimento de hash em um cassino provably fair?
A impressão digital SHA-256 da server seed secreta da casa, mostrada antes do jogo e conferida com a seed quando ela é revelada. Ela prova que a seed foi fixada antes das suas apostas e que a seed revelada é a que foi comprometida.
Um hash correspondente prova que o jogo foi justo?
Ele prova que a aleatoriedade não foi alterada após o comprometimento e, com uma derivação publicada, que cada resultado decorre do par de seeds. Não prova que a seed foi escolhida aleatoriamente, e não diz nada sobre a vantagem da casa, que é um número publicado separado.
A casa pode escolher uma seed de servidor que a favoreça?
Só se ela souber a client seed com a qual a server seed será pareada no momento da escolha. A defesa é comprometer a server seed antes da client seed ser definida. Neste site, uma mudança de client seed rotaciona o par na mesma requisição, então essa ordem não pode ser confirmada a partir do cliente; o artigo descreve o limite e a correção que foi proposta.
Como eu verifico uma rodada por conta própria?
Rotacione a seed para revelar a server seed aposentada, gere o hash dela para confirmar que corresponde ao compromisso que lhe foi mostrado, depois recalcule o HMAC-SHA256 da server seed sobre sua client seed, o nonce e o cursor, e passe o resultado pela derivação publicada do jogo. O painel de seed realiza o recálculo no seu navegador.
Por que o código de derivação é importante?
Porque o hash apenas fixa a seed. Transformar a seed em um resultado de dado ou carta é uma função, e a menos que essa função seja pública, um hash correspondente não diz nada sobre se o resultado foi aquele implicado pela seed. Aqui o cliente distribui a mesma derivação que o demo usa para gerar os resultados.
Provably fair é melhor do que uma auditoria de RNG licenciada?
Elas respondem a perguntas diferentes. Uma auditoria certifica o comportamento estatístico de um gerador ao longo de muitos sorteios; um compromisso permite que você verifique uma rodada específica depois do fato. Nenhuma substitui a outra, e nenhuma muda a vantagem da casa.
FONTES E REFERÊNCIAS
- Wikipedia — Commitment scheme: ocultação e vinculação, e compromissos baseados em hash
- Wikipedia — HMAC: hashing com chave e seu uso como função pseudoaleatória
- Código-fonte do engine Betkyo: _shared/seedApi.ts (commit, reveal e rotação), _shared/rng.ts (sha256Hex, hmacSha256Utf8, o uniforme de 7 bytes), _shared/demoLocal.ts (derivação uAt), _shared/SeedPanel.tsx
OS JOGOS NESTE ARTIGODice — regras e jogo grátis →Limbo — regras e jogo grátis →