ZK Speedrun: Noir, Circom, Zokrates in 15 Minutes
Published: 2024-02-02 16:40:23

---
title: ZK Speedrun: Noir, Circom, Zokrates in 15 Minutes
published: true
description: 
tags: 
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5mc58pn0n31dtxsglhny.png
# Use a ratio of 100:42 for best results.
# published_at: 2024-01-31 23:37 +0000
---

ℹ️ Are you a Circuit Breaker hacker? Join the Scroll telegram, find project ideas and join our telegram group by visiting our [Circuit Breaker cheat sheet](https://circuitbreaker.scroll.systems/)

## Zokrates

![ZK Zokrates Logo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p4ojuztmizan48h7cuqq.png)

### Instalation

```bash
curl -LSfs get.zokrat.es | sh
export PATH=$PATH:/home/YOURUSERNAME/.zokrates/bin
```

### Generate a proof

Create the zokrates circuit file.

`root.zok`
```js
def main(private field a, field b) {
    assert(a * a == b);
    return;
}
```

Now compile it and generate a proof.

```bash
zokrates compile -i root.zok
zokrates setup
zokrates compute-witness -a 3 9
zokrates generate-proof
```

The proof is now located in `proof.json`.

### Verify the proof

Generate a solidity verifier.

```bash
zokrates export-verifier
```

This will generate the `verifier.sol` contract. Now deploy it and pass it's address as constructor parameter to the following contract with custom solidity logic.

```javascript
// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;

library Pairing {
    struct G1Point {
        uint X;
        uint Y;
    }
    struct G2Point {
        uint[2] X;
        uint[2] Y;
    }
}

struct Proof {
    Pairing.G1Point a;
    Pairing.G2Point b;
    Pairing.G1Point c;
}

interface IZokratesVerifier {
    function verifyTx(Proof memory proof, uint[1] memory input) external view returns (bool r);
}

contract ZokratesCustomLogic {
    IZokratesVerifier zokratesVerifier;
    uint public publicInput;

    constructor(address zokratesVeriferAddress) {
        zokratesVerifier = IZokratesVerifier(zokratesVeriferAddress);
    }

    function sendProof(Proof memory proof, uint[1] memory input) public {
        // ZK verification
        zokratesVerifier.verifyTx(proof, input);

        // Your custom logic
        publicInput = input[0];
    }
}
```

## Noir

![ZK Noir Logo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oauub5ihspf289xhk4na.jpg)

### Instalation

#### On Linux

```bash
mkdir -p $HOME/.nargo/bin && \
curl -o $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.22.0/nargo-x86_64-unknown-linux-gnu.tar.gz && \
tar -xvf $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -C $HOME/.nargo/bin/ && \
echo -e '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.bashrc && \
source ~/.bashrc
```

#### On MacOs Apple Silicon

```bash
mkdir -p $HOME/.nargo/bin && \
curl -o $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.22.0/nargo-aarch64-apple-darwin.tar.gz && \
tar -xvf $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \
echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \
source ~/.zshrc
```

#### On MacOs Intel

```bash
mkdir -p $HOME/.nargo/bin && \
curl -o $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.22.0/nargo-x86_64-apple-darwin.tar.gz && \
tar -xvf $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \
echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \
source ~/.zshrc
```

### Generate a proof

Generate a new noir project and prepare it to receive the prover inputs.

```bash
nargo new hello_world
cd hello_world
nargo check
```

Now put the inputs in `Prover.toml` and generate the proof.

`Prover.toml`

```toml
x = "1"
y = "2"
```

```bash
nargo prove
```

The proof is now located at `proofs/hello_world.proof`.

### Verify the proof

Generate the solidity verifier.

```bash
nargo codegen-verifier
```

The verifier contract is now located at `contract/hello_world/plonk_vk.sol`. Deploy it and send it's address as param to the following contract with custom logic.

```javascript
// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;

interface INoirVerifier {
    function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool);
}

contract NoirCustomLogic {
    INoirVerifier noirVerifier;
    uint public publicInput;

    constructor(address noirVeriferAddress) {
        noirVerifier = INoirVerifier(noirVeriferAddress);
    }

    function sendProof(bytes calldata _proof, bytes32[] calldata _publicInputs) public {
        // ZK verification
        noirVerifier.verify(_proof, _publicInputs);

        // Your custom logic
        publicInput = uint(_publicInputs[0]);
    }
}
```

## Circom

![ZK Circom Logo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iy4t0s8j89ii29beracz.png)

### Installation

```bash
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
git clone https://github.com/iden3/circom.git
cd circom
cargo build --release
cargo install --path circom
npm install -g snarkjs
```

### Generate a proof

Create the circom circuit file and the inputs that will be passed to it.

`multiplier2.circom`

```js
pragma circom 2.0.0;

template Multiplier2() {
    signal input a;
    signal input b;
    signal output c;
    c <== a*b;
 }

 component main = Multiplier2();
```

`input.json`

```json
{"a": "3", "b": "11"}
```

Now let's generate the proof.

```bash
circom multiplier2.circom --r1cs --wasm --sym --c
node multiplier2_js/generate_witness.js multiplier2_js/multiplier2.wasm input.json witness.wtns
snarkjs powersoftau new bn128 12 pot12_0000.ptau -v
snarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau --name="First contribution" -v
snarkjs powersoftau prepare phase2 pot12_0001.ptau pot12_final.ptau -v
snarkjs groth16 setup multiplier2.r1cs pot12_final.ptau multiplier2_0000.zkey
snarkjs zkey contribute multiplier2_0000.zkey multiplier2_0001.zkey --name="1st Contributor Name" -v
snarkjs zkey export verificationkey multiplier2_0001.zkey verification_key.json
snarkjs groth16 prove multiplier2_0001.zkey witness.wtns proof.json public.json
snarkjs groth16 verify verification_key.json public.json proof.json
snarkjs generatecall
```

The proof will be printed on the terminal.

### Verify the proof

Generate the solidity verifier.

```bash
snarkjs zkey export solidityverifier multiplier2_0001.zkey verifier.sol
```

This will generate the `verifier.sol` contract. Deploy it and passit as constructo parameter to the following custom logic contract.

```javascript
// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;

interface ICircomVerifier {
    function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[1] calldata _pubSignals) external view returns (bool);
}

contract CircomCustomLogic {
    ICircomVerifier circomVerifier;
    uint public publicInput;

    constructor(address circomVeriferAddress) {
        circomVerifier = ICircomVerifier(circomVeriferAddress);
    }

    function sendProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[1] calldata _pubSignals) public {
        // ZK verification
        circomVerifier.verifyProof(_pA, _pB, _pC, _pubSignals);

        // Your custom logic
        publicInput = _pubSignals[0];
    }
}
```

For further information visit the [Zokrates](https://zokrates.github.io/gettingstarted.html), [Noir](https://noir-lang.org/docs/), and [Circom](https://docs.circom.io/getting-started/installation/) official documentation.

**Thank you for reading this article!**

Follow me on dev.to and on [Youtube](https://www.youtube.com/@filosofiacodigoinenglish4031) for everything related to Blockchain development.