Skip to content

45930/cachebox

Repository files navigation

Cachebox

Cachebox is a zk-app escape game built on the MINA blockchain. Hosted at zk-cachebox.herokuapp.com.

Local Dev

Running this app locally required node version 16+

local server pnpm dev

build pnpm build

production server pnpm start

Dotenv

A value must be set for these environment variables for the smart contracts to work

VITE_GATE_KEY=12345
VITE_LAB_KEY=12345
VITE_UNLABELED_PW=example
VITE_SESSION_KEY=32_CHAR_VALUE # used to encrypt session cookie

Web 2 Components

The web app is built with svelte-kit. In general, the app is kept entirely client-side with SSR and pre-fetch disabled so that the behavior of snarkyjs, the smart contract language, is more predictable. There is one endpoint, gameState.ts which handles a game state cookie. The other routes are an /about page, and the game routes nested under /play.

Stores

We use 3 stores to power the game. A store in svelte is similar to redux; it allows many components to share state. The first store is locationStore, which is simply a list of game locations, and some behavior configurations. The other 2 stores are related to snarkyjs, the smart contract programming language. One boolean store, snarkyStore, is set to true when the code has all been loaded and is ready to use. The other store deployedSnappStore handles details about smart contracts that have already been deployed like their address and interface.

Routing

Each locaiton in the location store represents a route under the /play directory. Any loction not explicitly handled by a route will fall back to the [tile-id] route. Most of the navigation options in the pages are determined by the locationStore.

Session

The session cookie has this shape

interface SessionData {
  user: string;
  tile: string;
  hasVisitedClearing: boolean;
  hasVisitedLab: boolean;
  gateProof: KeyProof;
  labProof: KeyProof;
  unlabeledRoomProof: KeyProof;
}

Tile is a location in the game, so that a user who leaves and comes back will return to where they left off. The hasVisited values are used to unlock behavior. The proof values are zero knowledge proofs that a user can use to assert completion of various puzzles in the game.

Headers

For snarky JS to work, these headers must be set.

'Cross-Origin-Embedder-Policy' => 'require-corp'
'Cross-Origin-Opener-Policy' => 'same-origin'

Svelte hooks should always set the headers correctly, but by changing config, especially SSR or prefetching, it is possible to bypass the hooks and miss the headers.

Mina Components

This project was built as part of the Mina ZK-App builders program. Mina is a zero knowledge focused blockchain which supports smart contracts written in javascript. At time of writing/building, there is not a public testnet, and some features are still missing from the sdk. For instance, the proofs that are generated by the game can't actually be verified. With that caveat, the following is how the Mina section of this app is organized.

Smart contract

There are a few smart contracts located in src/lib/snapps/not_used which the game does not use. The Monty Hall one is the most interesting of those. The one smart contract that is being used is src/lib/snapps/escapeGameSnapp.ts.

State

The smart contract stores the ciphertext of three encrypted values on chain. The ciphertext is split into two Fields per value. A Field is a zero-knowledge compatible data type for use in snarky js.

Note, this app does not use any typescript @decorators because they were not working well with snarkyjs on my production build. It is common to see decorators used to better illustrate what state and methods exist on a smart contract.

class EscapeGameSnapp extends SmartContract {
  constructor(address: PublicKey) {
    super(address);
    this.gateKeyCT1 = State();
    this.gateKeyCT2 = State();
    this.labKeyCT1 = State();
    this.labKeyCT2 = State();
    this.unlabeledPwCT1 = State();
    this.unlabeledPwCT2 = State();

  }
  ...
}

Interface

interface EscapeGameSnappInterface {
  address: PublicKey;
  guessGateKey(key: string): Promise<KeyProof> | Promise<null>;
  guessUnlabeledPw(key: string): Promise<KeyProof> | Promise<null>;
  guessLabKey(key: string): Promise<KeyProof> | Promise<null>;
}

Proof System

The proof system in src/lib/snarkyUtils/keyProof.ts allows for proofs of knowledge to be made and combined. Since we have 3 encrypted values, there are 3 puzzles we can prove knowledge of. We can consider that a proof of any one puzzle might look like a boolean array of false with one true value at the index of the known puzzle. Or we can combine those arrays with a bitwise or to mean that multiple puzzles have been solved.


// First puzzle solved
[ 1, 0, 0]

// Second puzzle solved
[0, 1, 0]

// First and second puzzle solved
[1, 1, 0]

About

Cachebox is a game based on Mina snapps

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published