Para garantir transparência e equidade comprovável, geramos uma cadeia de 10 milhões de hashes SHA256 para cada jogo multijogador, começando com um segredo do servidor que foi alimentado repetidamente com a saída SHA256 novamente em si mesmo 10 milhões de vezes
O SHA256 do hash final para Platform é: eeb4d340bfaed702601b9a08faba2f8088c4810c3e3a883293accaf25053b883
O SHA256 do hash final para Crash é: c46f0705f6ba4df891ce44accda8f89f5a6fa8b987eb7c7b445280cf6cabfbc6
O SHA256 do hash final para Battle é: 63cb1eb64ec4eb4de02f6bad85e42365d08f37497a1b7e907bd0b9183f27e1b3
Ao publicar aqui, estamos evitando a capacidade de escolher uma cadeia SHA256 alternativa. Agora o servidor de jogo está reproduzindo esta cadeia de hashes em ordem reversa, usando esses valores para calcular os resultados do jogo de forma comprovadamente justa.
1. Hash Inicial Secreto: Cada tipo de jogo multijogador tem seu próprio hash inicial privado (conhecido apenas pelo servidor), formando a raiz de uma cadeia hash única.
2. Geração de Cadeia Hash: A partir do hash secreto inicial, geramos uma cadeia de 10.000.000 de hashes aplicando SHA256 repetidamente.
func HashSeed(seed string) string {
hash := sha256.Sum256([]byte(seed))
return hex.EncodeToString(hash[:])
}
func CalculateHashChain(firstHash string) []string {
hashes := make([]string, 10_000_000)
for i := int64(0); i <= 10_000_000; i++ {
firstHash = HashSeed(firstHash)
hashes[i] = firstHash
}
return hashes
}
3. Consumo Reverso: Revelamos o hash final na cadeia ao público. Cada rodada de jogo consome os hashes em ordem reversa: Rodada 1 usa hash[10_000_000], Rodada 2 usa hash[9_999_999], e assim por diante...
4. Este design torna impossível falsificar futuros hashes, enquanto permite que qualquer pessoa verifique todos os hashes anteriores.
Imprevisibilidade: Os resultados futuros do jogo não podem ser conhecidos ou influenciados, nem mesmo pelo servidor.
Verificabilidade: Os jogadores podem verificar a integridade de qualquer rodada anterior usando apenas o hash final revelado publicamente.
Isolamento de Jogo: Cada tipo de jogo tem sua própria cadeia, evitando manipulação entre jogos.
Para garantir equidade comprovável em jogos single-player, nossa plataforma usa um sistema baseado em três componentes principais para gerar a semente do resultado:
1. Semente do Cliente: Esta é uma semente controlada pelo usuário. É gerada automaticamente quando um usuário se registra, mas o usuário pode alterá-la a qualquer momento. Alterar a semente do cliente inicia a geração de uma nova semente de servidor.
2. Semente do Servidor: É gerada pelo servidor usando parâmetros internos que não são divulgados ao usuário. Está vinculada exclusivamente à semente do cliente atual. Para cada semente do cliente, há uma semente de servidor correspondente. Quando o usuário altera a semente do cliente, a semente de servidor anterior é revelada para fins de verificação.
3. Nonce: Um número único baseado no carimbo de tempo da aposta (em milissegundos). Garante que até mesmo as ações repetidas produzem resultados diferentes.
Esses três valores são combinados e codificados usando HMAC-SHA256 para gerar a semente de jogo final, que é então usada para determinar o resultado do jogo.
func GenerateUserGameSeed(userSeed string, userServerSeed string, nonce int64) (string, error) {
data := fmt.Sprintf("%s:%s:%d", userServerSeed, userSeed, nonce)
mac := hmac.New(sha256.New, []byte(data))
gameSeed := hex.EncodeToString(mac.Sum(nil))
return gameSeed, nil
}
O servidor fornece a versão codificada da semente de servidor atual antes de qualquer aposta ser feita.
Depois que o usuário altera sua semente de cliente, a semente de servidor usada anteriormente é revelada.
Isso permite que os usuários verifiquem que todos os resultados gerados com a semente de servidor anterior foram consistentes e justos.