DEV Community

Cover image for Creating zk dApp Sudoku Proof
kOrriO
kOrriO

Posted on

Creating zk dApp Sudoku Proof

To begin, we need to install the required dependencies. Make sure you have Node.js and npm installed before proceeding.

First, let's install Circom:

npm install -g circom
Enter fullscreen mode Exit fullscreen mode

Next, we'll generate the circuit file for our Sudoku game proof:

circom create sudoku.circom
Enter fullscreen mode Exit fullscreen mode

Open the sudoku.circom file in your preferred editor and write the following code:

template Sudoku(idx) {
    signal a[9][9];
    signal x[10];
    signal y[10];
    signal v[10];

    for i in [0..8] {
        for j in [0..8] {
            constraint a[i][j] > 0;
            constraint a[i][j] < 10;
        }
    }

    for i in [0..8] {
        for j in [0..8] {
            c = a[i][j];
            constraint x[c] == i;
            constraint y[c] == j;
        }
    }

    for i in [0..2] {
        for j in [0..2] {
            num = i * 3 + j;
            constraint v[num] == (a[x[num]][y[num]]);
        }
    }

    def commodore = multiplexer([
        private x[0],
        private x[1],
        private x[2],
        private x[3],
        private x[4],
        private x[5],
        private x[6],
        private x[7],
        private x[8]
    ]);

    def everest = multiplexer([
        private y[0],
        private y[1],
        private y[2],
        private y[3],
        private y[4],
        private y[5],
        private y[6],
        private y[7],
        private y[8]
    ]);

    def kilimanjaro = multiplexer([
        private v[0],
        private v[1],
        private v[2],
        private v[3],
        private v[4],
        private v[5],
        private v[6],
        private v[7],
        private v[8]
    ]);

    constant C = 1;

    for i in [0..2] {
        for j in [0..2] {
            constraint commodore[num] == i;
            constraint everest[num] == j;
            constraint kilimanjaro[num] == (a[commodore[num]][everest[num]]);
        }
    }
}

component main = Sudoku(0);
Enter fullscreen mode Exit fullscreen mode

Now, let's generate the circuit:

circom sudoku.circom
Enter fullscreen mode Exit fullscreen mode

This will create a circuit.json file that represents our Sudoku game proof circuit.

Next, we'll write the Solidity smart contract. In the contracts directory, create a new file called Sudoku.sol and add the following code:

pragma solidity ^0.8.0;

contract Sudoku {
    struct Puzzle {
        uint8[9][9] puzzle;
    }

    struct Proof {
        uint32[9][9] proof;
    }

    function verifySolution(Puzzle memory puzzle, Proof memory proof) public pure returns (bool) {
        // TODO: Implement the verification logic
        return false;
    }
}
Enter fullscreen mode Exit fullscreen mode

The verifySolution function takes in a Puzzle struct (represents the Sudoku puzzle) and a Proof struct (represents the proof provided by the user) and returns a boolean indicating whether the solution is valid or not. We'll fill in the verification logic later.

Finally, let's write the JavaScript frontend code. In the src directory, create a new file called app.js and add the following code:

const Web3 = require('web3');
const contractData = require('../build/contracts/Sudoku.json');

const web3 = new Web3('http://localhost:8545'); // Update with your Ethereum provider's URL
const contractAddress = '<YOUR_CONTRACT_ADDRESS>'; // Update with the deployed contract address
const accountAddress = '<YOUR_ACCOUNT_ADDRESS>'; // Update with your Ethereum account address

const contract = new web3.eth.Contract(contractData.abi, contractAddress);

async function verifySolution(puzzle, proof) {
    const result = await contract.methods.verifySolution(puzzle, proof).call({ from: accountAddress });
    return result;
}

async function run() {
    const puzzle = [
        [6, 0, 2, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 7, 5, 2, 6, 0, 0],
        [0, 0, 8, 0, 6, 0, 0, 0, 0],
        [0, 0, 4, 0, 9, 8, 0, 7, 0],
        [7, 6, 0, 0, 0, 0, 0, 2, 4],
        [0, 3, 0, 5, 7, 0, 9, 0, 0],
        [0, 0, 0, 0, 1, 0, 4, 0, 0],
        [0, 0, 9, 3, 2, 7, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 6, 0, 5],
    ];

    const proof = [
        [0, 6, 7, 5, 4, 2, 3, 8, 9],
        [3, 1, 5, 0, 0, 0, 7, 6, 4],
        [2, 4, 8, 6, 9, 3, 1, 5, 0],
        [1, 7, 0, 4, 2, 6, 8, 9, 3],
        [9, 5, 6, 0, 8, 1, 2, 0, 7],
        [8, 2, 3, 7, 0, 5, 0, 4, 0],
        [5, 9, 2, 8, 0, 0, 0, 7, 6],
        [6, 8, 1, 9, 3, 0, 4, 2, 5],
        [4, 3, 0, 0, 0, 0, 0, 0, 0],
    ];

    const result = await verifySolution(puzzle, proof);
    console.log(result);
}

run();
Enter fullscreen mode Exit fullscreen mode

This code sets up the Web3 provider, loads the Sudoku smart contract, and provides a sample Sudoku puzzle and proof to test the verification.

Before running the script, make sure to replace <YOUR_CONTRACT_ADDRESS> with the deployed smart contract address and <YOUR_ACCOUNT_ADDRESS> with your Ethereum account address.

To run the application, open a terminal window and navigate to the project directory. Then, run the following command:

node src/app.js
Enter fullscreen mode Exit fullscreen mode

This will execute the script and print the result indicating whether the solution is valid or not.

That's it! You have created a zk DApp using Circom, Solidity, and JavaScript to prove someone's ability to solve a Sudoku game without revealing the answer. Feel free to enhance and customize the code as per your requirements.

Ps. This content is AI-generated by the prompt:

We will create a zk DApp to prove that someone knows how to solve a sudoku game, without revealing the answer.

We will use Circom (for circuits), Solidity (for smart contracts) and Javascript (for the frontend).
Enter fullscreen mode Exit fullscreen mode

Top comments (0)