<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://effectstream.github.io/docs/learn-compact-with-games</id>
    <title>EffectStream Blog</title>
    <updated>2026-06-01T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://effectstream.github.io/docs/learn-compact-with-games"/>
    <subtitle>EffectStream Blog</subtitle>
    <icon>https://effectstream.github.io/docs/img/favicon.svg</icon>
    <entry>
        <title type="html"><![CDATA[Werewolf]]></title>
        <id>https://effectstream.github.io/docs/learn-compact-with-games/werewolf</id>
        <link href="https://effectstream.github.io/docs/learn-compact-with-games/werewolf"/>
        <updated>2026-06-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[N-player social deduction with a host-facilitated flow tuned for performance at scale.]]></summary>
        <content type="html"><![CDATA[
<div class="wrapper_HR5J"><div class="label_u3_I"><span class="labelLeft_ZPD0"><span class="labelTitle_yDoQ">Werewolf</span><span class="labelDot_sdds">·</span><span class="labelKind_Mixq">Live demonstration</span></span><span class="labelRight_z2F4"><span class="labelStatus_WxIV">● PLAYABLE</span><span class="labelDot_sdds">·</span><span class="labelStatus_WxIV"><time class="date_Olo9" datetime="2026-06-01T00:00:00.000Z">Jun 2026</time></span></span></div><div class="stage_lZPK" style="aspect-ratio:1440 / 1008"><iframe src="https://werewolf.midnight.fun/?game_frame=true" title="Werewolf game" class="frame_cDyI" style="width:1464px;height:1032px;transform:scale(1)" scrolling="no" allow="fullscreen"></iframe></div><div class="caption_htAG"><span class="captionLeft_k6lD">click frame to play</span><span class="captionRight_jxDn">how it was built ↓</span></div></div>
<aside class="wrapper_dmRO" role="note"><div class="label_jyYz">◇ Note · Multi-chain</div><div class="body_ZO6Y"><p class="message_JrXM">EffectStream is a multi-chain library - you can easily swap the chain or add more wallets: Cardano, EVM chains, Midnight, Bitcoin, and more.</p><a class="action_epi2" href="https://effectstream.github.io/docs/home/chains/">Browse supported chains →</a></div></aside>
<p>Social deduction at a round table: vote out the werewolves before they pick off the village - with nobody able to see who voted for whom.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="under-the-hood">Under the hood<a href="https://effectstream.github.io/docs/learn-compact-with-games/werewolf#under-the-hood" class="hash-link" aria-label="Direct link to Under the hood" title="Direct link to Under the hood" translate="no">​</a></h2>
<p><strong>The game.</strong> Werewolf is N-player social deduction with day/night phases, secret roles, and elimination votes. The client renders a 3D round table with player avatars in <strong>Three.js</strong>.</p>
<p><strong>Chains.</strong> Werewolf splits across two chains: <strong>Arbitrum</strong> hosts the lobby (<code>createGame</code> / <code>joinGame</code> on a <code>PaimaL2Contract</code>), while the <strong>secret voting</strong> runs on <strong>Midnight</strong>. The EVM side is swappable; Midnight is where the privacy guarantees come from.</p>
<p><strong>Running on EffectStream.</strong> The EffectStream state machine tracks the EVM lobby and the on-chain round state, and computes the leaderboard. Votes are proved client-side in a WebAssembly worker and submitted through the <strong>batcher</strong>. A <strong>trusted-but-verifiable host node</strong> drives the round loop - it provides role witnesses and resolves each phase by decrypting votes - but every step is committed on-chain, so it can't lie: the whole game is auditable at the end.</p>
<p><strong>Leaderboard.</strong> Players earn points tracked into the leaderboard endpoint (the Standings panel). No achievements.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-compact-contract">The Compact contract<a href="https://effectstream.github.io/docs/learn-compact-with-games/werewolf#the-compact-contract" class="hash-link" aria-label="Direct link to The Compact contract" title="Direct link to The Compact contract" translate="no">​</a></h2>
<a href="https://github.com/effectstream/werewolf-game" target="_blank" rel="noopener noreferrer" class="link_MP4t"><span class="glyph_nB_4">&lt;/&gt;</span><span>View source on GitHub</span><span class="arrow_rvyh">→</span></a>
<p><strong>Source:</strong> <a href="https://github.com/effectstream/werewolf-game/blob/main/packages/shared/contracts/midnight/contract-werewolf/src/Werewolf.compact" target="_blank" rel="noopener noreferrer" class=""><code>packages/shared/contracts/midnight/contract-werewolf/src/Werewolf.compact</code></a></p>
<p>The headline is <strong>secret voting</strong>: each vote enters the contract already encrypted, only the host can decrypt it, yet the contract still enforces who may vote (a Merkle proof against the alive set) and that nobody votes twice (a per-round nullifier). Roles are committed up front and revealed only at the end, so the trusted host stays honest by construction.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="admin-secret-commitment">Admin secret commitment<a href="https://effectstream.github.io/docs/learn-compact-with-games/werewolf#admin-secret-commitment" class="hash-link" aria-label="Direct link to Admin secret commitment" title="Direct link to Admin secret commitment" translate="no">​</a></h3>
<p>The host's authority is a hash commitment, not a wallet pubkey. At game creation the admin's secret is committed as <code>adminSecretCommitment</code>; every admin-only circuit pulls the secret back through the <code>wit_getAdminSecret</code> witness and asserts the recomputed commitment matches. Same idea as Go Fish's owner check, scoped per game via the witness signature <code>(gameId)</code>.</p>
<details class="details_DvdZ"><summary class="summary_rS5Z"><span class="chevron__11n" aria-hidden="true">▸</span><span class="tag_xK_k">Compact</span><span class="title_RZ4p">`adminPunishPlayer` (admin gate)</span><span class="toggle_As0a" aria-hidden="true"></span></summary><div class="body_cu0N"><div class="language-compact codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-compact codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">witness</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">wit_getAdminSecret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">adminPunishPlayer</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    _gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    _playerIdx</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> gameId </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">_gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> playerIdx </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">_playerIdx</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> state </span><span class="token operator">=</span><span class="token plain"> games</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> adminSecret </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">wit_getAdminSecret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token function" style="color:rgb(80, 250, 123)">Crypto_computeAdminSecretCommitment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">adminSecret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">==</span><span class="token plain"> state</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">adminSecretCommitment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token string" style="color:rgb(255, 121, 198)">"Only Admin can punish"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> pk </span><span class="token operator">=</span><span class="token plain"> PlayerKey </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> playerIdx</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> playerIdx </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">players</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">member</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">pk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">&amp;&amp;</span><span class="token plain"> players</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">pk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">isAlive</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> current </span><span class="token operator">=</span><span class="token plain"> players</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">pk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        players</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">insert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">pk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> PlayerState </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">current</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> isAlive</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token boolean">false</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        games</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">insert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> GameState </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">state</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">            aliveCount</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">state</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">aliveCount </span><span class="token operator">-</span><span class="token plain"> </span><span class="token number">1</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div></div></details>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="secret-voting-encrypted-vote--alive-proof--nullifier">Secret voting (encrypted vote + alive proof + nullifier)<a href="https://effectstream.github.io/docs/learn-compact-with-games/werewolf#secret-voting-encrypted-vote--alive-proof--nullifier" class="hash-link" aria-label="Direct link to Secret voting (encrypted vote + alive proof + nullifier)" title="Direct link to Secret voting (encrypted vote + alive proof + nullifier)" translate="no">​</a></h3>
<p>Every day-phase vote enters the contract as an <strong>already-encrypted ciphertext</strong> built off-chain in the player's witness (<code>wit_getActionData</code>). The contract never learns what was voted - only the host's key decrypts it later. But the contract still enforces two things: (1) the voter is in the current alive set, proven by a Merkle path against <code>aliveTreeRoot</code> without revealing <em>which</em> player they are, and (2) they haven't already voted this round, via a per-round nullifier inserted into a public <code>Set</code>. The ciphertext lands in <code>roundVotes</code> keyed by the nullifier. The result is a verifiable secret ballot.</p>
<details class="details_DvdZ"><summary class="summary_rS5Z"><span class="chevron__11n" aria-hidden="true">▸</span><span class="tag_xK_k">Compact</span><span class="title_RZ4p">`voteDay`</span><span class="toggle_As0a" aria-hidden="true"></span></summary><div class="body_cu0N"><div class="language-compact codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-compact codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// Witness implemented by the player off-chain. ActionData wraps an encrypted</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// vote (only the host's key decrypts it), a Merkle path proving the player is</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// in the alive set, and the leaf secret used to nullify.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">witness</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">wit_getActionData</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> round</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> ActionData</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">ledger</span><span class="token plain"> voteNullifiers</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Set</span><span class="token operator">&lt;</span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">ledger</span><span class="token plain"> roundVotes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Map</span><span class="token operator">&lt;</span><span class="token plain">VoteKey</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">3</span><span class="token operator">&gt;&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">voteDay</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">_gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> gameId </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">_gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> state </span><span class="token operator">=</span><span class="token plain"> games</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">state</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">phase </span><span class="token operator">==</span><span class="token plain"> Phase</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Day</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Not Day phase"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> actionData </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">wit_getActionData</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> state</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">round</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> encryptedVote </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">actionData</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">encryptedAction</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> merklePath </span><span class="token operator">=</span><span class="token plain"> actionData</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">merklePath</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> leafSecret </span><span class="token operator">=</span><span class="token plain"> actionData</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">leafSecret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// (1) Prove the voter is alive, anonymously</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> leaf </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">Crypto_hash</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">leafSecret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token function" style="color:rgb(80, 250, 123)">Crypto_verifyMerkleProof</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">state</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">aliveTreeRoot</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> leaf</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> merklePath</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token string" style="color:rgb(255, 121, 198)">"Invalid Merkle Proof"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// (2) One vote per voter per round - nullifier blocks the second</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> nullifier </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">Crypto_computeNullifierDay</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> state</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">round</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> leafSecret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> publicNullifier </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">nullifier</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token operator">!</span><span class="token plain">voteNullifiers</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">member</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">publicNullifier</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Double voting detected"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    voteNullifiers</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">insert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">publicNullifier</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Store the ciphertext for the host to decrypt; the contract never sees the vote</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    roundVotes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">insert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        VoteKey </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> phase</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Phase</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Day</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> round</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> state</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">round</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> nullifier</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> publicNullifier </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        encryptedVote</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> publicNullifier</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div></div></details>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="post-game-fairness-via-master-secret-reveal">Post-game fairness via master secret reveal<a href="https://effectstream.github.io/docs/learn-compact-with-games/werewolf#post-game-fairness-via-master-secret-reveal" class="hash-link" aria-label="Direct link to Post-game fairness via master secret reveal" title="Direct link to Post-game fairness via master secret reveal" translate="no">​</a></h3>
<p>Role assignments are committed to public state at game creation but stay encrypted until the game ends. When the host reveals the master secret, anyone can recompute the salt for each <code>playerIdx</code> and verify the stored <code>roleCommitment</code> matches the claimed role. The host can't retroactively re-assign roles - the commitments were locked in at <code>createGame</code> time.</p>
<details class="details_DvdZ"><summary class="summary_rS5Z"><span class="chevron__11n" aria-hidden="true">▸</span><span class="tag_xK_k">Compact</span><span class="title_RZ4p">`verifyFairness`</span><span class="toggle_As0a" aria-hidden="true"></span></summary><div class="body_cu0N"><div class="language-compact codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-compact codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">verifyFairness</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    _gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    _masterSecret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    _playerIdx</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    _assignedRole</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">8</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Boolean</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> gameId </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">_gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> masterSecret </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">_masterSecret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> playerIdx </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">_playerIdx</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> assignedRole </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">_assignedRole</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> state </span><span class="token operator">=</span><span class="token plain"> games</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Step 1: the revealed master secret must hash to the public commitment</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> calculatedCommit </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">Crypto_hash</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">masterSecret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">calculatedCommit </span><span class="token operator">!=</span><span class="token plain"> state</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">masterSecretCommitment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token boolean">false</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Step 2: re-derive this player's salt from the master secret</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> saltSeed </span><span class="token operator">=</span><span class="token plain"> std_persistentHash</span><span class="token operator">&lt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain">masterSecret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">pad</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">32</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"salt"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> playerIdx</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Step 3: re-derive the role commitment and compare to the stored one</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> pk </span><span class="token operator">=</span><span class="token plain"> PlayerKey </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> playerIdx</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> playerIdx </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token operator">!</span><span class="token plain">players</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">member</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">pk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token boolean">false</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> roleCommitment </span><span class="token operator">=</span><span class="token plain"> players</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">pk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">roleCommitment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> derivedCommit </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">Crypto_commitRole</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">assignedRole</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> saltSeed</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> derivedCommit </span><span class="token operator">==</span><span class="token plain"> roleCommitment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div></div></details>
<!-- -->
<aside class="wrapper_oRlc" role="complementary"><div class="label_Yi32">◇ Note · Community</div><div class="body_G7uQ"><p class="message_TWsg">Have questions about the techniques in this post? Drop into the Midnight Discord - happy to talk it through.</p><a class="action_cOUd" href="https://discord.com/invite/midnightnetwork" target="_blank" rel="noopener noreferrer">Join Midnight Discord →</a></div></aside>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Go Fish]]></title>
        <id>https://effectstream.github.io/docs/learn-compact-with-games/go-fish</id>
        <link href="https://effectstream.github.io/docs/learn-compact-with-games/go-fish"/>
        <updated>2026-05-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Mental poker and trustless card shuffling, with a private key fed directly into circuits.]]></summary>
        <content type="html"><![CDATA[
<div class="wrapper_HR5J"><div class="label_u3_I"><span class="labelLeft_ZPD0"><span class="labelTitle_yDoQ">Go Fish</span><span class="labelDot_sdds">·</span><span class="labelKind_Mixq">Live demonstration</span></span><span class="labelRight_z2F4"><span class="labelStatus_WxIV">● PLAYABLE</span><span class="labelDot_sdds">·</span><span class="labelStatus_WxIV"><time class="date_Olo9" datetime="2026-05-01T00:00:00.000Z">May 2026</time></span></span></div><div class="stage_lZPK" style="aspect-ratio:1440 / 1008"><iframe src="https://gofish.midnight.fun/?game_frame=true" title="Go Fish game" class="frame_cDyI" style="width:1464px;height:1032px;transform:scale(1)" scrolling="no" allow="fullscreen"></iframe></div><div class="caption_htAG"><span class="captionLeft_k6lD">click frame to play</span><span class="captionRight_jxDn">how it was built ↓</span></div></div>
<aside class="wrapper_dmRO" role="note"><div class="label_jyYz">◇ Note · Multi-chain</div><div class="body_ZO6Y"><p class="message_JrXM">EffectStream is a multi-chain library - you can easily swap the chain or add more wallets: Cardano, EVM chains, Midnight, Bitcoin, and more.</p><a class="action_epi2" href="https://effectstream.github.io/docs/home/chains/">Browse supported chains →</a></div></aside>
<p>The classic card game, played honestly between two strangers - no trusted dealer, thanks to mental poker.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="under-the-hood">Under the hood<a href="https://effectstream.github.io/docs/learn-compact-with-games/go-fish#under-the-hood" class="hash-link" aria-label="Direct link to Under the hood" title="Direct link to Under the hood" translate="no">​</a></h2>
<p><strong>The game.</strong> Go Fish is a 2-player card game: ask your opponent for ranks, draw from the pond, and collect books of four. The client is built in <strong>Three.js</strong> with Balatro-style post-processing.</p>
<p><strong>Chains.</strong> Go Fish splits responsibilities across two chains: <strong>Arbitrum</strong> hosts the lobby and matchmaking (a <code>PaimaL2Contract</code> emits <code>createdLobby</code> / <code>joinedLobby</code>), while the actual card cryptography - shuffling, dealing, revealing - runs on <strong>Midnight</strong>. Arbitrum is swappable for any EVM chain; the Midnight side is where the interesting part lives.</p>
<p><strong>Running on EffectStream.</strong> The EffectStream state machine watches the EVM lobby events and auto-starts the match when the second player joins, then tracks the Midnight gameplay. Card moves are proved client-side in a WebAssembly worker and submitted through the <strong>batcher</strong> in gasless mode, so players don't need a funded wallet to play. A 300-second turn timeout (enforced on-chain) keeps a stalled opponent from freezing the game.</p>
<p><strong>Leaderboard.</strong> Players are ranked by games won and win-rate on the leaderboard endpoint (the Standings panel). No achievements - the ladder is the progression surface. The contract is also multi-tenant: one deployment hosts many concurrent games, every piece of state keyed by <code>gameId</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-compact-contract">The Compact contract<a href="https://effectstream.github.io/docs/learn-compact-with-games/go-fish#the-compact-contract" class="hash-link" aria-label="Direct link to The Compact contract" title="Direct link to The Compact contract" translate="no">​</a></h2>
<a href="https://github.com/effectstream/go-fish" target="_blank" rel="noopener noreferrer" class="link_MP4t"><span class="glyph_nB_4">&lt;/&gt;</span><span>View source on GitHub</span><span class="arrow_rvyh">→</span></a>
<p><strong>Source:</strong> <a href="https://github.com/effectstream/go-fish/blob/main/packages/shared/contracts/midnight/go-fish-contract/src/Deck.compact" target="_blank" rel="noopener noreferrer" class=""><code>packages/shared/contracts/midnight/go-fish-contract/src/Deck.compact</code></a></p>
<p>Go Fish's headline is a complete <strong>mental poker</strong> implementation in Compact - the protocol for shuffling and dealing a deck without anyone, including the contract, learning the card order. It isn't Go Fish-specific: any card game can be built on top of it. Cards are points on the Jubjub curve; players collaboratively mask the deck with secret scalars and reveal cards by peeling those scalars back off.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="cards-as-elliptic-curve-points">Cards as elliptic curve points<a href="https://effectstream.github.io/docs/learn-compact-with-games/go-fish#cards-as-elliptic-curve-points" class="hash-link" aria-label="Direct link to Cards as elliptic curve points" title="Direct link to Cards as elliptic curve points" translate="no">​</a></h3>
<p>Every card is a point on the embedded Jubjub curve. A static deck of 21 points (one per card value) is initialized once at deploy time and shared by every game; each per-game shuffle starts from a copy. Storing cards as curve points is what makes the rest of the protocol possible: <code>std_ecMul(point, scalar)</code> lets each player homomorphically mask the deck with their secret without anyone decrypting anything in between.</p>
<details class="details_DvdZ"><summary class="summary_rS5Z"><span class="chevron__11n" aria-hidden="true">▸</span><span class="tag_xK_k">Compact</span><span class="title_RZ4p">`init_static_deck` + per-game deck</span><span class="toggle_As0a" aria-hidden="true"></span></summary><div class="body_cu0N"><div class="language-compact codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-compact codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">module Deck </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> CompactStandardLibrary</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> CompactStandardLibrary </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">prefix</span><span class="token plain"> std_</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'./HashTransient'</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">prefix</span><span class="token plain"> h_</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// Static mapping shared by every game: value &lt;-&gt; JubjubPoint</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">ledger</span><span class="token plain"> deckCurveToCard</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">        </span><span class="token class-name">Map</span><span class="token operator">&lt;</span><span class="token plain">JubjubPoint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Field</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">ledger</span><span class="token plain"> reverseDeckCurveToCard</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Map</span><span class="token operator">&lt;</span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> JubjubPoint</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">ledger</span><span class="token plain"> staticDeckInitialized</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">  </span><span class="token class-name">Boolean</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// Per-game deck state: gid -&gt; {cardIndex -&gt; JubjubPoint}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">ledger</span><span class="token plain"> gameDeck</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">         </span><span class="token class-name">Map</span><span class="token operator">&lt;</span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token class-name">Map</span><span class="token operator">&lt;</span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> JubjubPoint</span><span class="token operator">&gt;&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">ledger</span><span class="token plain"> gameDeckSize</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">     </span><span class="token class-name">Map</span><span class="token operator">&lt;</span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">64</span><span class="token operator">&gt;&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">ledger</span><span class="token plain"> gameTopCardIndex</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Map</span><span class="token operator">&lt;</span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// One-time: seed the static deck with 21 curve points</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">init_static_deck</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">staticDeckInitialized</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token function" style="color:rgb(80, 250, 123)">for</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> i of </span><span class="token number">0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token number">21</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> cardPoint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> JubjubPoint </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">getPointFromValue</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">i</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        deckCurveToCard</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">insert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">cardPoint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">i</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> Field</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        reverseDeckCurveToCard</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">insert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">i</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> cardPoint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    staticDeckInitialized </span><span class="token operator">=</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div></div></details>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="joint-shuffle-with-cheating-detection">Joint shuffle with cheating detection<a href="https://effectstream.github.io/docs/learn-compact-with-games/go-fish#joint-shuffle-with-cheating-detection" class="hash-link" aria-label="Direct link to Joint shuffle with cheating detection" title="Direct link to Joint shuffle with cheating detection" translate="no">​</a></h3>
<p>Each player calls <code>shuffle_deck</code>. The circuit masks every card with the player's secret scalar via <code>std_ecMul</code>, then asks an off-chain witness (<code>get_sorted_deck_witness</code>) to return the masked cards in shuffled order. To catch a witness that swapped a card out, the circuit computes a coordinate-based <strong>grand product</strong> over both the original and the sorted lists with an in-circuit challenge <code>gamma</code>; the products must match. If any card was substituted, the product breaks and the shuffle reverts. After the second player shuffles, the deck is fully masked - no single party can decrypt it.</p>
<details class="details_DvdZ"><summary class="summary_rS5Z"><span class="chevron__11n" aria-hidden="true">▸</span><span class="tag_xK_k">Compact</span><span class="title_RZ4p">`shuffle_deck`</span><span class="toggle_As0a" aria-hidden="true"></span></summary><div class="body_cu0N"><div class="language-compact codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-compact codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">shuffle_deck</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> playerIndex</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">64</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> gid </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> secret </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">player_secret_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gid</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> playerIndex</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> INDICES_21</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Vector</span><span class="token operator">&lt;</span><span class="token number">21</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">64</span><span class="token operator">&gt;&gt;</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token number">0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">1</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">2</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">3</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">4</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">5</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">6</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">7</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">8</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">9</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">10</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token number">11</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">12</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">13</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">14</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">15</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">16</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">17</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">18</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">19</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">20</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Apply the player's secret as a scalar to every card point</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> cards </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">map</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">idx</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> point </span><span class="token operator">=</span><span class="token plain"> gameDeck</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gid</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">idx</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> JubjubPoint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">std_ecMul</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">point</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">secret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> INDICES_21</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Witness returns the masked deck in shuffled order</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> sorted_cards </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">get_sorted_deck_witness</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">cards</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Grand-product cheating check over X-coordinates</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> xsum </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">fold</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">acc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> c</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> acc </span><span class="token operator">+</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">jubjubPointX</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">c</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">0</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> Field</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> cards</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> gamma</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Field </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">h_hashField</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">xsum</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> Field</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> prod_original </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">fold</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">acc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> c</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> acc </span><span class="token operator">*</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">jubjubPointX</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">c</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">+</span><span class="token plain"> gamma</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">1</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> Field</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> cards</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> prod_sorted   </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">fold</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">acc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> c</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> acc </span><span class="token operator">*</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">jubjubPointX</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">c</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">+</span><span class="token plain"> gamma</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">1</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> Field</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> sorted_cards</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">prod_original </span><span class="token operator">==</span><span class="token plain"> prod_sorted</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">           </span><span class="token string" style="color:rgb(255, 121, 198)">"Witness failed: Cheating detected (cards modified)"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Write the shuffled, masked deck back</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token function" style="color:rgb(80, 250, 123)">for</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> i of </span><span class="token number">0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token number">21</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        gameDeck</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gid</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">insert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">i</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">sorted_cards</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain">i</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div></div></details>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="card-reveal-via-partial-decryption">Card reveal via partial decryption<a href="https://effectstream.github.io/docs/learn-compact-with-games/go-fish#card-reveal-via-partial-decryption" class="hash-link" aria-label="Direct link to Card reveal via partial decryption" title="Direct link to Card reveal via partial decryption" translate="no">​</a></h3>
<p>To learn a card, every other player who masked the deck applies the <strong>inverse</strong> of their secret scalar with <code>std_ecMul(point, invScalar)</code>. Once all masks except the asking player's are peeled off, the result is a <code>JubjubPoint</code> back in the static value-to-point map - the asker reads its card value while everyone else still sees only a masked point. The contract verifies the inverse scalar against a stored hash so a player can't submit a wrong inverse to corrupt the reveal.</p>
<details class="details_DvdZ"><summary class="summary_rS5Z"><span class="chevron__11n" aria-hidden="true">▸</span><span class="tag_xK_k">Compact</span><span class="title_RZ4p">`partial_decryption`</span><span class="toggle_As0a" aria-hidden="true"></span></summary><div class="body_cu0N"><div class="language-compact codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-compact codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// player_secret_key &amp; getFieldInverse are private witnesses; only their</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// hashes go on-chain.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">witness</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">getFieldInverse</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">x</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Field</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Field</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">witness</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">player_secret_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> player</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Field</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Field</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">partial_decryption</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    point</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> JubjubPoint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    playerId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">64</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> JubjubPoint </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> gid </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gameId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> secret </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">player_secret_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gid</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">playerId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> secret_hash </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">h_hashField</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">secret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Verify this secret was used to mask this game's deck</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        gamePlayersKeysHashes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gid</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">member</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">secret_hash</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token string" style="color:rgb(255, 121, 198)">"Player secret key unknown in this game"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Recompute the multiplicative inverse and verify against the stored hash</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> invScalar </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">getFieldInverse</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">secret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> invScalar_hash </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">h_hashField</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">invScalar</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> expected </span><span class="token operator">=</span><span class="token plain"> gamePlayersKeysInverses</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gid</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">secret_hash</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">invScalar_hash </span><span class="token operator">==</span><span class="token plain"> expected</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Witness failed: Invalid Field inverse"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Peel this player's mask off the point</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">std_ecMul</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">point</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">invScalar</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div></div></details>
<!-- -->
<aside class="wrapper_oRlc" role="complementary"><div class="label_Yi32">◇ Note · Community</div><div class="body_G7uQ"><p class="message_TWsg">Have questions about the techniques in this post? Drop into the Midnight Discord - happy to talk it through.</p><a class="action_cOUd" href="https://discord.com/invite/midnightnetwork" target="_blank" rel="noopener noreferrer">Join Midnight Discord →</a></div></aside>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Safe Solver]]></title>
        <id>https://effectstream.github.io/docs/learn-compact-with-games/safe-solver</id>
        <link href="https://effectstream.github.io/docs/learn-compact-with-games/safe-solver"/>
        <updated>2026-04-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Many small actions per round leaning on an EVM chain for a responsive puzzle feel.]]></summary>
        <content type="html"><![CDATA[
<div class="wrapper_HR5J"><div class="label_u3_I"><span class="labelLeft_ZPD0"><span class="labelTitle_yDoQ">Safe Solver</span><span class="labelDot_sdds">·</span><span class="labelKind_Mixq">Live demonstration</span></span><span class="labelRight_z2F4"><span class="labelStatus_WxIV">● PLAYABLE</span><span class="labelDot_sdds">·</span><span class="labelStatus_WxIV"><time class="date_Olo9" datetime="2026-04-01T00:00:00.000Z">Apr 2026</time></span></span></div><div class="stage_lZPK" style="aspect-ratio:1440 / 1008"><iframe src="https://safesolver.midnight.fun/?game_frame=true" title="Safe Solver game" class="frame_cDyI" style="width:1464px;height:1032px;transform:scale(1)" scrolling="no" allow="fullscreen"></iframe></div><div class="caption_htAG"><span class="captionLeft_k6lD">click frame to play</span><span class="captionRight_jxDn">how it was built ↓</span></div></div>
<aside class="wrapper_dmRO" role="note"><div class="label_jyYz">◇ Note · Multi-chain</div><div class="body_ZO6Y"><p class="message_JrXM">EffectStream is a multi-chain library - you can easily swap the chain or add more wallets: Cardano, EVM chains, Midnight, Bitcoin, and more.</p><a class="action_epi2" href="https://effectstream.github.io/docs/home/chains/">Browse supported chains →</a></div></aside>
<p>Press your luck cracking safes for loot - bank your score before an alarm wipes the round.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="under-the-hood">Under the hood<a href="https://effectstream.github.io/docs/learn-compact-with-games/safe-solver#under-the-hood" class="hash-link" aria-label="Direct link to Under the hood" title="Direct link to Under the hood" translate="no">​</a></h2>
<p><strong>The game.</strong> Safe Solver is a single-player, turn-based press-your-luck puzzle: open safes one at a time, each resolved by seeded RNG, and cash out before you trip an alarm. The client is rendered in <strong>Three.js</strong> (native WebGL canvas).</p>
<p><strong>Chains.</strong> Same split as BlockKart - <strong>Arbitrum</strong> for the game inputs (a <code>PaimaL2Contract</code> with <code>fee = 0</code>) and <strong>Midnight</strong> as a minimal anchor. The EVM choice is swappable; EffectStream handles the sync either way.</p>
<p><strong>Running on EffectStream.</strong> The state machine's grammar is <code>initLevel</code> / <code>checkSafe</code> / <code>submitScore</code>: each <code>checkSafe</code> turn is resolved server-side with seeded RNG, and <code>submitScore</code> banks the run. Because a round is <em>many</em> small actions, keeping per-turn state on the EVM/backend side - not on Midnight - is what keeps it responsive.</p>
<p><strong>Leaderboard &amp; achievements.</strong> Banked scores are ranked on the <code>/metrics/leaderboard</code> endpoint, and Safe Solver awards achievements shown in the Honors panel.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-compact-contract">The Compact contract<a href="https://effectstream.github.io/docs/learn-compact-with-games/safe-solver#the-compact-contract" class="hash-link" aria-label="Direct link to The Compact contract" title="Direct link to The Compact contract" translate="no">​</a></h2>
<a href="https://github.com/effectstream/safe-solver" target="_blank" rel="noopener noreferrer" class="link_MP4t"><span class="glyph_nB_4">&lt;/&gt;</span><span>View source on GitHub</span><span class="arrow_rvyh">→</span></a>
<p><strong>Source:</strong> <a href="https://github.com/effectstream/safe-solver/blob/main/packages/shared/contracts/midnight-contracts/contract-midnight-data/src/midnight-data.compact" target="_blank" rel="noopener noreferrer" class=""><code>packages/shared/contracts/midnight-contracts/contract-midnight-data/src/midnight-data.compact</code></a></p>
<p>Safe Solver uses the exact same minimal Midnight anchor as BlockKart - byte for byte. It's worth seeing the same architectural choice arrive from a different game's constraints.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="same-anchor-pattern-different-reason">Same anchor pattern, different reason<a href="https://effectstream.github.io/docs/learn-compact-with-games/safe-solver#same-anchor-pattern-different-reason" class="hash-link" aria-label="Direct link to Same anchor pattern, different reason" title="Direct link to Same anchor pattern, different reason" translate="no">​</a></h3>
<p>BlockKart needed off-chain speed for racing; Safe Solver needs it for <em>volume</em> - dozens of small actions per round would be prohibitively expensive to prove on Midnight directly. Pushing the per-click state machine onto the EVM side and using Compact only as an anchor is the same design choice for a different reason. When your contract gets this short, ask whether you actually need the rest of Compact's expressiveness or whether the chain is just your notary.</p>
<details class="details_DvdZ"><summary class="summary_rS5Z"><span class="chevron__11n" aria-hidden="true">▸</span><span class="tag_xK_k">Compact</span><span class="title_RZ4p">Full contract (11 lines)</span><span class="toggle_As0a" aria-hidden="true"></span></summary><div class="body_cu0N"><div class="language-compact codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-compact codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token pragma keyword" style="color:rgb(189, 147, 249);font-style:italic">pragma</span><span class="token pragma"> </span><span class="token pragma keyword" style="color:rgb(189, 147, 249);font-style:italic">language_version</span><span class="token pragma"> </span><span class="token pragma operator">&gt;=</span><span class="token pragma"> </span><span class="token pragma number">0.18.0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> CompactStandardLibrary</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">constructor</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">ledger</span><span class="token plain"> payload</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Opaque</span><span class="token operator">&lt;</span><span class="token string" style="color:rgb(255, 121, 198)">"string"</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">storeValue</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">_payload</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Opaque</span><span class="token operator">&lt;</span><span class="token string" style="color:rgb(255, 121, 198)">"string"</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    payload </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">_payload</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div></div></details>
<!-- -->
<aside class="wrapper_oRlc" role="complementary"><div class="label_Yi32">◇ Note · Community</div><div class="body_G7uQ"><p class="message_TWsg">Have questions about the techniques in this post? Drop into the Midnight Discord - happy to talk it through.</p><a class="action_cOUd" href="https://discord.com/invite/midnightnetwork" target="_blank" rel="noopener noreferrer">Join Midnight Discord →</a></div></aside>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[BlockKart]]></title>
        <id>https://effectstream.github.io/docs/learn-compact-with-games/blockkart</id>
        <link href="https://effectstream.github.io/docs/learn-compact-with-games/blockkart"/>
        <updated>2026-03-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Arbitrum plus an effect stream to keep the racing loop snappy, with a global leaderboard.]]></summary>
        <content type="html"><![CDATA[
<div class="wrapper_HR5J"><div class="label_u3_I"><span class="labelLeft_ZPD0"><span class="labelTitle_yDoQ">BlockKart</span><span class="labelDot_sdds">·</span><span class="labelKind_Mixq">Live demonstration</span></span><span class="labelRight_z2F4"><span class="labelStatus_WxIV">● PLAYABLE</span><span class="labelDot_sdds">·</span><span class="labelStatus_WxIV"><time class="date_Olo9" datetime="2026-03-01T00:00:00.000Z">Mar 2026</time></span></span></div><div class="stage_lZPK" style="aspect-ratio:1440 / 1008"><iframe src="https://blockkart.paimastudios.com/?game_frame=true" title="BlockKart game" class="frame_cDyI" style="width:1464px;height:1032px;transform:scale(1)" scrolling="no" allow="fullscreen"></iframe></div><div class="caption_htAG"><span class="captionLeft_k6lD">click frame to play</span><span class="captionRight_jxDn">how it was built ↓</span></div></div>
<aside class="wrapper_dmRO" role="note"><div class="label_jyYz">◇ Note · Multi-chain</div><div class="body_ZO6Y"><p class="message_JrXM">EffectStream is a multi-chain library - you can easily swap the chain or add more wallets: Cardano, EVM chains, Midnight, Bitcoin, and more.</p><a class="action_epi2" href="https://effectstream.github.io/docs/home/chains/">Browse supported chains →</a></div></aside>
<p>A fast-paced racing simulator where you tune a kart, race for the top spot, and climb an on-chain leaderboard.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="under-the-hood">Under the hood<a href="https://effectstream.github.io/docs/learn-compact-with-games/blockkart#under-the-hood" class="hash-link" aria-label="Direct link to Under the hood" title="Direct link to Under the hood" translate="no">​</a></h2>
<p><strong>The game.</strong> BlockKart is a single-player score-attack racer: you submit a car build plus item loadout, and a deterministic race runs against three AI bots. The client renders the race in <strong>Three.js</strong> (native WebGL canvas) with a CRT-style post-processing pass.</p>
<p><strong>Chains.</strong> BlockKart pairs <strong>Arbitrum</strong> with <strong>Midnight</strong>. Game inputs go to an Arbitrum <code>PaimaL2Contract</code> (deployed with <code>fee = 0</code>); the deterministic race simulation runs in the EffectStream node; and Midnight holds a tiny anchor contract. Arbitrum is the chosen EVM today, but the EVM layer is standard <code>PaimaL2Contract</code> - point it at any EVM chain and the rest is unchanged.</p>
<p><strong>Running on EffectStream.</strong> The EffectStream state machine ingests the EVM <code>PaimaGameInteraction</code> events: a <code>play</code> input records the race entry and schedules an <code>executeRace</code> ~10 blocks later, which replays the seeded simulation, records the result, and awards achievements. The batcher has both an EVM adapter and a Midnight adapter; the Midnight side writes the anchor.</p>
<p><strong>Leaderboard &amp; achievements.</strong> Results land in Postgres and are ranked by wins on the <code>/metrics/leaderboard</code> endpoint. BlockKart defines win, loss, and per-surface (dirt/ice/asphalt) achievements, shown in the Honors panel.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-compact-contract">The Compact contract<a href="https://effectstream.github.io/docs/learn-compact-with-games/blockkart#the-compact-contract" class="hash-link" aria-label="Direct link to The Compact contract" title="Direct link to The Compact contract" translate="no">​</a></h2>
<a href="https://github.com/effectstream/block-kart-legends" target="_blank" rel="noopener noreferrer" class="link_MP4t"><span class="glyph_nB_4">&lt;/&gt;</span><span>View source on GitHub</span><span class="arrow_rvyh">→</span></a>
<p><strong>Source:</strong> <a href="https://github.com/effectstream/block-kart-legends/blob/main/packages/shared/contracts/midnight-contracts/contract-midnight-data/src/midnight-data.compact" target="_blank" rel="noopener noreferrer" class=""><code>packages/shared/contracts/midnight-contracts/contract-midnight-data/src/midnight-data.compact</code></a></p>
<p>Here's the teaching moment: the Midnight contract is intentionally tiny. All of the racing logic lives on Arbitrum and in the EffectStream node; Midnight is just an immutable anchor. Not every Compact contract should model the whole game.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-anchor-only-pattern">The "anchor only" pattern<a href="https://effectstream.github.io/docs/learn-compact-with-games/blockkart#the-anchor-only-pattern" class="hash-link" aria-label="Direct link to The &quot;anchor only&quot; pattern" title="Direct link to The &quot;anchor only&quot; pattern" translate="no">​</a></h3>
<p>The entire contract is 11 lines: a single <code>ledger payload: Opaque&lt;"string"&gt;</code> plus a <code>storeValue</code> circuit that <code>disclose</code>s and writes it. No enums, no maps, no witnesses, no commit-reveal. The EffectStream node calls <code>storeValue</code> to notarize game-event data on Midnight. Reach for this pattern when you need tamper-evident anchoring but not zero-knowledge - the cheaper the on-chain piece, the cheaper every update.</p>
<details class="details_DvdZ"><summary class="summary_rS5Z"><span class="chevron__11n" aria-hidden="true">▸</span><span class="tag_xK_k">Compact</span><span class="title_RZ4p">Full contract (11 lines)</span><span class="toggle_As0a" aria-hidden="true"></span></summary><div class="body_cu0N"><div class="language-compact codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-compact codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token pragma keyword" style="color:rgb(189, 147, 249);font-style:italic">pragma</span><span class="token pragma"> </span><span class="token pragma keyword" style="color:rgb(189, 147, 249);font-style:italic">language_version</span><span class="token pragma"> </span><span class="token pragma operator">&gt;=</span><span class="token pragma"> </span><span class="token pragma number">0.18.0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> CompactStandardLibrary</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">constructor</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">ledger</span><span class="token plain"> payload</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Opaque</span><span class="token operator">&lt;</span><span class="token string" style="color:rgb(255, 121, 198)">"string"</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">storeValue</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">_payload</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Opaque</span><span class="token operator">&lt;</span><span class="token string" style="color:rgb(255, 121, 198)">"string"</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    payload </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">_payload</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div></div></details>
<!-- -->
<aside class="wrapper_oRlc" role="complementary"><div class="label_Yi32">◇ Note · Community</div><div class="body_G7uQ"><p class="message_TWsg">Have questions about the techniques in this post? Drop into the Midnight Discord - happy to talk it through.</p><a class="action_cOUd" href="https://discord.com/invite/midnightnetwork" target="_blank" rel="noopener noreferrer">Join Midnight Discord →</a></div></aside>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Dust to Dust]]></title>
        <id>https://effectstream.github.io/docs/learn-compact-with-games/dust-to-dust</id>
        <link href="https://effectstream.github.io/docs/learn-compact-with-games/dust-to-dust"/>
        <updated>2026-02-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Time-based quests, tradeable characters, and witness functions powering a Phaser-driven world.]]></summary>
        <content type="html"><![CDATA[
<div class="wrapper_HR5J"><div class="label_u3_I"><span class="labelLeft_ZPD0"><span class="labelTitle_yDoQ">Dust to Dust</span><span class="labelDot_sdds">·</span><span class="labelKind_Mixq">Live demonstration</span></span><span class="labelRight_z2F4"><span class="labelStatus_WxIV">● PLAYABLE</span><span class="labelDot_sdds">·</span><span class="labelStatus_WxIV"><time class="date_Olo9" datetime="2026-02-01T00:00:00.000Z">Feb 2026</time></span></span></div><div class="stage_lZPK" style="aspect-ratio:1440 / 960"><iframe src="https://dust2dust.midnight.fun/?game_frame=true" title="Dust to Dust game" class="frame_cDyI" style="width:1464px;height:984px;transform:scale(1)" scrolling="no" allow="fullscreen"></iframe></div><div class="caption_htAG"><span class="captionLeft_k6lD">click frame to play</span><span class="captionRight_jxDn">how it was built ↓</span></div></div>
<aside class="wrapper_dmRO" role="note"><div class="label_jyYz">◇ Note · Multi-chain</div><div class="body_ZO6Y"><p class="message_JrXM">EffectStream is a multi-chain library - you can easily swap the chain or add more wallets: Cardano, EVM chains, Midnight, Bitcoin, and more.</p><a class="action_epi2" href="https://effectstream.github.io/docs/home/chains/">Browse supported chains →</a></div></aside>
<p>Battle through dungeons with a deck of tradeable characters in a time-gated roguelike.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="under-the-hood">Under the hood<a href="https://effectstream.github.io/docs/learn-compact-with-games/dust-to-dust#under-the-hood" class="hash-link" aria-label="Direct link to Under the hood" title="Direct link to Under the hood" translate="no">​</a></h2>
<p><strong>The game.</strong> Dust to Dust is a single-player roguelike deckbuilder: register, send characters on timed quests, then fight boss battles with the abilities you've collected and upgraded. The client is built on <strong>Phaser 3</strong>, with a combat scene driven by the contract's resolved state.</p>
<p><strong>Chains.</strong> Like Kachina, Dust to Dust is <strong>Midnight-only</strong>. Quests, abilities, RNG, and progression all live in one Compact contract - no second chain to settle to. The EffectStream foundation keeps that an open choice rather than a hard-coded one.</p>
<p><strong>Running on EffectStream.</strong> An EffectStream state machine mirrors the contract ledger (players, abilities, active quests and battles) into Postgres, surfaced to the client through <code>/game/*</code> REST endpoints. Quest and battle transactions are proved client-side in a WebAssembly worker and submitted through the <strong>batcher</strong>, so moves are <strong>gasless</strong> for players.</p>
<p><strong>Leaderboard &amp; achievements.</strong> Players are ranked by quest points on the <code>/metrics/leaderboard</code> endpoint. Dust to Dust also ships <strong>100+ achievements</strong> - spirit-collection, quest milestones, battle feats, smithing - tracked off-chain by the state machine and shown in the Honors panel.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-compact-contract">The Compact contract<a href="https://effectstream.github.io/docs/learn-compact-with-games/dust-to-dust#the-compact-contract" class="hash-link" aria-label="Direct link to The Compact contract" title="Direct link to The Compact contract" translate="no">​</a></h2>
<a href="https://github.com/effectstream/dust-to-dust" target="_blank" rel="noopener noreferrer" class="link_MP4t"><span class="glyph_nB_4">&lt;/&gt;</span><span>View source on GitHub</span><span class="arrow_rvyh">→</span></a>
<p><strong>Source:</strong> <a href="https://github.com/effectstream/dust-to-dust/blob/main/backend/packages/midnight/contract-game2/src/game2.compact" target="_blank" rel="noopener noreferrer" class=""><code>backend/packages/midnight/contract-game2/src/game2.compact</code></a></p>
<p>The Compact contract is the loot vault and rules engine. Two things make it a good teacher: quests are anchored to real wall-clock time (no client-side speed-running), and the gameplay math is written as circuit-friendly algebra instead of branches, because Compact circuits don't have loops. The contract is actually generated from a <code>template.compact</code> so the combat paths can be unrolled.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="time-anchored-quests-via-blocktimegte--blocktimelte">Time-anchored quests via <code>blockTimeGte</code> / <code>blockTimeLte</code><a href="https://effectstream.github.io/docs/learn-compact-with-games/dust-to-dust#time-anchored-quests-via-blocktimegte--blocktimelte" class="hash-link" aria-label="Direct link to time-anchored-quests-via-blocktimegte--blocktimelte" title="Direct link to time-anchored-quests-via-blocktimegte--blocktimelte" translate="no">​</a></h3>
<p>A quest is started with a claimed <code>start_time</code> that must lie inside a tight 120-second window around chain time. Combined with a level-gating assert against <code>player_boss_progress</code>, this stops clients from speed-running the curve - the quest's duration is enforced by the chain, not the client's clock.</p>
<details class="details_DvdZ"><summary class="summary_rS5Z"><span class="chevron__11n" aria-hidden="true">▸</span><span class="tag_xK_k">Compact</span><span class="title_RZ4p">`start_new_quest`</span><span class="toggle_As0a" aria-hidden="true"></span></summary><div class="body_cu0N"><div class="language-compact codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-compact codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">start_new_quest</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    loadout</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> PlayerLoadout</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    level</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Level</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    start_time</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">64</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Field </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token function" style="color:rgb(80, 250, 123)">verify_loadout</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">loadout</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Anchor "now" to chain time, not the client's clock</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">blockTimeGte</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">start_time</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">           </span><span class="token string" style="color:rgb(255, 121, 198)">"start_time is in the future"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">blockTimeLte</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">start_time</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">+</span><span class="token plain"> </span><span class="token number">120</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">64</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">           </span><span class="token string" style="color:rgb(255, 121, 198)">"start_time is too far in the past"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Higher levels require proof of the previous boss completion</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">level</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">difficulty</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token number">1</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> player_id </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">derive_player_pub_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">player_secret_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> prevLevel </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">level</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">difficulty</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">-</span><span class="token plain"> </span><span class="token number">1</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">            player_boss_progress</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">player_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">member</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">level</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">biome</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">&amp;&amp;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">            player_boss_progress</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">player_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">level</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">biome</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">member</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">prevLevel</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">&amp;&amp;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">            player_boss_progress</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">player_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">level</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">biome</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">prevLevel</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token string" style="color:rgb(255, 121, 198)">"Must complete previous level boss to access this level"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// [build and insert QuestConfig omitted for brevity]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">derive_quest_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">quest</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div></div></details>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="algebra-over-branches-smaller-faster-circuits">Algebra over branches (smaller, faster circuits)<a href="https://effectstream.github.io/docs/learn-compact-with-games/dust-to-dust#algebra-over-branches-smaller-faster-circuits" class="hash-link" aria-label="Direct link to Algebra over branches (smaller, faster circuits)" title="Direct link to Algebra over branches (smaller, faster circuits)" translate="no">​</a></h3>
<p>Compact circuits have no loops and every branch costs constraints, so Dust to Dust writes its gameplay math as pure arithmetic: predicates are cast to <code>Uint&lt;1&gt;</code> (<code>0</code> or <code>1</code>) and multiplied into the expression, so a false condition zeroes its contribution out without an <code>if</code>. The score computation below collapses an entire decision tree into one chained multiplication. (This is also why the contract is code-generated from a template - the per-enemy combat paths get unrolled into flat algebra.)</p>
<details class="details_DvdZ"><summary class="summary_rS5Z"><span class="chevron__11n" aria-hidden="true">▸</span><span class="tag_xK_k">Compact</span><span class="title_RZ4p">`ability_score` + `effect_score`</span><span class="toggle_As0a" aria-hidden="true"></span></summary><div class="body_cu0N"><div class="language-compact codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-compact codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// Ranks how "good" an ability is. Pure circuit - no branches, just math.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> pure </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">ability_score</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ability</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Ability</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token number">3</span><span class="token plain"> </span><span class="token operator">*</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">effect_score</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ability</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">effect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token operator">+</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">effect_score</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ability</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">on_energy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token number">0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token operator">+</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">effect_score</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ability</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">on_energy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token number">1</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token operator">+</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">effect_score</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ability</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">on_energy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token number">2</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">*</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">2</span><span class="token plain"> </span><span class="token operator">+</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ability</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">generate_color</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">is_some </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">1</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">pure </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">effect_score</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">effect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Maybe</span><span class="token operator">&lt;</span><span class="token plain">Effect</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> aoe </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">1</span><span class="token plain"> </span><span class="token operator">+</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">effect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">is_aoe </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">1</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// Attacks score double a non-attack of equal amount.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> attack_compensate </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">1</span><span class="token plain"> </span><span class="token operator">+</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        effect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">effect_type </span><span class="token operator">==</span><span class="token plain"> EFFECT_TYPE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">attack_phys </span><span class="token operator">||</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        effect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">effect_type </span><span class="token operator">==</span><span class="token plain"> EFFECT_TYPE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">attack_ice  </span><span class="token operator">||</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        effect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">effect_type </span><span class="token operator">==</span><span class="token plain"> EFFECT_TYPE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">attack_fire</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">1</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// `effect.is_some as Uint&lt;1&gt;` zeros the whole product out when the</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// optional is empty - no `if (effect.is_some) { ... } else { 0 }` branch.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">effect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">is_some </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">1</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token operator">*</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">effect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">amount </span><span class="token operator">*</span><span class="token plain"> aoe </span><span class="token operator">*</span><span class="token plain"> attack_compensate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div></div></details>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="deterministic-per-player-rng-via-persistenthash">Deterministic per-player RNG via <code>persistentHash</code><a href="https://effectstream.github.io/docs/learn-compact-with-games/dust-to-dust#deterministic-per-player-rng-via-persistenthash" class="hash-link" aria-label="Direct link to deterministic-per-player-rng-via-persistenthash" title="Direct link to deterministic-per-player-rng-via-persistenthash" translate="no">​</a></h3>
<p>Each player keeps a single <code>rng: Bytes&lt;32&gt;</code> cell in their <code>Player</code> ledger entry. Every time a circuit needs randomness, <code>get_player_rng</code> reads the current value, advances it via <code>persistentHash&lt;Bytes&lt;32&gt;&gt;(old_rng)</code>, and writes the new value back. <code>persistentHash</code> is the persistent (SHA-256-based) hash from the standard library - deterministic enough to replay and audit, but only the player can predict the next value.</p>
<details class="details_DvdZ"><summary class="summary_rS5Z"><span class="chevron__11n" aria-hidden="true">▸</span><span class="tag_xK_k">Compact</span><span class="title_RZ4p">`get_player_rng` + initial seed</span><span class="toggle_As0a" aria-hidden="true"></span></summary><div class="body_cu0N"><div class="language-compact codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-compact codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// On registration, seed the RNG from a public hash of (player_id, players.size())</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">register_new_player</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> player_id </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">derive_player_pub_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">player_secret_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> initial_rng </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">persistentHash</span><span class="token operator">&lt;</span><span class="token plain">Field</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">player_id </span><span class="token operator">+</span><span class="token plain"> players</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">size</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    players</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">insert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">player_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Player </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token number">0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> initial_rng </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// [insert starting abilities, etc.]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// Every read advances the RNG via persistentHash and writes back.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">get_player_rng</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> player_id </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">derive_player_pub_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">player_secret_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> old_player </span><span class="token operator">=</span><span class="token plain"> players</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">player_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> new_rng </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">persistentHash</span><span class="token operator">&lt;</span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">old_player</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">rng</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    players</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">insert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">player_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Player </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> old_player</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">gold</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> new_rng </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> old_player</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">rng</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div></div></details>
<!-- -->
<aside class="wrapper_oRlc" role="complementary"><div class="label_Yi32">◇ Note · Community</div><div class="body_G7uQ"><p class="message_TWsg">Have questions about the techniques in this post? Drop into the Midnight Discord - happy to talk it through.</p><a class="action_cOUd" href="https://discord.com/invite/midnightnetwork" target="_blank" rel="noopener noreferrer">Join Midnight Discord →</a></div></aside>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Kachina]]></title>
        <id>https://effectstream.github.io/docs/learn-compact-with-games/kachina</id>
        <link href="https://effectstream.github.io/docs/learn-compact-with-games/kachina"/>
        <updated>2026-01-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Browser-native gameplay with sponsored transactions, commit-reveal moves, and a shared lobby.]]></summary>
        <content type="html"><![CDATA[
<div class="wrapper_HR5J"><div class="label_u3_I"><span class="labelLeft_ZPD0"><span class="labelTitle_yDoQ">Kachina</span><span class="labelDot_sdds">·</span><span class="labelKind_Mixq">Live demonstration</span></span><span class="labelRight_z2F4"><span class="labelStatus_WxIV">● PLAYABLE</span><span class="labelDot_sdds">·</span><span class="labelStatus_WxIV"><time class="date_Olo9" datetime="2026-01-01T00:00:00.000Z">Jan 2026</time></span></span></div><div class="stage_lZPK" style="aspect-ratio:1440 / 1080"><iframe src="https://kachina.midnight.fun/?game_frame=true" title="Kachina game" class="frame_cDyI" style="width:1464px;height:1104px;transform:scale(1)" scrolling="no" allow="fullscreen"></iframe></div><div class="caption_htAG"><span class="captionLeft_k6lD">click frame to play</span><span class="captionRight_jxDn">how it was built ↓</span></div></div>
<aside class="wrapper_dmRO" role="note"><div class="label_jyYz">◇ Note · Multi-chain</div><div class="body_ZO6Y"><p class="message_JrXM">EffectStream is a multi-chain library - you can easily swap the chain or add more wallets: Cardano, EVM chains, Midnight, Bitcoin, and more.</p><a class="action_epi2" href="https://effectstream.github.io/docs/home/chains/">Browse supported chains →</a></div></aside>
<p>Build a team of gladiators and fight 3v3, head-to-head, in a tactical browser battleground.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="under-the-hood">Under the hood<a href="https://effectstream.github.io/docs/learn-compact-with-games/kachina#under-the-hood" class="hash-link" aria-label="Direct link to Under the hood" title="Direct link to Under the hood" translate="no">​</a></h2>
<p><strong>The game.</strong> Kachina is a turn-based PvP arena: you draft three heroes, equip them, pick a stance each round, and trade blows until one side falls. The client is built on <strong>Phaser 3</strong>, with a thin TypeScript API layer bridging the game scenes and the on-chain contract.</p>
<p><strong>Chains.</strong> Kachina runs entirely on <strong>Midnight</strong> - there's no second chain. The lobby, matchmaking, every move, and the win/loss result all live in one Compact contract. Because it's built on EffectStream, swapping or adding a settlement chain later is a config change, not a rewrite.</p>
<p><strong>Running on EffectStream.</strong> An EffectStream state machine subscribes to the Midnight indexer, reads the contract's public ledger each block, and mirrors it into Postgres so the frontend can poll game state over REST. Player moves never touch a wallet pop-up for gas: the move is handed to a <strong>batcher</strong> that generates the ZK proof, balances the transaction with dust, and submits it - so <strong>players pay zero fees</strong>. Proving happens client-side in a WebAssembly Web Worker, so nobody installs a proof server.</p>
<p><strong>Leaderboard.</strong> Wins are tallied from finalized matches into a ranked leaderboard exposed at a <code>/metrics/leaderboard</code> endpoint (the Standings panel on the right). Kachina has no achievements - the ladder is the whole progression story.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-compact-contract">The Compact contract<a href="https://effectstream.github.io/docs/learn-compact-with-games/kachina#the-compact-contract" class="hash-link" aria-label="Direct link to The Compact contract" title="Direct link to The Compact contract" translate="no">​</a></h2>
<a href="https://github.com/effectstream/kachina-colosseum" target="_blank" rel="noopener noreferrer" class="link_MP4t"><span class="glyph_nB_4">&lt;/&gt;</span><span>View source on GitHub</span><span class="arrow_rvyh">→</span></a>
<p><strong>Source:</strong> <a href="https://github.com/effectstream/kachina-colosseum/blob/main/backend/packages/midnight/contract-pvp/src/pvp.compact" target="_blank" rel="noopener noreferrer" class=""><code>backend/packages/midnight/contract-pvp/src/pvp.compact</code></a></p>
<p>The Compact contract is the referee. It runs the match as a state machine, anchors every action to a witness-derived player secret, gates moves on block time, and - crucially - locks moves behind a commit-reveal hash so neither player can react to what the other hasn't shown yet.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="commit-reveal-via-transienthash">Commit-reveal via <code>transientHash</code><a href="https://effectstream.github.io/docs/learn-compact-with-games/kachina#commit-reveal-via-transienthash" class="hash-link" aria-label="Direct link to commit-reveal-via-transienthash" title="Direct link to commit-reveal-via-transienthash" translate="no">​</a></h3>
<p>P1's move stays in private witnesses; only <code>transientHash&lt;MoveHasher&gt;(secret, commands, stances, nonce)</code> is written to public state. P2 then commits in the clear, and P1 reveals - the contract recomputes the same hash from the now-disclosed values and rejects the reveal unless it matches. <code>transientHash</code> is the circuit-efficient hash from the Compact standard library; the nonce is what makes two identical move sequences produce different commitments.</p>
<details class="details_DvdZ"><summary class="summary_rS5Z"><span class="chevron__11n" aria-hidden="true">▸</span><span class="tag_xK_k">Compact</span><span class="title_RZ4p">Commit step + reveal verification</span><span class="toggle_As0a" aria-hidden="true"></span></summary><div class="body_cu0N"><div class="language-compact codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-compact codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// In p1_commit_commands - P1's move is committed as a hash:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">p1_commit</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">insert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">match_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> transientHash</span><span class="token operator">&lt;</span><span class="token plain">MoveHasher</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">MoveHasher </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">player_secret_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">player_commands</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">player_stances</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">nonce</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">commit_nonce</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">insert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">match_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">nonce</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">game_state</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">insert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">match_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> GAME_STATE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">p2_commit_reveal</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// In p1_reveal_commands - the reveal must recompute the same hash:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">transientHash</span><span class="token operator">&lt;</span><span class="token plain">MoveHasher</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">MoveHasher </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">player_secret_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">player_commands</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">player_stances</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    commit_nonce</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">match_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">==</span><span class="token plain"> p1_commit</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">match_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Commit doesn't match"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><br></div></code></pre></div></div></div></details>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="witness-derived-player-identity">Witness-derived player identity<a href="https://effectstream.github.io/docs/learn-compact-with-games/kachina#witness-derived-player-identity" class="hash-link" aria-label="Direct link to Witness-derived player identity" title="Direct link to Witness-derived player identity" translate="no">​</a></h3>
<p>Identity in Kachina is never a wallet pubkey. It's <code>transientCommit(player_secret_key(), salt)</code> - a commitment the contract can verify but the network can't unwind. Every authorized action calls <code>derive_public_key</code> against the caller's witness and asserts equality with the stored value; an attacker who learns the on-chain commitment still needs the secret to produce a matching one.</p>
<details class="details_DvdZ"><summary class="summary_rS5Z"><span class="chevron__11n" aria-hidden="true">▸</span><span class="tag_xK_k">Compact</span><span class="title_RZ4p">`derive_public_key` + authorization assert</span><span class="toggle_As0a" aria-hidden="true"></span></summary><div class="body_cu0N"><div class="language-compact codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-compact codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">witness</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">player_secret_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> pure </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">derive_public_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">sk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Field </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> transientCommit</span><span class="token operator">&lt;</span><span class="token class-name">Bytes</span><span class="token operator">&lt;</span><span class="token number">32</span><span class="token operator">&gt;&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">sk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">123456789</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// On every authorized action:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    p1_public_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">match_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">==</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">derive_public_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">player_secret_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token string" style="color:rgb(255, 121, 198)">"Not authorized as P1"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><br></div></code></pre></div></div></div></details>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="block-time-gating--turn-timeout">Block-time gating + turn timeout<a href="https://effectstream.github.io/docs/learn-compact-with-games/kachina#block-time-gating--turn-timeout" class="hash-link" aria-label="Direct link to Block-time gating + turn timeout" title="Direct link to Block-time gating + turn timeout" translate="no">​</a></h3>
<p>Every action carries a claimed <code>now</code> parameter and asserts it lies inside a tight window around the actual chain time using <code>blockTimeGte</code> / <code>blockTimeLte</code>. The same primitives power <code>claim_timeout_win</code>: if the opponent has been silent for longer than <code>TURN_TIMEOUT</code>, the active player can prove the wait against chain time and end the match.</p>
<details class="details_DvdZ"><summary class="summary_rS5Z"><span class="chevron__11n" aria-hidden="true">▸</span><span class="tag_xK_k">Compact</span><span class="title_RZ4p">`blockTimeGte` / `blockTimeLte` + timeout win</span><span class="toggle_As0a" aria-hidden="true"></span></summary><div class="body_cu0N"><div class="language-compact codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-compact codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// 5-minute per-turn timeout, in seconds (blockTimeGte uses secondsSinceEpoch)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">ledger</span><span class="token plain"> TURN_TIMEOUT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">64</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// 2-block grace for clock drift between prover and chain</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">ledger</span><span class="token plain"> BLOCK_TIME</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">64</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// On every action - "now" must fall inside the chain-time window:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">blockTimeGte</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">now </span><span class="token operator">-</span><span class="token plain"> BLOCK_TIME</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">       </span><span class="token string" style="color:rgb(255, 121, 198)">"Claimed timestamp is in the future"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">blockTimeLte</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">now </span><span class="token operator">+</span><span class="token plain"> TIMESTAMP_MAX_AGE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">64</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">       </span><span class="token string" style="color:rgb(255, 121, 198)">"Timestamp is too old"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// claim_timeout_win - end the match if the opponent times out:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">circuit</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">claim_timeout_win</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> match_id </span><span class="token operator">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token function" style="color:rgb(80, 250, 123)">current_match_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> last_move_at_timestamp </span><span class="token operator">=</span><span class="token plain"> last_move_at</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">lookup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">match_id</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">64</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// [state/auth checks omitted for brevity]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">assert</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token function" style="color:rgb(80, 250, 123)">blockTimeGte</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token builtin" style="color:rgb(189, 147, 249)">disclose</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">last_move_at_timestamp </span><span class="token operator">+</span><span class="token plain"> TURN_TIMEOUT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> </span><span class="token class-name">Uint</span><span class="token operator">&lt;</span><span class="token number">64</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token string" style="color:rgb(255, 121, 198)">"Opponent has not timed out yet"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)">// ... assigns the win to whichever player is the active one</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div></div></details>
<!-- -->
<aside class="wrapper_oRlc" role="complementary"><div class="label_Yi32">◇ Note · Community</div><div class="body_G7uQ"><p class="message_TWsg">Have questions about the techniques in this post? Drop into the Midnight Discord - happy to talk it through.</p><a class="action_cOUd" href="https://discord.com/invite/midnightnetwork" target="_blank" rel="noopener noreferrer">Join Midnight Discord →</a></div></aside>]]></content>
    </entry>
</feed>