Provably Fair Gaming

Bitino offers Provably Fair Gaming. This means anyone can immediately and independently verify we have no control over the ordering of the cards and the game cannot be tampered with.

To achieve Provably Fair Gaming we utiilise powerful cryptographic algorithms. These ensure neither you nor us can possibly know the shuffle of a deck until the moment a game begins and any retroactive manipulation would be impossible to hide.

Technical Implementation

Our random numbers are generated using Python's implementation of the Mersenne Twister / Fisher Yates Shuffle

  1. We generate a list of initial numbers
  2. We create a server 'seed' and call random.seed
  3. The initial numbers are shuffled into their starting order using random.shuffle
  4. The initial numbers and their order is made public as an encrypted hash using SHA256(server_seed+json_string(initial_numbers))
  5. When you start a game, we use javascript in your browser to create a client 'seed' to shuffle the deck, calling random.seed once more
  6. The initial order is then shuffled again to create the final order used in your game

When the game has finished, you can verify the order of the cards was unique and not altered:

  1. Regenerate the initial hash from the initial numbers and our server seed, ensuring it matches the one we gave you when you started playing
  2. Shuffle the 'validated' list of initial numbers using your client seed to create a final list of numbers
  3. Compare the final list of numbers to the numbers that appeared in your game
Shuffling the cards using the client seed which we don't know before hashing the original numbers means the server nor the client could possibly know the final shuffle outcome before you start playing.

Working Python validation example

import hashlib
import random
import json

def gen_sha256_hex_digest(s):
    m = hashlib.sha256()
    m.update(s)
    return m.hexdigest()

def validate_initial_hash(server_seed, initial_numbers, initial_hash):
    return initial_hash == gen_sha256_hex_digest(server_seed + initial_numbers)

def validate_final_numbers(client_seed, initial_numbers, final_numbers):
    numbers = json.loads(initial_numbers)
    random.seed(client_seed)
    random.shuffle(numbers)
    return json.loads(final_numbers) == numbers

server_seed = 'cc8032f3d89a2df1fbba4aeb6d1ee42a1901be2ec661d6cd'
initial_numbers = '[9,13,1,12,9,9,9,4,3,13,11,12,8,1,1,4,10,3,7,1,1,2,4,2,3,7,10,7,11,8,11,4,13,2,3,11,12,7,13,2,2,8,13,4,8,6,4,7,4,3]'
initial_hash = 'd6bfa8a8b43f766bb4b6da63ee1add4ca4e313b59477b78c54eb170c851ac8b5'
client_seed = '06a1e68c3beea0e870e8c1cc7ea11b200aeec65b395e60f858d347352bef9f8f'
final_numbers = '[2,13,9,11,12,6,7,1,3,1,4,8,1,13,9,8,13,4,13,8,3,7,8,2,9,4,13,3,7,3,9,2,11,11,10,12,10,7,4,7,1,4,3,12,4,11,1,2,2,4]'

print "Initial Hash Valid? %s" % bool(validate_initial_hash(server_seed, initial_numbers, initial_hash))
print "Final Numbers Valid? %s" % bool(validate_final_numbers(client_seed, initial_numbers, final_numbers))

Game History

Game IDHashing