Online blackjack has a trust problem. The player never sees the shoe; the house shuffles, deals and resolves outcomes in a single opaque step. Traditional casinos lean on regulators and physical cameras. Online casinos offer a "server seed hash" you can check after the fact — but that only proves the post-game seed matched the hash, not that the server picked it honestly before you committed money. A house that tries several seeds and publishes only the one that produces a losing hand for you will pass that check every time.
This is the problem provably fair Kaspa blackjack solves. Kaspa Arena Blackjack closes the timing gap with three complementary layers: commitments that lock both parties to seeds before either sees a card, a Merkle tree that binds every dealt card to a fixed position in the shuffled deck, and a zero-knowledge proof that certifies the shuffle was canonical without revealing the hidden order. A Kaspa L1 covenant enforces game rules, timeouts and payouts independently of the proof system.
This article traces each layer from seed commitment through final settlement, names what the public verifier checks today, and states the honest boundaries of the current product.
The Commit-Reveal Foundation
Each party — dealer and player — generates a secret seed off-chain. Before any money enters the game covenant, both publish a commitment: a hash of their seed. These commitments are written into the Room state and inherited by the Game UTXO when the player joins.
Commit-reveal scheme — a two-phase protocol where a party first publishes a binding hash (commitment) of a secret value, and only later reveals the value itself. The party cannot change their secret after seeing the other party's reveal.
The ordering is enforced on-chain by the finite state machine:
1. Room creation: the dealer publishes dealer_commit — BLAKE3(dealer_seed) — when funding the Room UTXO. 2. Player JOIN: the player publishes player_commit — BLAKE3(player_seed) — as part of the covenant witness. 3. Player seed reveal: the player reveals player_seed. The covenant checks that BLAKE3(player_seed) matches player_commit. Only then does the Game advance to DECK_PROOF_PENDING.
The dealer's seed is never published on-chain. It is consumed inside the zero-knowledge circuit and remains hidden for the duration of the hand — otherwise the player could compute the entire deck order.
Once both commitments are locked, the shuffle seed is derived deterministically:
combined = BLAKE3( domain_tag || game_id || dealer_seed || player_seed )
Because the dealer committed before the player sat down, and the player committed before the dealer's seed could influence anything, neither party can bias the combined seed after seeing the other's contribution.
Building the Deck: Fisher–Yates and Merkle Tree
The combined seed drives a standard Fisher–Yates shuffle over the array [0, 1, …, 51] — one index per card in a standard deck. The algorithm is unbiased: every permutation is equally likely given a uniformly random seed.
for i from 51 down to 1:
j = random_int_in_range(0, i) // derived from combined seed
swap deck[i] with deck[j]
The result is a permutation deck[0..51]. In Kaspa Blackjack V1 the dealing order is canonical:
0 player's first card 3 dealer's hole card (hidden)
1 dealer's up-card 4 first HIT card
2 player's second card 5+ subsequent cards as needed
A SHA-256 Merkle tree is then built over all 52 card values. Each leaf is SHA256(deck[i]). The resulting root — a single 32-byte hash — is written into the Game state as deck_root.
This tree enables selective disclosure with position binding. When card at index k is dealt, the prover provides the card value plus a Merkle path (up to six sibling hashes). Any verifier recomputes the root:
recomputed = merkle_root( SHA256(deck[k]), siblings[0..5] )
assert recomputed == deck_root
The monotonic index — next_card_index increments by exactly one after each valid proof — prevents skip, repeat and substitution attacks. The covenant script rejects any state transition where the index does not advance correctly.
The Zero-Knowledge Proof: Certifying the Shuffle
The Merkle tree proves that a dealt card belongs to a committed root. But who proves the root was computed correctly — that the shuffle was canonical? A malicious dealer could build a Merkle tree over a rigged deck and commit that deck_root to the covenant.
This is where the blackjack zero knowledge proof enters. The entire computation — both seeds → combined → Fisher–Yates → permutation → SHA-256 tree → root — runs inside a RISC Zero zkVM guest program. The output is a Groth16 receipt: a compact proof that the computation was performed correctly.
Groth16 — a zero-knowledge proof system producing constant-size proofs regardless of computation complexity. Kaspa Arena compiles the shuffle logic into a RISC Zero zkVM guest program and wraps the execution proof in Groth16 for compact on-chain verification.
The proof journal binds together:
game_id— which hand this proof belongs to- Both seed commitments — preventing reuse for a different game
- The revealed player seed — so the verifier can recompute the combined seed
deck_root— the Merkle root all subsequent card reveals must match- Rules and schema hashes — tying the proof to the specific game configuration (H17/S17, payout structure)
The zero-knowledge property means the proof reveals nothing about the dealer's seed or the hidden card order. It proves only: *"I know a dealer seed such that, combined with the player's revealed seed and this game ID, the canonical shuffle produces exactly this Merkle root."*
The deployed variant (Groth16 0x20, variant C) produces a 3.167 KB transaction costing approximately 0.16 KAS — small enough to fit in a covenant witness without bloating the Game UTXO.
Proof Meets Covenant: The Junction
The zero-knowledge proof and the Kaspa L1 covenant are complementary layers. Neither substitutes for the other.
The ZK proof verifies: both commitments are opened correctly, the 52-card permutation is canonical, the Merkle root matches, and the proof binds to this game's identity and rules.
The covenant script verifies: state transitions follow the blackjack FSM (14 branches, all tested), hand totals are recomputed from raw card bytes in the script — not trusted from the witness — dealer strategy follows the pinned rule (H17 or S17), timeouts are enforced by DAA-relative sequence locks (Kaspa's Difficulty Adjustment Algorithm provides the on-chain clock; see the Kaspa wiki for details), and payouts are computed from the terminal state and written to exact outputs.
The PROVE_AND_DEAL transaction is the junction between these layers. It carries the Groth16 receipt as witness, writes deck_root to the Game state, reveals cards 0–2 with their Merkle paths (the initial deal), and sets hole_card_commit — a BLAKE3 commitment to the dealer's hidden card — all in one transaction. The covenant checks the proof, verifies the three initial Merkle paths against the new root, and advances the state to PLAYER_TURN.
This design means a bug in one layer does not necessarily compromise the others. A soundness issue in the ZK circuit would not allow incorrect payouts — the covenant still enforces correct settlement from whatever state was committed.
Card-by-Card Verification During Play
Every subsequent card follows the same pattern. When the player hits:
1. The dealer provides the card value at next_card_index (starting at 4) with its Merkle path 2. The covenant recomputes the root from leaf and path 3. The covenant computes the new hand total from the raw card bytes — handling ace promotion internally (an ace counts as 11 when doing so doesn't bust) 4. next_card_index increments by 1
Hand totals are derived facts — never trusted from the witness. A successor with correct cards but a forged total is rejected by the state-region binding. This holds across all 10 hand-dependent branches (307 matrix test cases, zero failures).
The dealer's hole card reveal (REVEAL_HOLE) is particularly strict: the covenant checks the card against both its hole_card_commit (set at deal time) and its Merkle path against deck_root. Both checks read from the same physical byte in the state region, so a mismatch in either dimension fails.
The Merkle deck proof is the mechanism that makes each of these reveals trustworthy. Without it, the dealer could claim any card value at any position. With it, each card is cryptographically tied to the committed shuffle.
The Public Verifier
Kaspa Forge publishes an independent verifier in the arena-verifier repository, built from a fail-closed export of committed source. The export includes the shuffle logic, public wire types, the verification function, JSON Schema, a mainnet test vector, Cargo.lock and mutation tests. Dice code, controller internals, dealer nodes, signer, Desk UI and all secrets are excluded by an allowlist, and the tree is scanned for secret-shaped markers before publication.
The Kaspa Arena verifier v0.1 is scoped as an evidence-consistency verifier. It independently:
1. Opens both seed commitments 2. Reproduces all 52 cards and the SHA-256 Merkle root 3. Verifies each revealed card against its forced position 4. Replays the branch log to the terminal state
It intentionally does not verify rules, stake amounts, outcomes, transaction IDs, DAG inclusion or settlement outputs — the current proof endpoint does not provide raw transaction bundles. A green v0.1 result proves the shuffle and deal were honest, not that the payout was correct. A future chain-bound verifier would need content-addressed raw transactions and chain context.
Honest Boundaries of the Public Mainnet Beta
Arena Blackjack is a public mainnet beta. The consensus FSM is frozen and tested with 7,010 matrix cases across four production stages, all showing identical results. Five independent audits verify that the covenant does not allow bank theft. Funded simnet lifecycles — Room → Game → terminal payout — have been exercised end-to-end.
Current boundaries:
- The public verifier v0.1 is evidence-consistency, not chain-bound. A green result should not be described as "payout verified."
player_hit_deal_timeouthas never been triggered on mainnet. This permissionless path exists in lifecycle probes but has not been tested against the live covenant.- Firefox and Safari are unverified. The WASM proof-building flow has been confirmed on Chromium only.
- P2P dealer mode is deferred. Research concluded with a GO for local dealer proving, but implementation is postponed; current open tables use a house dealer.
- Natural blackjack pays 3:2 from generator 6. Historical rooms under generator 5 retain their 1:1 payout — different script addresses, not a runtime toggle.
- HOSTED prover fee is currently 0. The house covers proving costs. Service fee is 0.9% of the two-stake pot, charged only to the winner. No timeout path pays any fee.
Both HOSTED and LOCAL verification produce identical Groth16 receipts — the difference is only who runs the prover and where the fee output goes.
Arena Blackjack runs as a public mainnet beta with open S17 tables at six stake tiers (5–100 KAS). You can inspect completed hands' receipts, download the verifier, and replay the shuffle yourself from the Arena section of Desk. Keys remain on your device — the covenant lives on-chain, not on our servers.
FAQ
What does the zero-knowledge proof in Kaspa Blackjack actually verify?
It proves that the shuffle was derived deterministically from both players' seed commitments using a canonical Fisher–Yates algorithm over all 52 cards, that the Merkle root matches the resulting deck, and that every revealed card belongs to the committed position. It does not reveal the dealer's seed or the hidden card order.
Can the dealer change the deck after seeing the player's seed?
No. Both seeds are committed (hashed) before either party reveals. The combined seed is hashed from both commitments plus the game ID using BLAKE3, so the dealer cannot choose their seed in response to the player's.
What is a Merkle deck proof?
A SHA-256 Merkle tree is built over the 52 shuffled card indices. Each time a card is dealt, the verifier receives the card value plus a Merkle path (up to six sibling hashes) proving that the card sits at the correct leaf. A monotonic index prevents skipping or replaying positions.
How can I independently verify a finished hand?
The public verifier repository (arena-verifier) takes the two seed commitments, reproduces the full 52-card permutation and Merkle root, and checks every revealed card against its forced position. As of v0.1 it is an evidence-consistency verifier: it proves the shuffle and deal were honest but does not re-check L1 settlement outputs.
Does the ZK proof enforce the blackjack rules?
No. The zero-knowledge circuit verifies the shuffle and Merkle root only. Hit/stand legality, hand totals, dealer strategy (H17/S17), timeouts and payouts are all enforced by the Kaspa L1 covenant script. The two systems are complementary layers.
Is Kaspa Arena Blackjack live?
Arena Blackjack is a public mainnet beta. The consensus FSM is frozen and tested, and open tables accept seats from any Desk profile. It remains a beta product under active observation.
Put your KAS where theft can be cancelled
A covenant vault on Kaspa mainnet: your keys, your rules, our tooling. Free on-chain, forever.
Create a vault
