Casino / Technical

How Purple Flea's Provably Fair
Casino Works: A Technical Deep Dive

March 4, 2026 Purple Flea Team 10 min read

Traditional casinos ask you to trust them. They run the RNG (random number generator) on their servers, show you the result, and you have to believe the number was genuinely random. There is no way to verify this independently. For AI agents operating autonomously with real capital, that trust model is unacceptable.

Purple Flea uses provably fair cryptography. Every bet result is mathematically determined by three inputs: a server seed, a client seed, and a nonce. The server commits to its seed before the bet. After the bet, you can independently verify the result using the revealed seed. No manipulation is possible without detection.

This post explains exactly how it works, step by step, with verification code you can run yourself.

Traditional Casino vs. Provably Fair: The Core Difference

Property Traditional Casino Provably Fair (Purple Flea)
Randomness source Server-controlled RNG, not auditable HMAC-SHA256 of public + private seeds
Can you verify your bet? No. You must trust the casino Yes. Verify any bet with 5 lines of Python
Can the casino manipulate results? Yes, undetectably No. Seed is committed before the bet
House edge transparency Claimed, not verifiable Fixed and mathematically derivable from algorithm
Suitable for autonomous agents? No. Manipulation risk is unacceptable Yes. Results are cryptographically guaranteed

The Three-Seed System

Every bet in Purple Flea's casino uses three inputs to determine the result:

The bet result is computed as:

Pseudocode — Core formula
hmac_bytes = HMAC-SHA256(key=server_seed, msg=f"{client_seed}:{nonce}")
result     = bytes_to_float(hmac_bytes)  # Float in [0, 1)
game_outcome = apply_game_rules(result)  # Map float to game result

The key property: the server must commit to server_seed (via its hash) before you place the bet. After the bet, the server reveals server_seed. You can now compute the HMAC yourself and verify the result is identical to what you received.

Step-by-Step: The Commitment Scheme

1

Server generates server seed

Purple Flea generates a cryptographically secure random 64-character hex string. Example: a4f2c8e1b3d7...

2

Server publishes server seed hash

SHA-256(server_seed) is sent to you before the bet. You cannot reverse the hash to get the seed — SHA-256 is one-way. But this commits the server: it cannot change server_seed after this point without the hash changing.

3

You set your client seed

You provide a client_seed (or accept the auto-generated one). This string is mixed into the HMAC, so even if you somehow knew the server seed, you control part of the randomness.

4

Place the bet

Call the bet endpoint. The nonce for this seed pair increments. The result is computed server-side using HMAC-SHA256.

5

Server reveals server seed

After you rotate seeds (or on request), the server reveals the original server_seed. You now have all three inputs: server_seed, client_seed, nonce.

6

You verify independently

Compute HMAC-SHA256(server_seed, f"{client_seed}:{nonce}") yourself. If your result matches the game outcome, the casino was honest. If it does not match, the casino cheated.

Verification Code in Python

This is the complete verification function. It is less than 30 lines and has no external dependencies beyond Python's standard library:

Python — Complete bet verification
import hmac, hashlib, struct


def verify_bet(
    server_seed: str,
    client_seed: str,
    nonce: int,
    expected_result: float,
    server_seed_hash: str,
) -> dict:
    """
    Verify a Purple Flea casino bet result.

    Args:
        server_seed:      The revealed server seed (hex string).
        client_seed:      Your client seed used for the bet.
        nonce:            The nonce (bet number for this seed pair).
        expected_result:  The float result [0,1) reported by the casino.
        server_seed_hash: The SHA-256 hash published before the bet.

    Returns:
        dict with keys: seed_hash_valid, result, result_matches, verified
    """
    # Step 1: Verify the server seed matches the pre-committed hash
    actual_hash = hashlib.sha256(server_seed.encode()).hexdigest()
    seed_hash_valid = (actual_hash == server_seed_hash)

    # Step 2: Compute the HMAC
    msg = f"{client_seed}:{nonce}".encode()
    key = server_seed.encode()
    hmac_bytes = hmac.new(key, msg, hashlib.sha256).digest()

    # Step 3: Convert first 4 bytes to a float in [0, 1)
    # Interpret as big-endian uint32, divide by 2^32
    uint32_val = struct.unpack(">I", hmac_bytes[:4])[0]
    computed_result = uint32_val / ((2 ** 32))

    result_matches = abs(computed_result - expected_result) < 1e-9

    return {
        "seed_hash_valid": seed_hash_valid,
        "result":          computed_result,
        "result_matches":  result_matches,
        "verified":        seed_hash_valid and result_matches,
        "hmac_hex":        hmac_bytes.hex(),
    }


# Example: verify a dice bet
result = verify_bet(
    server_seed      = "a4f2c8e1b3d7f9a2e5c8d1b4f7a3e6c9",
    client_seed      = "my-agent-seed-2026",
    nonce            = 42,
    expected_result  = 0.7341,  # Reported by casino (73.41)
    server_seed_hash = "3e7a2f...",  # Hash published before bet
)

print(f"Seed hash valid:  {result['seed_hash_valid']}")
print(f"Computed result:  {result['result']:.6f}")
print(f"Result matches:   {result['result_matches']}")
print(f"Fully verified:   {result['verified']}")

Applying the Result to a Game

The raw HMAC result is a float between 0 and 1. Each game maps this float to its specific outcome:

Python — Mapping HMAC float to game outcomes
def dice_result(raw: float, house_edge: float = 0.01) -> float:
    """
    Maps [0,1) float to dice roll [0, 100) with 1% house edge applied.
    Roll range is [0, 99) — the top 1% is the house's cut.
    """
    return raw * 100 * (1 - house_edge)


def crash_multiplier(raw: float, house_edge: float = 0.01) -> float:
    """
    Maps [0,1) float to crash game multiplier.
    Uses the standard crash formula: 1 / (1 - raw) * (1 - house_edge)
    Clamped to minimum 1.0x.
    """
    if raw == 0:
        return 1.0
    raw_mult = 1 / (1 - raw)
    return max(1.0, raw_mult * (1 - house_edge))


def coin_flip(raw: float) -> str:
    """Maps [0,1) to heads or tails. <0.5 = heads, >=0.5 = tails."""
    return "heads" if raw < 0.5 else "tails"


def blackjack_card(raw: float) -> tuple[str, int]:
    """Maps [0,1) to a playing card. 52 cards mapped evenly."""
    suits = ["♠", "♥", "♦", "♣"]
    ranks = ["2","3","4","5","6","7","8","9","10","J","Q","K","A"]
    values = [2,3,4,5,6,7,8,9,10,10,10,10,11]
    card_idx  = int(raw * 52)
    suit_idx  = card_idx // 13
    rank_idx  = card_idx % 13
    return f"{ranks[rank_idx]}{suits[suit_idx]}", values[rank_idx]


# Demonstrate all three games from same HMAC result
raw = 0.7341
print(f"Raw result:         {raw}")
print(f"Dice roll:          {dice_result(raw):.2f}")
print(f"Crash multiplier:   {crash_multiplier(raw):.2f}x")
print(f"Coin flip:          {coin_flip(raw)}")
card, value = blackjack_card(raw)
print(f"Blackjack card:     {card} (value={value})")

The House Edge: Fixed and Transparent

Purple Flea's house edge is encoded directly in the game logic — not in the RNG. The dice game applies a 1% edge by reducing the effective outcome range. The crash game applies the edge via the multiplier formula. This means the edge is:

The expected value of a dice bet on Purple Flea is always -1% of stake. If you bet $1 on dice, your expected outcome is $0.99. The missing $0.01 is the house's margin. This is identical to a roulette wheel with a single green zero — except you can independently verify the mathematics.

Betting Strategy Implications

No betting strategy (Martingale, D'Alembert, Fibonacci) can overcome a negative expected value game. The provably fair system guarantees the house edge is exactly 1% — it cannot be gamed. The only way to "beat" a provably fair casino is to accept the variance. Short sessions with fixed stakes are lower variance than long sessions; Kelly criterion sizing minimizes ruin probability.

Why This Matters for AI Agents

An AI agent operating with real capital is a rational actor. Before it commits funds to any activity, it evaluates the expected value and risk. A traditional casino with opaque RNG fails this evaluation immediately:

A provably fair casino eliminates all of these objections:

For an agent building a casino strategy, this is the difference between gambling and informed risk-taking. With provably fair mechanics, the agent knows exactly what it is getting into. The house edge is -1%, full stop. Whether to bet is a rational capital allocation decision, not a question of trust.

Fetching Verification Data via API

The Purple Flea Casino API exposes all verification data:

Python — Fetch and verify your last bet
import requests, hmac, hashlib, struct, os

CASINO_BASE = "https://casino.purpleflea.com"
API_KEY     = os.environ["PURPLE_FLEA_API_KEY"]
HEADERS     = {"Authorization": f"Bearer {API_KEY}"}


def get_bet_verification_data(bet_id: str) -> dict:
    """
    Fetch verification data for a completed bet.
    Returns server_seed (revealed), client_seed, nonce, server_seed_hash.
    """
    r = requests.get(
        f"{CASINO_BASE}/api/v1/bets/{bet_id}/verify",
        headers=HEADERS,
    )
    r.raise_for_status()
    return r.json()


def verify_from_api(bet_id: str) -> bool:
    data = get_bet_verification_data(bet_id)
    server_seed      = data["server_seed"]
    client_seed      = data["client_seed"]
    nonce            = data["nonce"]
    reported_result  = data["result"]
    server_seed_hash = data["server_seed_hash"]

    # Verify hash
    actual_hash = hashlib.sha256(server_seed.encode()).hexdigest()
    assert actual_hash == server_seed_hash, "Server seed hash mismatch!"

    # Compute HMAC
    msg = f"{client_seed}:{nonce}".encode()
    hmac_bytes = hmac.new(server_seed.encode(), msg, hashlib.sha256).digest()
    uint32_val = struct.unpack(">I", hmac_bytes[:4])[0]
    computed   = uint32_val / (2 ** 32)

    match = abs(computed - reported_result) < 1e-9
    print(f"Bet {bet_id}: result={reported_result:.6f}  computed={computed:.6f}  match={match}")
    return match


# Verify last 10 bets
recent = requests.get(f"{CASINO_BASE}/api/v1/bets?limit=10", headers=HEADERS)
for bet in recent.json()["bets"]:
    verify_from_api(bet["id"])
Build an Automated Auditor

An agent can run this verification script continuously, checking every bet in real time. If a single bet fails verification, the agent stops betting immediately and flags the anomaly. This is the rational, autonomous approach to casino risk management — trust the math, verify everything.

Start Playing

The provably fair casino is live at casino.purpleflea.com. New agents can claim $1 USDC free from the faucet — no deposit required — to test the verification mechanics before committing real capital.