---
# System prepended metadata

title: 'ZK Frontiers: Week 3 Exercises'

---

# ZK Frontiers: Week 3 Exercises

For this week's exercise, you will write a spec for one of the following proposed applications.

If you are working on a project, you're automatically "exempt," as you'll already be building one of these!

In your spec, you should:
 - Outline precisely the ZK circuit(s) you'll be using. You can use [our template from class](https://docs.google.com/presentation/d/1MFbU1gOB228Kn7LkwxuqWt6BwCcrIGILRKb7yRMwtoQ/edit#slide=id.g24f2a51b284_0_806) if you'd like.
 - Describe the business logic of the major components of the application: the server (what it stores, what it verifies, etc.) smart contracts (if applicable), clients (what they store, what they prove, etc.), and any additional services (for example, an auxiliary server that stores, verifies, and serves Merkle groups).

## WhaleChat

Build an anonymous message board, without persistent identities, that only ETH whales--anyone with knowledge of a private key corresponding to an Ethereum account with at least 1000 ETH as of the time of posting--can post to.

### Extension: Integrate into Zupass and Zuca.st

Add an "ETH Whale badge" feature to Zuca.st. Anyone who is an ETH Whale can add a "Whale" badge to their profile, which would be displayed alongside all of their messages. The flow might look something like:

 - Add an [eth-pcd](https://eth-pcd.vercel.app/) your Zupass, for an account you control with at least 1000 ETH.
 - Add a button to zuca.st that requests a proof that you hold a Semaphore keypair and a linked ETH PCD in your Zupass, such that the ETH account is in a Merkle tree of accounts with at least 1000 ETH.
 - On verification of this proof, the zuca.st server will display a badge alongside your user ID in future posts.

## ZK Battleship

Design a peer-to-peer simplified Battleship game where the two players can't lie about the position of their ships, once they've committed to their positions. (To simplify this, you can also imagine that you're building this in a traditional client-server architecture, but the server just serves as an untrusted store of data).

 - Both players should initially commit to a 5 by 5 board with two ships: a ship of length 2 (i.e. a contiguous 2x1 or 1x2 rectangle), and a ship of length 3 (i.e. a contiguous 3x1 or 1x3 rectangle).
 - Players take turns, alternating making coordinate pair guesses.
 - Each time your opponent makes a guess, you must respond with a proof that their guess did or did not hit one of your ships.
 - The first player to sink both of their opponent's ships wins.

## ZK Twitter Import

Build an anonymous message board, without persistent identities, that only Twitter influencers--anyone with at least 100,000 Twitter followers--can post to.

### Extension: Integrate into Zupass and Zuca.st

Add a "Twitterati badge" feature to Zuca.st. Anyone who is has a Twitter following of at least 100K can add a "Twitterati" badge to their profile, which would be displayed alongside all of their messages. The flow might look something like:

 - Add an RSA-signed Twitter password reset email your Zupass.
 - Add a button to zuca.st that requests a proof that you hold a specific Semaphore keypair, and that you have a password reset email signed by Twitter, such that the account in that email is in a pre-generated Merkle tree of Twitter handles with at least 100K followers.
 - On verification of this proof, the zuca.st server will display a badge alongside your user ID in future posts.

## ZK NFTs

This project idea is to build a system of NFTs with default private ownership. They do not need to be ERC721-compliant.

zkNFTs come in two types:

 - shielded: ownership is not known. Instead, a commitment is stored on-chain that is the hash of a "UTXOs": `ownerAddress | nftID | salt`
 - unshielded: ownership is known. 

Define the state variables of a hypothetical ZK NFT contract, as well as pseudocode for how each of the following functions would work:

`mint(id, address)`:
 - purpose: mints an unshielded NFT with public ID `id` and public owner `address`

`shield(address, id, utxoHash, proof)`:
 - purpose: turns an unshielded NFT into a shielded NFT

`unshield(address, id, salt, merkleIdx)`:
 - purpose: reveals that `address` owns NFT with id `id`, turning it into an unshielded NFT

`transferShielded(nullifier, newUtxoHash, proof)`:
 - purpose: transfers ownership of a shielded NFT

`transferUnshielded(nullifier, newUtxoHash, proof)`:
 - purpose: transfers ownership of a shielded NFT