# Getting Started with Circom & Noir > What is Circom, what is Noir and why are you trying to get me to learn MORE languages? [Circom](https://docs.circom.io/) and [Noir](https://docs.aztec.network/noir) are programming languages designed for building privacy-preserving applications using zero-knowledge proofs (ZKPs). [Circom](https://docs.circom.io/) and [SnarkJS](https://github.com/iden3/snarkjs) have been utilized in numerous production-ready projects within the Ethereum network, such as [Tornado](https://tornado.cash/), [Polygon Hermez](https://hermez.io/), [Dark Forest](https://zkga.me/), and various others. [Aztec Protocol](https://docs.aztec.network/) is the team behind [Noir](https://docs.aztec.network/noir). Here is a [list of projects](https://github.com/noir-lang/awesome-noir#projects) using Noir aside from the Aztec team. **TL;DR** Circom and Noir enable the creation of efficient and scalable zero-knowledge circuits. - Circom is a language for building circuits that can be compiled into zero-knowledge proofs. - Noir is a programming language that was specifically designed for building privacy-preserving applications using zero-knowledge proofs. - Both Circom and Noir are languages for building arithmetic circuits. - In both languages, circuits are defined in terms of input and output signals and constraints that operate on those signals. By learning Circom and/or Noir, you can have access to two powerful tools for building privacy-preserving applications. While it may seem daunting to learn multiple programming languages, each language has its own strengths and use cases. Circom is particularly useful for building efficient and scalable circuits, while Noir is great for building complex applications that require advanced cryptographic operations. Zero-Knowledge Proofs (ZKPs) are a type of cryptographic protocol that can be used to prove the validity of computations without revealing the input values or intermediate computations. Learning Circom and Noir can greatly enhance your skills as a developer in the field of ZKP development, and provide you with a wider range of tools to build powerful privacy-preserving applications. #### Docs - [Circom](https://docs.circom.io/) - [Noir](https://noir-lang.org/index.html) #### Continue Reading?... > Have fun reading this post, but read the docs <3 The Circom and Noir docs are quite thorough and well laid out. Reading through them eventually is a very good idea. This blog post is meant to help as a supporting resource for "getting started" and will not cover more complex interactions with the languages; for another post I suppose. ### What You Might Learn > What one might learn from going through this post? - What is a ZKP? - Overview of Circom & Noir - Features, benefits, differences. - Instillation & setup - Writing circuits in Circom - Writing programs in Noir - Building, proving, verifying circuits - generating proofs - verifying proofs - compiling circuits into JSON artifacts. ## Background (ZKP) > https://docs.circom.io/background/background/ A **zero-knowledge** proof is a protocol that enables one party, called the prover, to convince another, the verifier, that a statement is true without revealing any information beyond the veracity of the statement. **Non-interactive zero-knowledge proofs** are a particular type of zero-knowledge proofs in which the prover can generate the proof without interaction with the verifier. NIZK protocols are very suitable for blockchain applications, because they allow a smart contract to act as a verifier. - In this context, the most preferable NIZK are zk-SNARK proofs (Zero Knowledge-Succinct ARguments of Knowledge), a set of non-interactive zero-knowledge protocols that have succinct proof size and sublinear verification time. - The importance of these protocols is double: - on the one hand, they help improve privacy guarantees - on the other, their small proof size has been used in scalability solutions. #### Arithmetic circuits > zk-SNARKs require the computational statement to be modeled with an arithmetic circuit. Although it may not always be obvious how to do this conversion, most computational problems we care about can easily be converted into arithmetic circuits. An **`F_p`-arithmetic circuit** is a circuit consisting of set of wires that carry values from the field **`F_p`** and connect them to addition and multiplication gates `modulo p`. - given a prime number `p`, the finite field **`F_p`** consists of the set of numbers ``{0,...,p-1}`` on which we can add and multiply these numbers `modulo p`. - For example, the finite field **`F_7`** consists of the set of numbers `{0,...,6}` on which we can add and multiply numbers `modulo 7`. - In other words, we only care about the reminder of dividing by 7. - For instance: - `15 modulo 7 = 1`, since `15 = 7 + 7 + 1` - `7 modulo 7 = 0` - `4*3 modulo 7 = 5`, since `4*3 = 12 = 7 + 5` #### Signals of a Circut > An arithmetic circuit takes some **input signals** that are values between `0,...,p-1` and performs additions and multiplications between them modulo the prime `p`. The output of every addition and multiplication gate is considered an **intermediate signal**, except for the last gate of the circuit, the output of which, is the **output signal** of the circuit. - In order to use zk-SNARK protocols, the relation between signals needs to be described as a system of equasions that relate variables with gates. - The equations that describe the circuit are called constraints; conditions that signals of that circuit must satisfy. #### Rank-1 constraint system > The set of constraints describing the circuit is called **rank-1 constraint system** $R1CS$. - If we have an arithmetic circuit with signals s_1,...,s_n, then we define a constraint as an equation of the following form: `(a_1*s_1 + ... + a_n*s_n) + (b_1*s_1 + ... + b_n*s_n) + (c_1*s_1 + ... + c_n*s_n) = 0` - If the R1CS of our circuit consists of the following two equations: - `d = a*b modulo 7` - `out = d+c modulo 7` - we can gather the two equations into a single one:`out = a*b + c modulo 7` - Zero-knowledge permits proving **circuit satisfiability**. What this means is, that you can prove that you know a set of signals that satisfy the circuit, or in other words, that you know a solution to the R1CS. This set of signals is called **witness**. #### Witness > An assignment of the signals is called a witness. - Imagine that the input `a` is a private key and the input `b` is the corresponding public key. If we define `a` as a private input, `b`, `c` as public inputs and `out` as a public output, with zero-knowledge we are able to prove, without revealing its value, that we know a private input `a` such that, for certain public values `b`, `c` and `out`, the equation `a*b + c = out mod 7` holds. - Note that we could easily deduce the value of `a` by isolating it from the other signals. It is important to design circuits that keep the privacy of the private inputs and prevent deducing them from the R1CS. ## Circom > [Circom Docs](https://docs.circom.io/) Circom is a language for building arithmetic circuits that can be compiled into zero-knowledge proofs. It allows programmers to define the constraints that define the arithmetic circuit using linear combinations of signals. In this post, we will explore how to build and verify zero-knowledge proofs for arithmetic circuits using Circom and SnarkJS. We'll start by introducing the concept of zero-knowledge proofs and their importance in preserving privacy. Then, we'll dive into Circom, a language for building arithmetic circuits, and walk through the process of defining constraints, compiling circuits, computing witnesses, and generating proofs. Finally, we'll show how to verify proofs both locally and on the Ethereum blockchain using SnarkJS and Solidity. By the end of this post, you should have a solid understanding of how to build and verify zero-knowledge proofs for arithmetic circuits using Circom and SnarkJS. ### Installation > [Installing Circom](https://docs.circom.io/getting-started/installation/) - get rust: ```curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh``` - get [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) (npm -v / node -v) - clone the thing: ```git clone https://github.com/iden3/circom.git``` - build the thing: ```cargo build --release``` - install the thing: ```cargo install --path circom``` - get snarkjs: ```npm install -g snarkjs``` ### Basic Example > [Example in docs](https://docs.circom.io/getting-started/writing-circuits/) - Circom is a tool to define constraints that form an arithmetic circuit. - The constraints should be in the form of `A*B + C = 0` where `A`, `B`, and `C` are linear combinations of signals. - A circuit can be defined using the reserved keyword "template" followed by its name, such as `Multiplier2`. - Signals are named identifiers, such as `a`, `b`, and `c`. **Example Circuit:** ```rust= // Sets the compiler version to 2.0.0 pragma circom 2.0.0; // Defines a new template called Multiplier2 template Multiplier2 () { // Declares input signals a and b, and output signal c signal input a; signal input b; signal output c; // Sets the value of c to the result of multiplying a and b c <== a * b; } ``` - In this example, the circuit has two input signals, `a` and `b`, and one output signal, `c`. - The operator ``<==`` is used to set the value of `c` to the result of multiplying `a` and `b`. - Alternatively, the operator ``==>`` can be used for the same purpose. - In a template, signals are declared first, followed by their associated constraints. > For more complex circuit examples: https://docs.circom.io/more-circuits/more-basic-circuits/ #### Compiling Circuits > https://docs.circom.io/getting-started/compiling-circuits/ - Using the template from above, save the circuit in a file with the .circom extension, for example, `multiplier2.circom`. - Compile the circuit using the circom command, providing options to generate the desired files. - `circom --help` ```bash circom multiplier2.circom --r1cs --wasm --sym --c ``` - The following files will be generated: - `multiplier2.r1cs`: contains the R1CS (Rank-1 Constraint System) of the circuit in binary format. - `multiplier2_js`: contains the Wasm (WebAssembly) code and other files needed to generate the witness. - `multiplier2.sym`: a symbols file required for debugging or for printing the constraint system in an annotated mode. - `multiplier2_cpp`: contains several files (`multiplier2.cpp`, `multiplier2.dat`, and other common files for every compiled program like `main.cpp`, `MakeFile`, etc.) needed to compile the C code to generate the witness. #### Computing the Witness > What is a [witness](https://docs.circom.io/background/background#witness)? - Before creating the proof, we need to calculate all the signals of the circuit that match all the constraints of the circuit. - The set of inputs, intermediate signals and output is called witness. - We need to create a file named `input.json` that containing the inputs written in the standard JSON format. - ex `{"a": "3", "b": "11"}` - [Computing the witness with WebAssembly](https://docs.circom.io/getting-started/computing-the-witness/#what-is-a-witness:~:text=needed%20JavaScript%20files.-,Computing%20the%20witness%20with%20WebAssembly,-Enter%20in%20the) - After calling the circom compiler with the flag --wasm and the circuit `multiplier2.circom` we can find a `multiplier2_js` folder that contains the Wasm code in `multiplier2.wasm` and all the needed JavaScript files. - Enter in the directory `multiplier2_js`, add the input in a file input.json and execute:```node generate_witness.js multiplier2.wasm input.json witness.wtns``` - [Computing the witness with C++](https://docs.circom.io/getting-started/computing-the-witness/#computing-the-witness-with-webassembly:~:text=json%20witness.wtns-,Computing%20the%20witness%20with%20C%2B%2B,-As%20a%20faster) - As a faster alternative, we can use the C++ directory to compute the witness using the previous file input.json. This directory is created when using the circom compiler with the flag `--c` - enter the directory and execute: `make` - The command creates an executable; we execute it indicating the input file and the name for the witness file: example: `./multiplier2 input.json witness.wtns` >Note. To compile the C++ source, we rely on some libraries that you need to have installed in your system. In particular, we use `nlohmann-json3-dev`, `libgmp-dev` and `nasm`. - The Witness file - The two programs will generate the same `ẁitness.wtns` file. This file is encoded in a binary format compatible with `snarkjs`, which is the tool that we use to create the actual proofs. - Note. For big circuits, the C++ witness calculator is significantly faster than the WASM calculator. #### Proving Circuits (Groth16) > https://docs.circom.io/getting-started/proving-circuits/ - [Groth16](https://eprint.iacr.org/2016/260) requires a per circuit trusted setup. The trusted setup consists of 2 parts: 1. The powers of tau, which is independent of the circuit. - Powers of Tau - First, we start a new "powers of tau" ceremony:`snarkjs powersoftau new bn128 12 pot12_0000.ptau -v` - Then, we contribute to the ceremony:`snarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau --name="First contribution" -v` - Now, we have the contributions to the powers of tau in the file `pot12_0001.ptau` and we can proceed with the Phase 2. 2. The phase 2, which depends on the circuit. - Execute the following command to start the generation of this phase:`snarkjs powersoftau prepare phase2 pot12_0001.ptau pot12_final.ptau -v` - Generate a `.zkey` file that will contain the proving and verification keys together with all phase 2 contributions: `snarkjs groth16 setup multiplier2.r1cs pot12_final.ptau multiplier2_0000.zkey` - Contribute to the phase 2 of the ceremony: `snarkjs zkey contribute multiplier2_0000.zkey multiplier2_0001.zkey --name="1st Contributor Name" -v` - Export the verification key: `snarkjs zkey export verificationkey multiplier2_0001.zkey verification_key.json` #### Generating a Proof > Once the witness is computed and the trusted setup is already executed, we can generate a zk-proof associated to the circuit and the witness - generate a zk-proof associated to the circuit and the witness: `snarkjs groth16 prove multiplier2_0001.zkey witness.wtns proof.json public.json` - generates a Groth16 proof and outputs two files: 1. `proof.json`: it contains the proof. 2. `public.json`: it contains the values of the public inputs and outputs. #### Verifying a Proof > A valid proof not only proves that we know a set of signals that satisfy the circuit, but also that the public inputs and outputs that we use match the ones described in the public.json file. - Verify the proof: `snarkjs groth16 verify verification_key.json public.json proof.json` - The command uses the files `verification_key.json` we exported earlier, `proof.json`, and `public.json` to check if the proof is valid. (OK) #### Verifying from a Smart Contract > It is also possible to generate a Solidity verifier that allows verifying proofs on Ethereum blockchain. - Generate the Solidity code using the command: `snarkjs zkey export solidityverifier multiplier2_0001.zkey verifier.sol` - This command takes validation key `multiplier2_0001.zkey` and outputs Solidity code in a file named `verifier.sol`. - You can take the code from this file and cut and paste it in Remix. You will see that the code contains two contracts: Pairing and Verifier. You only need to deploy the Verifier contract. - You can also use the JavaScript VM, but in some browsers the verification takes long and the page may freeze. - The Verifier has a view function called `verifyProof` that returns `TRUE` if and only if the proof and the inputs are valid. - To facilitate the call, you can use `snarkJS` to generate the parameters of the call by typing: `snarkjs generatecall` - Cut and paste the output of the command to the parameters field of the `verifyProof` method in Remix. - If everything works fine, this method should return `TRUE`. - You can try to change just a single bit of the parameters, and you will see that the result is verifiable `FALSE`. ## Noir > [Installing Noir](https://noir-lang.org/getting_started/nargo/installation.html) Noir is a programming language that was specifically designed for building privacy-preserving applications using zero-knowledge proofs. It is a high-level language that makes it easy for developers to express complex cryptographic operations using simple and intuitive syntax. The language is built on top of the Rust programming language, which provides fast execution speeds and strong type safety guarantees. Noir also comes with a suite of powerful tools and libraries that make it easy to build, prove, and verify zero-knowledge circuits. Overall, Noir is a powerful tool for developers who want to build privacy-preserving applications without sacrificing performance or security. This post provides an overview of Noir, including how to install it and use its suite of tools and libraries to build, prove, and verify zero-knowledge circuits. A basic example is also provided to demonstrate how to create and verify a proof in a Noir program. ### Installation - [Compile from Source](https://noir-lang.org/getting_started/nargo/installation.html#option-2-compile-from-source): - Install [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) and [Rust](https://www.rust-lang.org/tools/install). - Download Noir's source code from Github by running: `git clone git@github.com:noir-lang/noir.git` - Change directory into the Noir project by running: `cd noir` - Option 2.1: Install Executable with WASM backend Install Nargo by running: `cargo install --locked --path=crates/nargo --no-default-features --features plonk_bn254_wasm` - Option 2.2: [Install Executable with Native Backend](https://noir-lang.org/getting_started/nargo/installation.html#option-22-install-executable-with-native-backend) - Check if the installation was successful by running `nargo --help` ### Commands > https://noir-lang.org/getting_started/nargo/commands.html - The `nargo` command (same a `nargo help` / `nargo -h` / `nargo --help`) brings up the menu. - `nargo new` - <pkg name> - `nargo check` - Generate `Prover.toml` and Verifier.toml files for specifying prover and verifier. - `nargo excecute` - <witness_name> - `nargo prove` - <proof_name> - `nargo verify` - <proof> - `nargo codegen-verifier` - Generate a Solidity verifier smart contract for the program. - `nargo compile` - <circuit_name> ### Basic Example > [Hello, World example in docs](https://noir-lang.org/getting_started/hello_world.html) - Noir is a domain specific language for creating and verifying proofs. It's design choices are influenced heavily by Rust. - `nargo` is a command line tool for interacting with Noir programs (e.g. compiling, proving, verifying and more). - Alternatively, the interactions can also be performed in TypeScript. - `nargo new hello_world` - In production, the common practice is to name the project folder as `circuits` for better identifiability when sitting alongside other folders in the codebase (e.g. `contracts`, `scripts`, `test`). - The default main.nr generated should look like this: ```Rust= fn main(x : Field, y : pub Field) { constrain x != y; } ``` - Program inputs in Noir are private by default (e.g. `x`), but can be labeled public using the keyword `pub` (e.g. `y`). - `cd hello_world` & `cargo check` - Fill in input values for execution in the `Prover.toml` file. - `constrain x != y;` - `nargo prove` <proof_name> - `nargo verify` <proof_name> We did it! We created and verified a proof in a Noir program! ## Next Steps > What might one want to read next? After going through the basics of Circom and Noir, you might want to explore more advanced topics and real-world use cases for both languages. Here are some suggestions for what to read next: **Circom:** - [Example circuits](https://github.com/iden3/circomlib) - [Circom and zk-SNARKs tutorials](https://github.com/iden3/tutorial-examples) **Noir:** - [Awesome Noir](https://github.com/noir-lang/awesome-noir) **Others** - [Developer's Guide to the ZK Galaxy](https://blockchain.capital/a-developers-guide-to-the-zkgalaxy/) By diving into more advanced topics and real-world examples, you'll gain a deeper understanding of how to build and verify zero-knowledge proofs for arithmetic circuits using Circom and Noir, as well as how to apply these techniques in various scenarios such as privacy-preserving applications and decentralized systems.