检查一局可自行验证的崩盘游戏,只要几分钟,不需要任何特别的软件,只要一个新一点的浏览器,愿意复制粘贴两串十六进制字符就行。这篇一步一步讲「服务器种子、客户端种子和 nonce」这种设计的一般做法,教你确认锁定有没有被守住。
验证一局,我需要准备什么?
三样东西:
- 一个新一点的网页浏览器:Chrome、Firefox、Edge 或 Safari。你会用到浏览器内置的开发者控制台。
- 你的可自行验证种子:服务器种子(更换之后才揭晓)、你的客户端种子,以及你想验证的那一局的 nonce。这些都可以在平台的公平性设置里找到。
- 几分钟时间,第一次的话。
不需要特别的软件,不用下载,也不用命令行工具。你需要的一切,浏览器里都有。
如果你想在开始前,先弄懂你在验证什么、为什么重要,先读《可自行验证是什么》。这篇假设你已经懂这个概念,想要的是动手做的步骤。
服务器种子、客户端种子和 nonce,在哪里找?
位置每款游戏、每个网站都不一样,所以要看游戏自己的公平性页面,或者叫可自行验证的页面。在每个玩家各自一套的设计里,你通常会找到:
- 服务器种子哈希:对现在正在用的种子的 SHA-256 锁定。
- 你的客户端种子:常常可以自己改。
- nonce:一个计数器,每下一注就加一。
- 停用种子的方法,常常叫作更换种子,它会揭晓旧的服务器种子,再开始一个新的。
建在哈希链上、大家共用局的游戏,做法不一样:开局前公布链的末端,每一局结束后再揭晓那一局的哈希。
停用种子之前:记下你现在的客户端种子,以及你想检查的那一局的 nonce。换了之后,旧的数值可能就不再显示了。
怎样算出揭晓的种子的 SHA-256?
更换之后,你会看到真正的服务器种子,一长串十六进制字符。第一步,是确认这个种子算出来的 SHA-256 哈希,和更换之前显示的哈希一样。
方法 1:浏览器控制台
打开浏览器的开发者控制台(按 F12,再点「Console」),粘贴:
async function sha256(message) {
const encoder = new TextEncoder();
const data = encoder.encode(message);
const hash = await crypto.subtle.digest('SHA-256', data);
return Array.from(new Uint8Array(hash))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
}
// 换成你真正揭晓的服务器种子
sha256('your_revealed_server_seed_here').then(console.log);
输出是一串 64 个字符的十六进制字符串。把它和更换之前显示的服务器种子哈希,一个字符一个字符地对比。
方法 2:我们的哈希检查工具
打开哈希检查工具,粘贴揭晓的服务器种子,以及更换之前显示的哈希,选 SHA-256。它用你浏览器的 Web Crypto 运行,不会传任何东西给我们。它确认的是锁定;它不会重新算出这一局。
如果对得上:平台在任何一局开始之前,就锁定了这个种子。继续下一步。
如果对不上:平台在锁定哈希之后,换了种子。这是严重的失败。把一切都记录下来,然后报告。
怎样重新算出这一局的哈希?
现在你知道服务器种子是真的。下一步,重新算出某一注背后的带密钥哈希(HMAC-SHA256)。把这段粘贴到浏览器控制台:
async function hmacSha256(key, message) {
const encoder = new TextEncoder();
const cryptoKey = await crypto.subtle.importKey(
'raw', encoder.encode(key), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']
);
const sig = await crypto.subtle.sign('HMAC', cryptoKey, encoder.encode(message));
return Array.from(new Uint8Array(sig))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
}
// 换成你真正的数值
// 信息的格式(这里是 "client:nonce")由游戏的说明决定,对比之前先确认
hmacSha256('your_revealed_server_seed', 'your_client_seed:42').then(console.log);
把哈希变成倍数。这最后一步,每款游戏都有自己公开的公式,而且公式各不相同:读哈希的哪一部分、庄家优势怎么加进去、结果怎么取整。用游戏公平性页面上的公式。我们不在这里放一条公式,因为从一款游戏抄来的公式,用在另一款游戏上会算出错的答案,看起来就像检查没通过。
重要的提醒:
- 信息的格式、公式和取整方式,全部都来自游戏的说明。
- nonce 通常数的是下注,不是局。如果你跳过了一些局,那些局你的 nonce 不会变。
- 取整可能让最后一位小数差 0.01。差 0.01 是取整造成的;像 2.47 对 3.12 这样的差距,才是对不上。
如果我的验证对不上,该怎么做?
先排除自己弄错的可能:
- 检查你的客户端种子。你用的,是你要验证的那一局当时正在用的客户端种子吗?如果你改过,就要用旧的那个。
- 检查 nonce。nonce 是按每一注算的。如果平台数 nonce 的方式和你想的不一样,对不上可能只是 nonce 差了几个。
- 检查公式。不同的游戏,用不同的计算公式。确认你用的是游戏自己说明的那一条。
- 检查服务器种子。你用的揭晓的服务器种子,是对的那一次更换的吗?如果你换过好几次,要确认这个种子,对应的是那一局当时正在用的那一次。
如果你已经排除了自己弄错的可能,验证还是对不上:
- 把一切都截图。揭晓的服务器种子、锁定的哈希、你的客户端种子、nonce、显示的爆点,以及你算出来的爆点。
- 再试几局。从同一次更换里,再验证 3 到 5 局。如果全部都对不上,问题是系统性的。如果只有一局对不上,可能是数据显示出错。
- 报告给平台。大部分平台都有处理可自行验证争议的客服渠道。
- 保留证据。在正确进行的检查里,一个有记录、可以重复的对不上,是很严重的事,而且这是任何人都能重新跑一遍的证据。
一个正确实现的系统,不应该有任何一次验证对不上。这些密码学运算是确定的:同样的输入,永远得到同样的输出。如果输出对不上,要么是输入错了(自己弄错),要么是系统没有照它说的运作(平台的问题)。
怎样一次验证很多局?
抽查的话,几局就够了。要验证很多局,就把同一个函数,套在一段 nonce 上循环,再把每个结果和游戏的历史记录对比:
async function hashesForRange(serverSeed, clientSeed, startNonce, endNonce) {
const rows = [];
for (let nonce = startNonce; nonce <= endNonce; nonce++) {
rows.push({ nonce, hash: await hmacSha256(serverSeed, clientSeed + ':' + nonce) });
}
return rows;
}
hashesForRange('your_revealed_server_seed', 'your_client_seed', 1, 100).then(console.table);
对每个哈希套用游戏公开的公式,再和那个 nonce 显示的结果对比。
检查通过了,还有什么是它说明不了的?
检查通过,证明的是这一局在下注之前就定好了,之后也没有被改过。它证明不了游戏整体的返还率,和官方公布的一样;那需要数大量的局,附上误差范围公布。一款游戏过了最低样本量,实验室就一款一款做这件事。见《返还率是什么》。
它也不能告诉你任何关于下一局的事。一个种子要等它产生的局都结束了,才会揭晓,所以验证永远是往回看的。历史记录说明的是过去的表现,它预测不了下一局。说能从哈希读出下一局结果的软件,看不到那个保密的种子;见预测软件和机器人的检查。
哪些游戏可以这样检查?
只有可自行验证的游戏,比如 Aviator、Mines 和 Stake Crash,才让你从种子重新算出一局。每款游戏用的是它自己公开的公式,而我们的工具暂时还不能重新算出 Aviator 的倍数。先公布哈希的游戏,比如 JetX,让你检查锁定,但没有公布从哈希到结果的公式。第三方认证随机的游戏,比如 Spaceman,完全没办法一局一局检查。每款游戏的页面都有一个公平性标签,写明适用哪一种。
检查的价值,不管是五局还是五十局,都一样:它把「相信平台」从一种信念,变成一个任何人都能检验的说法。
这一页对你有用吗?
匿名:不用账号,也不设 cookie。