Welcome to the first provably fair seeding event. One of the most requested features of
bustabit has been to create a provably distribution of game crashes, to replace our provably predetermined multipliers.
The
original scheme of turning a multiplayer game in which peers do not trust each other was first proposed by Dooglus, refined by Eric and solidified into code by Steve.
The high level of the scheme is as follows:
1) We have generated a chain of 10 million sha256 hashes, starting with a server secret that has been repeatedly fed the output of sha256 back into itself 10 million times. The sha256 of the final hash in the chain is: c1cfa8e28fc38999eaa888487e443bad50a65e0b710f649affa6718cfbfada4d, by publicising it here we are preventing any ability to pick an alternate sha256 chain.
2) Bustabit will play through that chain of hashes, in reverse order, and use the hashes to determine the crash point in a probably fair manner.
3) To avoid criticism that the Bitcoin address used in step 1 was carefully chosen to generate lots of "bad" crash points, each hash in the chain will be salted with a client seed, which we have no control of. The client seed will be the block hash of a Bitcoin block that hasn't yet been mined: block 339300.
The reference code (javascript) is as follows:
The method to create the hash chain is simply sha256:
function genGameHash(serverSeed) {
return crypto.createHash('sha256').update(serverSeed).digest('hex');
}
The method to convert a game hash, mix it with the picked client seed to a money pot multiplier:
function crashPointFromHash(serverSeed, clientSeed) {
function divisible(hash, mod) {
// We will read in 4 hex at a time, but the first chunk might be a bit smaller
// So ABCDEFGHIJ should be chunked like AB CDEF GHIJ
var val = 0;
var o = hash.length % 4;
for (var i = o > 0 ? o - 4 : 0; i < hash.length; i += 4) {
val = ((val << 16) + parseInt(hash.substring(i, i+4), 16)) % mod;
}
return val === 0;
}
var hash = crypto.createHmac('sha256', serverSeed).update(clientSeed).digest('hex');
/* In 1 of 101 games the game crashes instantly. */
if (divisible(hash, 101))
return 0;
/* Use the most significant 52-bit from the hash
to calculate the crash point */
var h = parseInt(hash.slice(0,52/4),16);
var e = Math.pow(2,52);
return Math.floor((100 * e - h) / (e - h));
}
The chain could be generated with code such as:
var serverSecret = 'If you knew this, you could steal all my money';
var clientSeed = '0000examplehash';
var gamesToGenerate = 1e7;
var serverSeed = serverSecret;
for (var game = gamesToGenerate; game > 0; --game) {
serverSeed = genGameHash(serverSeed);
console.log('Game ' + game + ' has a crash point of ' + (crashPointFromHash(serverSeed, clientSeed) / 100).toFixed(2) +'x', '\t\tHash: ' + serverSeed);
}
var terminatingHash = genGameHash(serverSeed);
console.log('The terminating hash is: ', terminatingHash);
Using our chosen starting serverSeed, the hash terminating the chain is
c1cfa8e28fc38999eaa888487e443bad50a65e0b710f649affa6718cfbfada4d. That is to say, the first game's hash played under the new provably fair scheme, when hashed will be c1cfa8e28fc38999eaa888487e443bad50a65e0b710f649affa6718cfbfada4d.