Skip to main content

Algorithm reference

The shared JavaScript API turns player mnemonics or public round data into a deterministic stream of bytes and numbers. These functions are game-independent: a game decides how to interpret their output. Every stage is exported as a separate function so it can be inspected, tested, and presented independently.

import {
binarySeedFromMnemonic,
bytes,
floats,
generateMnemonic,
integers,
integersFromFloats,
roundSeeds,
uint64,
} from '@gambalabs/provably-fair'

Seed functions

generateMnemonic()

Generates a valid 12-word English BIP-39 mnemonic using 128 bits from a cryptographically secure random source.

function generateMnemonic(): string

This function has no parameters and returns a new string on every call.

const clientMnemonic = generateMnemonic()
const serverMnemonic = generateMnemonic()

binarySeedFromMnemonic()

Converts one mnemonic into the 64-character seed consumed by the random byte stream.

function binarySeedFromMnemonic(mnemonic: string): string
ParameterTypeRequiredDescription
mnemonicstringyesA non-empty mnemonic phrase.

The conversion uses PBKDF2-SHA512 with the salt mnemonic, 2,048 iterations, and a 64-byte derived key. The hexadecimal result is encoded as hexadecimal a second time and trimmed to 64 characters.

const clientSeed = binarySeedFromMnemonic(clientMnemonic)

roundSeeds()

Maps the public values of a round directly to the common seed shape. Public rounds do not generate mnemonics and do not run PBKDF2.

function roundSeeds(input: RoundSeedInput): BinarySeeds
ParameterTypeRequiredDescription
input.roundSeedstringyesPublic seed used as the HMAC key.
input.hashSeedstringyesPublic beacon value. An empty string is allowed.
input.roundIdnumberyesNon-negative integer used as the nonce.
const seeds = roundSeeds({ roundSeed, hashSeed, roundId })

The returned mapping is direct: roundSeed → serverSeed, hashSeed → clientSeed, and roundId → nonce.

Byte and cursor functions

bytes()

Reads a window from the deterministic HMAC-SHA256 stream.

function bytes(seeds: BinarySeeds, byteCursor: number, count: number): Uint8Array
ParameterTypeRequiredDescription
seedsBinarySeedsyesClient seed, server seed, and nonce.
byteCursornumberyesZero-based raw byte offset.
countnumberyesNumber of bytes to read.
const firstFourBytes = bytes(seeds, 0, 4)

Each 32-byte block authenticates this message with the server seed as its key:

{clientSeed}:{nonce}:{block}

Number functions

floats()

Generates raw deterministic values in [0, 1). Each result consumes four bytes, starting at byteCursor.

function floats(seeds: BinarySeeds, byteCursor: number, count: number): number[]
ParameterTypeRequiredDescription
seedsBinarySeedsyesClient seed, server seed, and nonce.
byteCursornumberyesRaw byte offset where reading begins.
countnumberyesNumber of floats to return.
const first = floats(seeds, 0, 1)
const nextThree = floats(seeds, 4, 3) // Start after the first four-byte float.

For four bytes b₀, b₁, b₂, and b₃, one float is:

b₀ / 256 + b₁ / 65,536 + b₂ / 16,777,216 + b₃ / 4,294,967,296

uint64()

Reads one unsigned 64-bit integer from an eight-byte slot. The return type is bigint, preserving every bit before modulo arithmetic is applied.

function uint64(serverSeed: string, clientSeed: string, nonce: number, slot: number): bigint
ParameterTypeRequiredDescription
serverSeedstringyesHMAC key.
clientSeedstringyesFirst value in the HMAC message.
noncenumberyesNon-negative round or bet number.
slotnumberyesEight-byte slot index; slot 5 begins at byte 40.
const draw = uint64(serverSeed, clientSeed, nonce, 5)
const selectedIndex = Number(draw % 6n)

integers()

Generates unique integer positions from 1 through target. Values are drawn without replacement.

function integers(seeds: BinarySeeds, byteCursor: number, count: number, target: number): number[]
ParameterTypeRequiredDescription
seedsBinarySeedsyesClient seed, server seed, and nonce.
byteCursornumberyesRaw byte offset where reading begins.
countnumberyesNumber of integers to draw. Must not exceed target.
targetnumberyesPositive integer defining the pool 1..target.
const positions = integers(seeds, 0, 3, 10)
// Three unique values between 1 and 10.

integersFromFloats()

Applies the same without-replacement selection to floats that were already generated.

function integersFromFloats(values: readonly number[], target: number): number[]
ParameterTypeRequiredDescription
valuesreadonly number[]yesRaw values in [0, 1).
targetnumberyesPositive integer defining the pool 1..target.
const raw = floats(seeds, 0, 3)
const positions = integersFromFloats(raw, 10)

Use this form when the interface needs to show or store the intermediate floats before converting them into integer positions.

Complete JavaScript flow

Player-seed games

import {
binarySeedFromMnemonic,
floats,
generateMnemonic,
integers,
} from '@gambalabs/provably-fair'

const clientMnemonic = generateMnemonic()
const serverMnemonic = generateMnemonic()

const clientSeed = binarySeedFromMnemonic(clientMnemonic)
const serverSeed = binarySeedFromMnemonic(serverMnemonic)

const seeds = {
clientSeed,
serverSeed,
nonce: 0,
}

const rawValues = floats(seeds, 0, 3)
const positions = integers(seeds, 0, 3, 10)

Public-round games

import { roundSeeds, uint64 } from '@gambalabs/provably-fair'

const seeds = roundSeeds({ roundSeed, hashSeed, roundId })
const draw = uint64(seeds.serverSeed, seeds.clientSeed, seeds.nonce, 5)