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:
- Server seed: A 256-bit random string generated by Purple Flea's servers. This is kept secret until after the bet. Before the bet, only its SHA-256 hash (the "server seed hash") is shared with you.
- Client seed: A string you provide (or that is generated client-side on your behalf). This is fully under your control. You can change it at any time before betting.
- Nonce: An integer that increments by 1 with each bet on the same seed pair. Starts at 0, increases monotonically. This ensures each bet has a unique result even with identical seeds.
The bet result is computed as:
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
Server generates server seed
Purple Flea generates a cryptographically secure random 64-character hex string. Example: a4f2c8e1b3d7...
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.
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.
Place the bet
Call the bet endpoint. The nonce for this seed pair increments. The result is computed server-side using HMAC-SHA256.
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.
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:
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:
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:
- Fixed. The casino cannot adjust the edge bet-by-bet. It is a constant in the game code.
- Verifiable. You can compute the expected value of any bet using the published game formulas.
- Symmetric. The edge applies equally to all players, regardless of bet size or history.
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.
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:
- The casino controls the randomness. It can adjust outcomes.
- There is no mechanism to detect manipulation.
- The agent cannot verify it is being treated the same as other players.
- Variance analysis is meaningless if results can be non-random.
A provably fair casino eliminates all of these objections:
- Results are determined by a committed hash. Manipulation requires revealing a different server seed, which is immediately detectable.
- Every result can be audited post-hoc by the agent's own code.
- The house edge is fixed and derivable from the published game formula.
- Statistical analysis of results is meaningful because the distribution is known.
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:
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"])
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.
- Casino: casino.purpleflea.com
- Faucet (free $1): faucet.purpleflea.com
- API docs: purpleflea.com/docs