flinch.io is an upcoming Bitcoin game that will be introduced within the next few weeks. Our provably fair system is based on the excellent work of blockage, dooglus, espringe and RHavar. It requires picking a public salt that I demonstrably cannot know yet, which I'll do in this post.
If you'd like to help me out, please quote the text after the break. Thanks!
Starting with a secret value I have generated a chain of 15,000,000 SHA256 hashes. Each element is the hash of the binary 256-bit value of the previous hash,
not of its hex-encoded string representation. The hash of the final element in the chain is
90b299d1122020f324bdfd62d680d74d2bb90c0679e1503fd97a2c1a475aae18.
Every game maps to a hash in the chain: The 15,000,000th element of the chain is the hash of game #1 and the first element in the chain is the hash of game #15,000,000. To verify that a hash belongs to a game #n, simply hash it n times and compare the result with the terminating hash.
Each game's result is determined by its hash:
// GameResult calculates the corresponding crash point for a game hash and salt.
//
// Crash points have two decimal places, so a result of 1234 is interpreted as
// 12.34x. The largest possible result is 6966505673588736.
func GameResult(seed, salt []byte) uint64 {
const nBits = 46 // number of most significant bits to use
// 1. HMAC_SHA256(key=salt, message=seed
hmacHash := hmac.New(sha256.New, salt)
hmacHash.Write(seed)
seed = hmacHash.Sum(nil)
// 2. r = 46 most significant bits
seedInt := new(big.Int).SetBytes(seed)
seedInt.Rsh(seedInt, sha256.Size*8-nBits)
r := seedInt.Uint64()
// 3. X = r / 2^46
X := float64(r) / math.Pow(2, 46) // uniformly distributed in [0; 1)
// 4. X = 99 / (1-X)
X = 99 / (1 - X)
// 5. return max(trunc(X), 100)
result := uint64(X)
if result == 99 {
return 100
}
return result
}
Since JavaScript is more widespread than Go, I've also created a
Node.js version of the reference function.
Before being used to calculate its game's result, each game hash is salted with the hash of Bitcoin block (
#450,719) in its binary form. This block has not been mined yet, which proves that I could not have deliberately picked a hash chain that is unfavorable for players.