Provable fairness and PoL in casinos (and not only)

Greetings readers! In this post, I will briefly talk about provable fairness in a casino, as well as Proof Of Liabilities.

About experience

Not so long ago, I began to be interested in the work of the gambling market, namely the casino. Many people have an erroneous opinion about the operation of an online casino. Many people imagine a casino as a service where people are brazenly deceived, all games are twisted and it is unrealistic to win there, but in this article I want to tell you more about the possibilities of how an ordinary player can check his bet or funds for honesty.

The casino model

All casinos have a concept – RTP (Return To Player), the percentage of the bet returned to the player over a long distance. This value usually reaches 94-99%. That is, for every dollar wagered by the player, he will receive 94-99 cents. Of course, this all happens in the long run, but in the short run, the player can be in a huge plus or vice versa in a huge minus. But there are many unscrupulous casinos that do not pay out funds or brazenly twist their games.

Proven Honesty

This concept implies that the casino cannot influence the outcome of the game in any way and until the moment the bet is made, the outcome is determined.

This diagram contains four parts:

  • server seed

  • Client Seed

  • nonce

  • Cursor

Let’s take a closer look at each part

Server Seed is a random number generated by the casino. The player sees only the hash of this number before making a bet.

Client Seed is a random number generated by the user. He can change it at any time before making a bet.

Nonce – a number that increases with each bet. When the server is reset, the seed usually becomes 0.

Cursor – the number needed if the outcome of the game requires more numbers, for example for slots. If the game requires 1 number, then we use the value 0 as the cursor, if the outcome of the game requires more than 8 numbers, then we can increase the cursor by one.

Having collected all the data we need, we can get a 256 bit number, for this we use HMAC_SHA256(server_seed + client_seed + nonce + cursor)

Having received 32 bytes, we can convert them into 8 floating point numbers.

Implementation of this algorithm:

func GenerateFloats(bytes []byte) []float64 {
	var result []float64
	for i := 0; i < len(bytes) / 4; i++ {
		var res float64
		for j := 0; j < 4; j++ {
			divider := math.Pow(256, float64(j+1))
			partialResult := float64(bytes[(i*4)+j]) / divider
			res += partialResult
		}
		result = append(result, res)
	}
	return result
}

Thus, we can further convert this into a result for some game, let’s draw a card:

// Index of 0 to 51 : ♦2 to ♣A
const CARDS = [ 
  ♦2, ♥2, ♠2, ♣2, ♦3, ♥3, ♠3, ♣3, ♦4, ♥4,  
  ♠4, ♣4, ♦5, ♥5, ♠5, ♣5, ♦6, ♥6, ♠6, ♣6, 
  ♦7, ♥7, ♠7, ♣7, ♦8, ♥8, ♠8, ♣8, ♦9, ♥9, 
  ♠9, ♣9, ♦10, ♥10, ♠10, ♣10, ♦J, ♥J, ♠J, 
  ♣J, ♦Q, ♥Q, ♠Q, ♣Q, ♦K, ♥K, ♠K, ♣K, ♦A, 
  ♥A, ♠A, ♣A 
]; 

// Game event translation
const card = CARDS[Math.floor(float * 52)];

Proof Of Liabilities

This algorithm can be used not only in gambling, but also in centralized crypto exchanges (CEX), and other services that accept deposits.

I took as an example given implementation in JS, and I will talk about it superficially.

Imagine a bitcoin casino that accepts deposits to a hot wallet, then these bitcoins go to the cold wallet of the casino. As a result, we get a wallet with a balance of 100 bitcoins, but a user who has replenished 5 bitcoins cannot be sure that his funds are stored on this cold wallet and that the casino can pay him back his 5 bitcoins at any time. What if the sum of all stored funds is less than the sum of players’ balances?

The PoL algorithm comes to our aid. This algorithm is built using the Merkle tree and a casino or exchange can regenerate this tree every 24 hours and show the root node to all users.

{"root":{"sum":"87.19198928","hash":"2f88e5473199aaacb6f2f60b8d93a11862426902aeb31c0198c8f6c4156329dd"},"currency":"BTC","timestamp":1670972401975}

About implementation

In this example, I will talk about the implementation from the repository above, but more data can be entered.

The leaves in this tree will be users, and the internal nodes will be the intermediate balance of users below.

Information about the sheet (user)

  • Name – user name, his id

  • Nonce – a random number generated by the operator, available only to the user. It is necessary that his neighbor could not find out the name.

  • Sum – user balance

  • Hash – SHA256(name + ‘|’ + sum + ‘|’ + nonce)

intermediate node

  • Sum – intermediate node balance (sum of left and right children)

  • Hash – SHA256(sum + ‘|’ + left_hash + ‘|’ + right_hash)

function NodeCombiner (left_child, right_child) {
  var n = {};
  n.sum = left_child.sum + right_child.sum;
  n.hash = sha256(string(n.sum) + '|' + left_child.hash + '|' + right_child.hash);
  return n;
}

Final node(root node)

Contains as well as internal node Sum and Hash

You can play around with this algorithm. here

The advantage of this algorithm is that you do not need the number of users multiple of 2 ^ n.

Tree visualization
Tree visualization

The user can check whether his funds are in the total mass. To do this, it is enough for him to provide his data and ask the operator for intermediate nodes of the tree.

In conclusion

I want to say that if these algorithms were popularized to the masses, then we could avoid a lot of scams from casinos and centralized exchanges (for example, the collapse of FTX).

Similar Posts

Leave a Reply