LCP

Nowadays, there are numerous platforms on the internet where millions of users invest their money to win huge prize money or rewards by giving just a fraction of it. One such example is HypeDrop, where a user can open mystery boxes that may cost anywhere between $1 undefined $20k. These boxes consist of exorbitant rewards, and there might be debate about the chances of getting a fair result. This also applies to your favourite casino if it is fair enough to you or not?

Here comes in the picture Provably Fair Algorithm. Letundefineds see what is provably fair and how it is implemented on blockchain.

What is a Provably Fair Algorithm?

Provably fair is a technique that makes sure that a generated number was truly random without any manipulation done to get this number. It guarantees the user and, enables them to verify that the generated result is randomly generated and not manipulated.

This algorithm takes in the following parameters to make sure the true nature of randomness:

  1. client_seed: It is a string of n length, randomly generated at the client-side or the frontend, which can be modified.
  2. server_seed: It is also a randomly generated string on the server-side, and it is a 64-character hex string. Before you start betting, the server sends you a hashed version of the server_seed. This ensures that the outcome is pre-determined and will not change afterward.
  3. nonce: Nonce is a sequentially incrementing number that tracks the number of bets placed so far.

Role of Blockchain

We have seen that Provably Fair itself is a fair method to generate random numbers. However, to add a bit more fairness, we can implement this in Solidity and deploy it on the Ethereum network in the form of a Smart Contract.

A smart contract is a simple program stored on the blockchain and can be accessed using the contract address. Since the smart contract is stored on the blockchain, it is immutable and cannot be modified in the future. This blockchain feature makes sure that the deployed functions are not altered.

The smart contract does not generate its server_seed to minimize the gas fees. This may seem a little skeptical, however, we can add a server to compensate for it.

The first step is to generate the client_seed. We are writing the random string generation code in javascript.


 function randomString(length) {
   const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
   let random = '';
   for(let i = 0; i < length; i++) {
     random += chars[Math.floor(Math.random() * chars.length)];
   }
   return random;
 }

We can pass in a length in this function and generate a random string


randomString(30) // jd2X84dcjgUvIacaR4mVWssotfzIe3
randomString(30) // X3X6cWFGhwxAZbgZzldfHYed6ERIzw

Now we have the client_seed.

The same function can be implemented on the server-side as well to generate a random string that can be passed to the contract. Nonce will be available with the server. These parameters will then be passed to the contract.

Letundefineds have a look at the contract function that we are going to use and see how it generates a random number


function getRandomNumber(string memory client_seed,string memory server_seed, uint nonce) public pure returns(uint) {
       string memory hashed_server_seed = toHex(sha256(abi.encodePacked(server_seed)));
       string memory combination = string(abi.encodePacked( uint2str(nonce),'-',client_seed,'-',hashed_server_seed));
       bytes memory hashed_combination = bytesToSHA3_512(abi.encodePacked(stringToBytes32(combination)));
       return getResult(hashed_combination);
   }

The getRandom() function takes in the parameters; client_seed, server_seed, and nonce. It then performs the following operations:

  • Converts the server_seed into a SHA256 hex and then converts it into a string using the toHex() function
  • Using the abi.encodePacked() function, it combines the client_seed, hashed server_seed (converted into a string), and the nonce, which can be converted into a string using uint2str() function and explicitly performs string conversion
  • Then it passes the combination to the bytesToSHA3_512() function, which hashes this input and returns a SHA512 output.
  • This output is then passed to the getResult() function, which returns the random number


function getResult(bytes memory hashValue) internal pure returns (uint){
       bytes memory result = extractSig(hashValue, 0, 6);
       uint randomNumber;
       randomNumber = bytesToUint(result);
       return (randomNumber%10000)/100;
   }

We will create a contract.js file to make a connection with our contract. For achieving this, we are going to install the web3 package:

The deployment of this contract has already been done using truffle on the Ropsten network (not covered in this blog)

To install this write:

npm install undefinedsave web3

After successful installation of the package, we will import the same and create an instance of web3 by giving it an appropriate provider and creating a variable for our contract address. In our case, we are using Infura as our provider.


var Web3 = require("web3");
let web3 = new Web3(new Web3.providers.HttpProvider('https://ropsten.infura.io/v3/'));
var addr = "";

To make a connection with the contract, we will need the contract address as well as the ABI (Application Binary Interface) of the contract.

ABI is a human-readable representation of the programundefineds interface, which defines the methods used to interact with the contract.

When deployed with truffle, the contractundefineds ABI can be found within the JSON file of the contract, which can be found in the build/contracts folder of the project.

We now declare a new variable abi and pass the ABI of the contract to it.



var abi = [
 {
   inputs: [
     {
       internalType: "string",
       name: "client_seed",
       type: "string",
     },
     {
       internalType: "string",
       name: "server_seed",
       type: "string",
     },
     {
       internalType: "uint256",
       name: "nonce",
       type: "uint256",
     },
   ],
   name: "getRandomNumber",
   outputs: [
     {
       internalType: "uint256",
       name: "",
       type: "uint256",
     },
   ],
   stateMutability: "pure",
   type: "function",
   constant: true,
 },
];


Now letundefineds make a connection to the contract and call the getRandom() function to generate the random number.


var ProvablyFair = new web3.eth.Contract(abi, addr);
 
ProvablyFair.methods
 .getRandomNumber(
   "jd2X84d1jvUvIqcaRFmVWIsot2zIeH",
   "XaX6MWShOwxAZbggz4dfTYVd6EuIzw",
   1
 )
 .call()
 .then(console.log);

Then we call the contract.js using the node command and see the final output

Output:


 > node connection/contract.js           
 > 18
 

With the slightest change in the input parameters, the generated output gets changed. This is what defines the truly random nature of Provably Fair.

Conclusion

In conclusion, Provably Fair is the Golden Standard when it comes to online gambling as it is developed in a way that allows the players to verify the randomly generated number and gives the platform a level of trust as both the site manager and the players know the outcome before the game starts.

We, at Seaflux, are Blockchain enthusiasts who are helping enterprises worldwide. Have a query or want to discuss Blockchain projects? Schedule a meeting with us here, weundefinedll be happy to talk to you!

Jay Mehta - Director of Engineering
Jay Mehta

Director of Engineering