# Circom > https://linear.app/uncloak/issue/UNC-17/circom-examples ## Getting Started > https://docs.circom.io/getting-started/installation/ - get rust ```curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh``` - get nmp or yarn (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 snarky: ```npm install -g snarkjs``` ### Notes > zk-SNARK proofs are an specific type of zero-knowledge proofs that allow you to prove that you know a set of signals that match all the constraints of a circuit without revealing any of the signals except the public inputs and the outputs. - 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. - [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. > For a more complex circuit example: https://docs.circom.io/more-circuits/more-basic-circuits/ After compiling the circuit and running the witness calculator with an appropriate input, we will have a file with extension `.wtns` that contains all the computed signals and, a file with extension `.r1cs` that contains the constraints describing the circuit. Both files will be used to create our proof. #### Using the Groth16 zk-SNARK protocol > https://eprint.iacr.org/2016/260 - Groth16 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`. #### 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. ### The Circom Language > Notes specifically about the language #### Signals > https://docs.circom.io/circom-language/signals/ - The arithmetic circuits built using circom operate on signals, which contain field elements in Z/pZ. - Signals can be named with an identifier or can be stored in arrays and declared using the keyword signal. Signals can be defined as input or output, and are considered intermediate signals otherwise. - `signal input in;` - `signal output out[N];` - `signal inter;` - Since circom 2.0.4, it is also allowed the initialization of intermediate and outputs signals right after their declaration. ```Circom= pragma circom 2.0.0; template Multiplier2(){ //Declaration of signals signal input in1; signal input in2; signal output out <== in1 * in2; } component main {public [in1,in2]} = Multiplier2(); ``` - In circom, all output signals of the main component are public (and cannot be made private), the input signals of the main component are private if not stated otherwise using the keyword public as above. The rest of signals are all private and cannot be made public. - Signals can only be assigned using the operations <-- or <== and --> or ==>. - The safe options are <== and ==>, since they assign values and also generate constraints at the same time. - Using <-- and --> is, in general, dangerous and should only be used when the assigned expression cannot be included in a constraint, like in the following example. - `out[k] <-- (in >> k) & 1; #### Variables & Mutability > https://docs.circom.io/circom-language/variables-and-mutability/ - Variables are identifiers that hold non-signal data and are mutable. Variables are declared using the keyword `var` - Variable assignment is made using the equal symbol =. Declarations may also include an initialization, as in the following examples: - `var x;` - `x = 234556;` - `var y = 0;` - `var z[3] = [1,2,3];` #### Templates & Components > https://docs.circom.io/circom-language/templates-and-components/ - The instantiation of a template is a new circuit object, which can be used to compose other circuits, so is part of larger circuits. -