# Journey to my first ZK game

By [botdad](https://paragraph.com/@botdad) · 2022-03-30

---

I’ve had a passing interest in zero knowledge proofs for a long time, when I first heard of them they felt more like magic than cryptography. I learn best with a project but I hadn’t had any practical need to implement anything with zero knowledge proofs until:

![The ZKP Nerd Snipe](https://storage.googleapis.com/papyrus_images/69000b4508b299051bfe4c44d5c8f0c51ba4e8fe0e73d3a1f50591ecae59a44f.png)

The ZKP Nerd Snipe

So I wanted to build a Rock Paper Scissors game for [Arbibots](https://arbibots.xyz) owners but I had no idea how to 1) do it on chain 2) hide the moves from other players and 3) ensure that players submit a valid move.

I got a bit stuck here, tweeted this out. 0 = Rock, 1 = paper, 2 = scissors.

[https://twitter.com/0xB07DAD/status/1483935652500553731](https://twitter.com/0xB07DAD/status/1483935652500553731)

I wasn’t yet familiar with some of the ZKP commit/reveal mechanism so the replies were a nudge in the right direction but I still couldn’t quite figure it out. I started researching more building blocks, reading and understanding the [tornado cash](https://github.com/tornadocash/tornado-core) codebase and circuits, [circom docs](https://docs.circom.io/), [dark forest circuits](https://github.com/darkforest-eth/circuits), [circom-ecdsa](https://github.com/0xPARC/circom-ecdsa), and the [iden3 circom libs](https://github.com/iden3/circomlib).

I started dreaming up some ideas of things to work on from here:

[https://twitter.com/0xB07DAD/status/1489323754773573633?s=20&t=vNu55l\_j46h1p8mV3XwwhA](https://twitter.com/0xB07DAD/status/1489323754773573633?s=20&t=vNu55l_j46h1p8mV3XwwhA)

[https://twitter.com/0xB07DAD/status/1493336351453765638?s=20&t=vNu55l\_j46h1p8mV3XwwhA](https://twitter.com/0xB07DAD/status/1493336351453765638?s=20&t=vNu55l_j46h1p8mV3XwwhA)

Started to gain some confidence around this whole stack, researching more projects and paying attention to [@0xPARC](https://twitter.com/0xPARC) which lead to disclosing a flaw in one of their projects.

[https://twitter.com/0xPARC/status/1493704577002049537](https://twitter.com/0xPARC/status/1493704577002049537)

But I still couldn’t figure out how to make RPS work. I let it simmer in the back of my mind for a few weeks and then it clicked.

[https://twitter.com/0xB07DAD/status/1499247835908243456?s=20&t=vNu55l\_j46h1p8mV3XwwhA](https://twitter.com/0xB07DAD/status/1499247835908243456?s=20&t=vNu55l_j46h1p8mV3XwwhA)

Commit reveal scheme with user provided secret. Verifying the move with the following:

      signal temp;
      temp <== (move - 1) * (move - 2);
      0 === temp * move; // ensure that the move is 0, 1, or 2
    

The steps of the game is the following

*   Player 1 commits their valid move with a secret
    
*   Player 2 plays their move in the clear
    
*   Player 1 reveals their move by providing the same secret
    

I did not want Player 1 to have to save their secret, but with my stealthdrop flaw investigation I knew that even though a ECDSA signature is not unique, it is idempotent when generated by a wallet. If I provided the same message to sign to the wallet during both steps I could get the same secret out!

Now what if player 1 forgot their move? How about we brute force it inside a circuit???

      // brute force all possible moves
      for(var move = 0; move < totalMoves; move++){
        mimcAttestation[move] = MiMCSponge(2, 220, 1);
        isEqual[move] = IsEqual();
    
        mimcAttestation[move].ins[0] <== move;
        mimcAttestation[move].ins[1] <== secret;
        mimcAttestation[move].k <== 0;
    
        isEqual[move].in[0] <== moveAttestation;
        isEqual[move].in[1] <== mimcAttestation[move].outs[0];
    
        // 0 * move when not equal -- 1 * move when equal
        calcTotal.in[move] <== isEqual[move].out * move;
        // should add up to 1 since only 1 move will be equal
        calcTotalVerify.in[move] <== isEqual[move].out;
      }
    
      // make sure we found one and only one match
      1 === calcTotalVerify.out;
      
      foundMove <== calcTotal.out;
    

All three of my requirements for the game: ✅

I wrapped it all up, threw in some solidity and an interface, added some betting (and if player 1 is a jerk and decides to not reveal they lose their bet after a deadline. jerk)

code is here, launch to the Arbibots community soon.

[https://github.com/botdad/arbirps/](https://github.com/botdad/arbirps/)

I’ve been taking part in @0xPARC’s ZK learning group #2 and am feeling pretty good about my skills with this stack. On to the next bigger ZK project!

---

*Originally published on [botdad](https://paragraph.com/@botdad/journey-to-my-first-zk-game)*
