Building a browser game with client-side Groth16 proofs
A smart contract can't tell whether a submitted score came from a valid game or was simply made up. Dario Dash handles that by proving the run itself. I have been building Dario Dash , a small endless runner on Dusk. The game runs in the browser and does not require a wallet to play. After a ranked run, the browser can generate a Groth16 proof locally and submit the score to a smart contract. The contract does not trust the submitted score. It accepts it only after verifying the proof, binding it to the transaction sender and checking that the run seed has not already been used. The source is available on GitHub . What actually needs to be proven? A score by itself says almost nothing. A client could simply submit any number it wants. For Dario Dash, a valid run includes much more than the final score: the player movement and jump timing the seed-derived obstacle schedule obstacle clearance and collision windows item pickups damage and game-over conditions fireball kills transitions between Regular, Super, Fire and Cape forms the number of ticks played the resulting score The proof must establish that these rules were followed from the initial state until the claimed final state. It also needs to bind the run to the account submitting it, otherwise somebody could copy another player's proof. The architecture The repository is split into a few layers: dash_zk contains the deterministic game simulation used by the browser proving path. dash_core contains a separate 60 Hz simulation used by the RISC Zero path. dash_web exposes the Rust simulation to the browser through WebAssembly. zk_browser contains the Circom circuit and the JavaScript proof conversion code. contract verifies the proof and maintains the leaderboard on Dusk. web contains the playable Vite application. The important boundary is that the game logic is deterministic and integer-only. Floating point physics would be a mess to reproduce consistently across JavaScript, WebAssembly, the proof circuit and th