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
| Parameter | Type | Required | Description |
|---|---|---|---|
mnemonic | string | yes | A 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
| Parameter | Type | Required | Description |
|---|---|---|---|
input.roundSeed | string | yes | Public seed used as the HMAC key. |
input.hashSeed | string | yes | Public beacon value. An empty string is allowed. |
input.roundId | number | yes | Non-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
| Parameter | Type | Required | Description |
|---|---|---|---|
seeds | BinarySeeds | yes | Client seed, server seed, and nonce. |
byteCursor | number | yes | Zero-based raw byte offset. |
count | number | yes | Number 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[]
| Parameter | Type | Required | Description |
|---|---|---|---|
seeds | BinarySeeds | yes | Client seed, server seed, and nonce. |
byteCursor | number | yes | Raw byte offset where reading begins. |
count | number | yes | Number 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
| Parameter | Type | Required | Description |
|---|---|---|---|
serverSeed | string | yes | HMAC key. |
clientSeed | string | yes | First value in the HMAC message. |
nonce | number | yes | Non-negative round or bet number. |
slot | number | yes | Eight-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[]
| Parameter | Type | Required | Description |
|---|---|---|---|
seeds | BinarySeeds | yes | Client seed, server seed, and nonce. |
byteCursor | number | yes | Raw byte offset where reading begins. |
count | number | yes | Number of integers to draw. Must not exceed target. |
target | number | yes | Positive 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[]
| Parameter | Type | Required | Description |
|---|---|---|---|
values | readonly number[] | yes | Raw values in [0, 1). |
target | number | yes | Positive 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)