• Stars
    star
    165
  • Rank 228,906 (Top 5 %)
  • Language
    TypeScript
  • License
    Other
  • Created about 6 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A Mastermind game using zk-snarks

A Mastermind game with zk-SNARKs

NOTE: this project is several years old and uses highly outdated libraries. Furthermore, the circuit code was written as a beginner to circom and may contain mistakes, which if repeated in other projects, may lead to security flaws. Please proceed with discretion.

This is an implementation of the Mastermind board game which uses zk-SNARKs instead of a trusted third party to enforce game rules.

It uses the snarkjs and circom JavaScript libraries from iden3.

Image source

About zk-SNARKS

zk-SNARKs allow you to cryptographically prove knowledge of some secret data without revealing said data. For a simple explanation of zk-SNARKs, read this blog post by Christian Lundkvist.

The rules of Mastermind

There are two players: the codebreaker and the codemaster.

The codemaster creates a secret four-digit sequence of coloured pegs, limited to red, blue, green, and yellow.

To win, the codebreaker must guess the secret sequence of pegs within a set number of attempts. After each guess, if the codebreaker does not yet have the correct solution, the codemaster must tell the codebreaker the following clue:

  1. How many exact matches of colour and position there are β€” these are are black pegs

  2. How many pegs have matching colours, but are in the wrong position β€” these are white pegs.

For example, if the solution is R R B Y, and the guess is Y R B G, the codemaster must provide this clue: 2 black pegs and 1 white peg.

Solution       : Y R B G
Guess          : R R B Y

Exact matches  : 0 1 1 0 -> 2 black pegs
Inexact matches: 0 0 0 1 -> 1 white peg

Inexact matches do not overlap; for instance:

Solution       : R R Y B
Guess          : G G R B

Exact matches  : 0 0 0 1 -> 1 black peg
Inexact matches: 0 0 1 0 -> 1 white peg (not two, even though there are two red 
                                         pegs in the solution)

An illustrated example:

Image source

The protocol

1. Prepare the circuit

Create an arithmetic circuit C which is essentially this function:

C (pubGuess, pubClue, pubSolutionHash, privSolution):
    hash(privSolution) === pubSolutionHash
    genClue(pubGuess, privSolution) === pubClue

That is, given the secret sequence privSolution, the guess pubGuess, the clue pubClue, and a cryptographic hash of the secret sequence, the circuit:

a) calculates the correct clue and the cryptographic hash of the secret sequence, and

b) declares two constraints: that the cryptographic hash is correct and that the clue is correct.

In a later step, the codebreaker can cryptographically verify that (a) and/or (b) does not hold; more on that later.

2. Trusted setup

Generate the proving key, verifiying key, and toxic waste. Discard the toxic waste. Make the proving key and verifying key public. For simplicity, we assume that whoever did so can be trusted.

3. Generate a random salt

Using a commit-reveal scheme, the codemaster and codebreaker should arrive at a random salt. This is not part of the zk-SNARK, but helps to prevent a rainbow attack on the solution by the codebreaker.

4. Start the game

Before each game, the codemaster should generate the following:

a) the secret solution to the puzzle β€” e.g. G R Y B

b) the SHA256 hash of the solution and the salt

The codemaster should then send the hash to the codebreaker.

5. Make a guess

For each turn, the codebreaker should send their guess to the codemaster, who should then generate the following:

a) the clue which corresponds to the secret solution and the guess;

b) a proof that the clue is correct, which is the result of computing:

proof = Prover(provingKey, pubGuess, pubClue, pubSolutionHash, privSolution)

The codemaster must then send the clue and the proof back to the codemaster, who can verify that the clue is valid by computing:

Verify(verifyingKey, pubGuess, pubClue, pubSolutionHash, proof)

6. Repeat

Perform step 5 until the codebreaker guesses the correct solution. Note that this implementation of Mastermind lets you make as many guesses as you want, and even after you reach the correct solution.

Running the game

You need the TypeScript compiler tsc v2.7.2 or higher, and Node v10 or higher.

You may use yarn or npm as your package manager, but the following instructions will use yarn.

Setting up the circuit

1. Install dependencies

cd mastermind && \
yarn install && \
tsc

2. Compile the circuit

node build/mastermind/src/compile.js \
  -i mastermind/circuits/mastermind.circom \
  -o mastermind/circuits/mastermind.json -r

3. Perform the trusted setup

This takes about 30 seconds if you use Node 10 or greater. Note that it will take about ten times longer to complete if you use Node 9, as Node 10 has more optimised BigInt support.

mkdir -p mastermind/setup && \
node build/mastermind/src/trustedsetup.js \
  -i mastermind/circuits/mastermind.json \
  -pk mastermind/setup/mastermind.pk.json \
  -vk mastermind/setup/mastermind.vk.json -r

4. Generate a sample proof and public signals in JS

Generate the proof and public signals for a sample input:

mkdir -p mastermind/proofs mastermind/signals && \
node build/mastermind/src/generateproof.js \
  -c mastermind/circuits/mastermind.json \
  -vk mastermind/setup/mastermind.vk.json \
  -pk mastermind/setup/mastermind.pk.json \
  -po mastermind/proofs/mastermind.proof.json \
  -so mastermind/signals/testsignals.json

5. Verify a sample proof in JS

To verify it, run:

node build/mastermind/src/test_js_verification.js \
  -c mastermind/circuits/mastermind.json \
  -vk mastermind/setup/mastermind.vk.json \
  -p mastermind/proofs/mastermind.proof.json \
  -s mastermind/signals/testsignals.json

Run the Mastermind game in your browser

First, build the frontend

cd frontend && \
yarn install && \
yarn build:prod

You may also run the frontend development server using yarn dev.

In a different terminal, set up virtualenv:

cd backend && \
virtualenv -p python3 venv && \
source venv/bin/activate && \
pip3 install -r requirements.txt

Next, run the backend server in a separate terminal. Note that you have to set the NODE_PATH environment variable to a Node binary of version 10 or above.

export NODE_PATH='/path/to/node/10+' 
cd zkmm/backend && \
source venv/bin/activate && \
python3 manage.py migrate && \
python3 manage.py collectstatic -c --noinput && \
python3 manage.py runserver

Launch http://localhost:9000 for the development frontend environment, or http://localhost:8000 for the production frontend environment.

Make a guess and click on the Verify button to have the backend generate a proof, so that the frontend can verify the clue in the browser:

The proof takes about 18 seconds generate on an Intel i5 processor, and about 1 second to verify in the browser.

Bonus: verify a sample proof in Solidity

Generate the Solidity code of the verifier, and deploy it to a Ethereum network, like Ropsten.

If you wish to deploy it yourself, you can use Remix. Avoid using the Javascript VM to execute the verifyProof function as your browser may freeze up. Instead, get some Ropsten ether, deploy your contract to the testnet, and use that to verify the proof.

Alternatively, you can connect to a working verifier contract on Ropsten here.

mkdir -p mastermind/contracts && \
node build/mastermind/src/generateverifier.js \
  -i mastermind/setup/mastermind.vk.json \
  -o mastermind/contracts/mastermindverifier.sol -r

Next, generate the contract call parameters and paste the output into Remix:

node build/mastermind/src/generatecall.js \
  -p mastermind/proofs/mastermind.proof.json \
  -s mastermind/signals/testsignals.json

Example output:

["0x204fbb7755e152c2368ad1df3bb8f5cfa95f39adc6222f42ab138e70b92850af", "0x01aef8e7b8a5c1205abf51c7c91bef1eaba5b1046c61d761c7a03d316dc0185d"],[["0x24c698c2dd423d7df4455dee12783e51ecd281cb82139c9439311b015af50189", "0x19e0cac361ebd59dbf365492e823c7c02022774a9882282e00b5df912d291a02"],["0x023219cbe60a4d8bac7068e92a05486ec877608c4eb7897273863bf32c2ad2cf", "0x022ed9097142b1009e021cef3afd7778eec3a0aa65f74cdd21830283c44ada2c"]],["0x2dc657c7ee0f4c325dfb24562733d355d9bb4d01010967544467fe44eef8e8f9", "0x2d5b9b3bcefa2e0d31de45202a29355ef70994ec911d443cf804823a4dd09177"],["0x16425edee78f5b01f5e18b132ce10936bd2e08d222c6f298ed121d498689915b","0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x16425edee78f5b01f5e18b132ce10936bd2e08d222c6f298ed121d498689915b"]

Click the verifyProof button to execute the function.

More Repositories

1

perpetualpowersoftau

New repo: https://github.com/privacy-scaling-explorations/perpetualpowersoftau
Standard ML
124
star
2

mixer

MicroMix: A noncustodial Ethereum mixer
TypeScript
83
star
3

libkzg

A minimal KZG polynominal commitment library with a Solidity verifier
TypeScript
49
star
4

zknftmint

Solidity
43
star
5

circom-helper

A convenient way for developers to compile, cache, and execute circom circuits, as well as to generate proofs.
TypeScript
31
star
6

eip712-signing-demo

Demonstrates MetaMask's eip_signTypedData_v3 feature
JavaScript
20
star
7

elgamal-babyjub

TypeScript
19
star
8

oneofus

TypeScript
18
star
9

malvarma

Secure Monero cold wallets for the truly paranoid ❄❄❄
Python
16
star
10

semaphore-merkle-tree

A fork of zkp-sbmtjs
TypeScript
13
star
11

poseidon-encryption-circom

Poseidon encryption in Typescript and circom (decryption only) on the BN254 elliptic curve
TypeScript
10
star
12

semaphore-ui

A simple user interface for Semaphore, a zero-knowledge signalling gadget
TypeScript
8
star
13

py2-monero-wallet-generator

A Monero wallet generator written in pure Python 2
Python
8
star
14

tracing_the_kucoin_hacker

Jupyter Notebook
7
star
15

caishen

Frontend and contract code for smart red packets on the Ethereum blockchain
CSS
6
star
16

libsemaphore

A Semaphore and MicroMix client library
TypeScript
6
star
17

snarsma-mvp

Submission for ETH Singapore 2018
JavaScript
5
star
18

snarschain

TypeScript
5
star
19

halo2_circuits

Rust
4
star
20

circom_zkutil

4
star
21

coinstats

A web app to browse cryptocurrency market statistics
JavaScript
3
star
22

snarkjs-plonk-benchmarks

Shell
3
star
23

circom_test

TypeScript
2
star
24

eip-typed-data-translation

HTML
2
star
25

ssh-resumable-upload

A Docker container which helps to set up a rrsync-only Dropbear server
Dockerfile
1
star
26

UnsafeMaths

A gas-optimised arithmetic library for Ethereum
TypeScript
1
star
27

complexactioncomposer

JavaScript
1
star
28

snarkjs_plonk_in_browser

HTML
1
star
29

circom_sha256

1
star
30

poseidon_benchmarks

TypeScript
1
star
31

hireme

An Ethereum smart contract to hold an auction
JavaScript
1
star
32

noir_hello

Solidity
1
star
33

wgsl-experiments

WGSL
1
star