您鏈接到的頁面描述了這個過程,但是我會嘗試去詳細介紹並提供一個C#示例。
首先會發生兩個散列。一個通用的散列函數可以證明服務器在您賭博時不會更改服務器密鑰,但這個散列函數並不是祕密的,並且在開始玩遊戲時會發給玩家。還有一個鍵控散列(稱爲HMAC),用於實際生成骰子滾動並使用服務器密鑰,用戶提供的數據和計數的數字的組合。
這裏是發生這種情況的過程:
- 服務器生成播放會話密鑰,並設置一個計數器爲0
- SHA256上使用的密鑰來生成一個散列,該散列給予玩家。這個散列不用於任何數學運算來生成骰子擲骰,它僅用於玩家的驗證。
- 玩家請求骰子擲骰並提供一個用於生成號碼的短語。
- 服務器使用SHA512-HMAC使用密鑰作爲密鑰,然後使用用戶提供的字符串加上「 - 」加上在步驟1中設置的計數器的編號以生成哈希。
- 服務器將計數器加1,這是因爲每次都使用相同的服務器密鑰,並且如果使用了相同的用戶字符串,它只會一遍又一遍地生成相同的數字。
- 服務器將生成的哈希的前21位轉換爲
int
,然後檢查int
是否大於999999,如果它不斷重複直到找到不超過999999的數字。
- 它從步驟6中獲得一個浮點數,並對其執行
number%(10000)/100.0
。
- 該浮點數返回給用戶。
- 重複從第3步開始重新開始或繼續執行第10步。
- 播放器發出播放會話結束信號。服務器將密鑰返回給用戶,並在步驟1重新啓動。
用戶一旦從第10步獲得祕密密鑰,就可以使用SHA256對其進行哈希處理,並檢查他是否獲得與在播放會話開始時被告知的相同哈希值。然後,他可以重新執行服務器執行的所有步驟,現在他擁有密鑰並驗證服務器沒有僞造任何骰子。
如何做到這一點的代碼:它
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace SandboxConsole
{
public class Result
{
public Result(string hmacMessage, float roll)
{
HmacMessage = hmacMessage;
Roll = roll;
}
public string HmacMessage { get; }
public float Roll { get; }
}
class FairDiceRollServer
{
private byte[] _serverKey;
private ulong _nonce;
public byte[] StartSession()
{
if (_serverKey != null)
throw new InvalidOperationException("You must call EndSession before starting a new session");
//Generate a new server key.
using (var rng = RandomNumberGenerator.Create())
{
_serverKey = new byte[128];
rng.GetBytes(_serverKey);
}
_nonce = 0;
//Hash the server key and return it to the player.
using (var sha = SHA256.Create())
{
return sha.ComputeHash(_serverKey);
}
}
public Result RollDice(string userKey)
{
if(_serverKey == null)
throw new InvalidOperationException("You must call StartSession first");
if(_nonce == ulong.MaxValue)
throw new InvalidOperationException("Ran out of Nonce values, you must start a new session.");
using (var hmac = new HMACSHA256(_serverKey))
{
float? roll = null;
string message = null;
while (roll == null)
{
message = userKey + "-" + _nonce;
_nonce++;
var data = Encoding.UTF8.GetBytes(message);
var hash = hmac.ComputeHash(data);
roll = GetNumberFromByteArray(hash);
}
return new Result(message, roll.Value);
}
}
private float? GetNumberFromByteArray(byte[] hash)
{
var hashString = string.Join("", hash.Select(x => x.ToString("X2")));
const int chars = 5;
for (int i = 0; i <= hashString.Length - chars; i += chars)
{
var substring = hashString.Substring(i, chars);
var number = int.Parse(substring, System.Globalization.NumberStyles.HexNumber);
if(number > 999999)
continue;
return (number % 10000)/100.0f;
}
return null;
}
public byte[] EndSession()
{
var key = _serverKey;
_serverKey = null;
return key;
}
}
}
例中使用
using System;
using System.Linq;
namespace SandboxConsole
{
class Program
{
private int _test;
static void Main(string[] args)
{
var server = new FairDiceRollServer();
var hash = server.StartSession();
Console.WriteLine(string.Join("", hash.Select(x => x.ToString("X2"))));
for (int i = 0; i < 10; i++)
{
var roll = server.RollDice("My Key");
Console.WriteLine("Message: {0} Result: {1}", roll.HmacMessage, roll.Roll);
}
var key= server.EndSession();
Console.WriteLine(string.Join("", key.Select(x => x.ToString("X2"))));
Console.ReadLine();
}
}
}
使用有關algorthom使用,並給予公開信息,通過RollDice
返回的信息的關鍵用戶從EndSession
返回,用戶可以重新創建所有骰子卷,並證明服務器確實做了一個隨機生成(感謝用戶提供的數據,服務器不允許選擇),而不是一些僞造的預選k這是保證造成損失。
請問每個問題* 1 *問題,而不是4。請參閱[Meta](https://meta.stackexchange.com/questions/39223/one-post-with-multiple-questions-or-multiple-posts)瞭解更多信息。 – Amy
對不起,我只是假設我可以分組多個相關的問題,所有這些問題都導致產生一個可證明公平的擲骰子的相同的最終黃金。 –