Fairness & security
Provably fair
Every staked match on OHKO can be re-checked by anyone after it settles. The battle's randomness is fixed before your opponent joins, neither OHKO nor any player can choose it alone, and the result committed on-chain can be reproduced from public data.
Commit and reveal
-
Server seed. Before a staked match is created, the game server draws a 32-byte random
server_seedand stores it encrypted (AES-256-GCM). -
Commitment.
create_matchwritesseed_commitment = sha256(server_seed)into the on-chain match account. From then on the server seed cannot change without everyone noticing. -
Client entropy. When the opponent's
join_matchlands, the program records the most recent Solana slot hash (join_slot_hash). Nobody knew it when the commitment was made. -
Battle seed. The simulator seed is
battle_seed = sha256(server_seed ‖ creator ‖ opponent ‖ join_slot_hash)where
creatorandopponentare the two wallets' 32-byte public keys (the creator always plays as player 1). Every random number in the battle, including both random teams, comes from this seed. -
Settlement. The referee settles with
sha256(battle log)asbattle_log_hash, which is stored on-chain and in theMatchSettledevent. -
Reveal. Once the match is closed on-chain, the server seed is published with the replay.
OHKO could only cheat by knowing the slot hash in advance, and the player who joins cannot see the server seed. Neither side controls the final seed alone.
What a verification checks
sha256(server_seed)equals theseed_commitmentfrom the create transaction.- The battle seed derived from the revealed server seed, both wallets and the recorded slot hash is the one the battle used.
- The simulator's opening inputs (format, players, teams) are exactly what that seed implies, and after them only player choices and forced results follow.
- Re-running the simulator with the recorded inputs reproduces the public battle log byte for byte.
sha256(log)equals thebattle_log_hashcommitted at settlement.- The wallet that was paid is the winner of the re-simulated battle (or both were refunded for a draw).
All on-chain values (commitment, wallets, slot hash, log hash, winner) are read from the program's events in the create, join and settlement transactions on Solana, not from OHKO's servers.
Verify in the browser
Open any staked replay and press Verify, or go to /verify/<matchId>. The page re-runs the
battle in a web worker with exactly the same engine code the server used and shows each check
with its result and the transactions it read.
Verify from the command line
git clone <the OHKO repository> ohko && cd ohko
corepack enable && pnpm install
pnpm verify <matchId>
Options:
--api <url>reads the replay from another OHKO deployment (defaulthttps://ohko.duckdns.org).--rpc <url>reads the chain from your own Solana RPC endpoint (repeatable; the public devnet RPC is the default).
The command exits with status 0 only when every check passes, and prints which check failed otherwise.
Trust assumptions
Being honest about what the proof does not cover:
- Forfeits, timeouts and disconnects are decided by the referee. The log shows them, but a dishonest server could claim that a player timed out.
- Player choices are not signed by the players. The verifier proves the log follows from the seed and the recorded choices, not that each choice came from that player.
- The referee key decides results. The program limits what it can do: it can only pay one of the two players of a match, and only before the settle deadline. After the deadline anyone can refund both players in full. See Smart contract.
Free battles and tournaments
Free battles use the same deterministic engine: their replays publish the seed and the full input log, so they can be re-simulated too, but there is nothing on-chain to compare with. Tournaments commit one master seed on-chain when the table opens; each bracket battle's seed is derived from it, the tournament id, the match index and both wallets, and the master seed is revealed when the table closes.