Famebet

What Is Provably Fair?

Provably fair means that the outcome of each game is generated by a random value that players can independently verify. This guarantees transparency and fairness, ensuring that neither the player nor the casino can manipulate the result.

How Does It Work?

VRF (Verifiable Random Function) VRF (Verifiable Random Function) To generate a truly random value, we use a VRF. This function takes several inputs, including the user ID, game name, game nonce, and the casino's secret key. It performs cryptographic computations and outputs both a random value and a proof. This proof allows anyone to verify that the value was generated fairly and has not been tampered with. We follow the RFC6979 VRF implementation using the SECP256K1_SHA256_TAI cipher suite for secure and verifiable randomness.

Verifying Fairness

Players can independently verify the random value using the following code:

const { verify } = require('@roamin/ecvrf')
const toHex = require('string-hex')

const publicKey = '03c41192ba26b7efafa9c69c941f759690d4fd46761c8424edbad1d5fc2c5c0947'
const request = 'e1bc2c47-9b42-4409-8a21-d4c4f46455be|rollbit:mines|25|1234costam'
const random = 'e2983665217b5aaebf11c886ef31e001c9615362b0aa6c3e49de9057f8979e1d'
const proof = '03008cd333b153dddcffc64abf357222d31cd6e6f85ddbbe9227a60d2d0edcf9e6ab0f088c1f4402e6b4fa0ef430612d3ca86a686fc857ff412a8fe1553c821f47fcc21f4b2ca1d4c3b09b59a7e4fe1b8a'

try {
  const result = verify(publicKey, proof, toHex(request))
  console.log(result === random ? 'Is Verified' : 'Not Verified')
} catch (error) {
  console.log(error)
}

Calculating Game Outcome

Once the random value is verified, it is converted to a number:

import * as crypto from 'crypto';
function bytesToUniformFloat(xs) {
    const hash = crypto.createHash('blake2b512').update(xs).digest();
    const value = hash.readBigUInt64LE(0);
    return Number(value) / Number(BigInt(2 ** 64 - 1));
  }

This converted number is then used to generate the final game outcome based on game-specific logic.

function calcMinesIxs({ size, mines, randomValue }) {
    const remainingIxs = Array.from({ length: size }, (_, i) => i);
    const mineIxs = [];
    for (let i = 0; i < mines; i++) {
      const seedI = Buffer.from(randomValue+'-'+i, 'ascii');
      const ixI = Math.floor(bytesToUniformFloat(seedI) * remainingIxs.length);
      mineIxs.push(remainingIxs[ixI]);
      remainingIxs.splice(ixI, 1);
    }
    return mineIxs;
  }
  
function calcMinesWin({
    size,
    mines,
    reveals,
    bet
  } ) {
    let mult = 1.0;
    for (let i = 0; i < reveals; i++) {
      const lossProbability = mines / (size - i);
      mult *= 1.0 / (1.0 - lossProbability);
    }
    return Math.floor(100.0 * bet * mult * 0.98) / 100.0;
  }

function generateBoard({ size, mines, randomValue }) {
    const mineIxs = calcMinesIxs({ size, mines, randomValue });
    const sizeSqrt = Math.sqrt(size);
    const board = Array.from({ length: sizeSqrt }).map(() => Array(sizeSqrt).fill(0));
    for (const index of mineIxs) {
      const row = Math.floor(index / sizeSqrt);
      const col = index % sizeSqrt;
      if (row < sizeSqrt && col < sizeSqrt) {
        board[row][col] = -1;
      }
    }
    console.log("Board: 
", board, "
");
    return board;
  }

generateBoard({size: 25, mines: 2, randomValue:  "be87e890f696aad0aad28bef78a3f2322c7687a76ff6f86b6dadb4f2aa00eeb9"})
console.log("Multipliers:")
for(let i =1; i<24; i++){
  console.log(i, ": ", calcMinesWin({size: 25, mines: 2, reveals: i, bet: 1}))
}


Board: 
 [
  [ -1, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, -1 ],
  [ 0, 0, 0, 0, 0 ]
] 
Multipliers:
1 :  1.06
2 :  1.16
3 :  1.27
4 :  1.4
5 :  1.54
6 :  1.71
7 :  1.92
8 :  2.16
9 :  2.44
10 :  2.79
11 :  3.23
12 :  3.76
13 :  4.45
14 :  5.34
15 :  6.53
16 :  8.16
17 :  10.49
18 :  13.99
19 :  19.59
20 :  29.39
21 :  48.99
22 :  97.99
23 :  293.99