Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

arithmetic-circuits crate #380

Open
wants to merge 14 commits into
base: release-0.5.0
Choose a base branch
from
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
members = [
"relations",
"snark",
"arithmetic-circuits",
]

resolver = "2"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This repository contains two Rust crates:

* [`ark-snark`](snark): Provides generic traits for zkSNARKs
* [`ark-relations`](relations): Provides generic traits for NP relations used in programming zkSNARKs, such as R1CS
* [`arithmetic-circuits`](arithmetic-circuits): Provides a library for constructing arithmetic circuits and expressions

## Overview

Expand Down
29 changes: 29 additions & 0 deletions arithmetic-circuits/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "ark-arithmetic-circuits"
version.workspace = true
authors.workspace = true
description = "A library for arithmetic circuits"
homepage.workspace = true
repository.workspace = true
keywords = ["zero-knowledge", "cryptography", "arithmetic-circuits"]
categories = ["cryptography"]
include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
license.workspace = true
edition.workspace = true

[dependencies]
ark-std.workspace = true
ark-ff.workspace = true
ark-relations = { version = "0.5.0-alpha", default-features = false }
itertools = { version = "0.13.0", default-features = false }

[dev-dependencies]
tokio = { version = "1", features = [ "full" ] }
ark-ec = { version = "0.5.0-alpha", default-features = false }
ark-circom = { git = "https://github.com/arkworks-rs/circom-compat", branch = "release-0.5" }
ark-bn254 = { version = "0.5.0-alpha", default-features = false, features = [ "curve" ] }
ark-bls12-377 = { version = "0.5.0-alpha", default-features = false, features = [ "curve" ] }

[features]
default = [ "itertools/use_alloc" ]
std = [ "ark-ff/std", "ark-ec/std", "ark-std/std", "ark-relations/std", "itertools/use_alloc" ]
1 change: 1 addition & 0 deletions arithmetic-circuits/LICENSE-APACHE
1 change: 1 addition & 0 deletions arithmetic-circuits/LICENSE-MIT
61 changes: 61 additions & 0 deletions arithmetic-circuits/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
## Arithmetic circuits

Arithmetic circuits are a way to represent polynomial expressions as a sequence of addition and multiplication operations, which we conceptualise as gates. These operations take the form of nodes in a directed acyclic graph, where the edges represent the flow of data between the nodes. In this implementation, gates have a fan-in of two (i.e. two inputs) and arbitrary fan-out (i.e. their output can be the output of arbitrarily many other gates). We represent arithmetic circuits as an array of `Constants`, `Variables`, `Add` gates and `Mul` gates. Gates have a left and right input, which are indices for the respective nodes in the array. In order to directly construct an arithmetic circuit, the user must instantiate an empty `ArithmeticCircuit` struct and mutate it via its public methods (e.g. `new_variable`, `add`, `mul`), each of which returns the index of the new node in the array. For example, an arithmetic circuit expressing the computation `2 * x + y` can be constructed as follows:

```rust
let mut circuit = ArithmeticCircuit::new();
let two = circuit.constant(F::from(2));
let x = circuit.new_variable();
let y = circuit.new_variable();
let two_x = circuit.mul(two, x);
let result = circuit.add(two_x, y);
```

Variables can also be given labels for easier value assignment and tracking:

```rust
let x = circuit.new_variable_with_label("x");
let y = circuit.new_variable_with_label("y");
```

We note that there is only one `Constant` node for each field element `v` appearing in the computation: subsequent calls to `circuit.constant(v)` will point to the same node and therefore can be transparently made without incuring unnecessary spatial costs.


## Arithmetic expressions

We also provide tooling to generate arithmetic circuits from user-friendly `Expression`s. The latter allow the programmer to write mathematical formulas in a more human-readable way (e.g., `a + b * c`) and can subsequently be converted into an `ArithmeticCircuit`. For comparison, an arithmetic circuit for the same computation `2 * x + y` can be constructed as follows:

```rust
let x = Expression::variable("x");
let y = Expression::variable("y");
let result = 2 * x + y;
let circuit = result.to_arithmetic_circuit();
```

In the case of expressions, variable labels are indispensable anchors to each individual variable after the expression is compiled into a circuit.

Due to Rust's borrow-checker, an expression needs to be cloned if it is used more than once in the same line. For instance, the following
```rust
let expression = x * x + y;
```
will not compile, the correct syntax being:
```rust
let expression = x.clone() * x + y;
```
We note that cloning expressions is very cheap, since they are implemented using the `Rc` struct. This and other pain points of expression sysntax may be ironed out in the future.

## R1CS to arithmetic circuits

Our implementation also includes the method `from_constraint_system`, which allows the user to convert an Arkworks `ConstraintSystem` (i.e., an R1CS) into an `ArithmeticCircuit`. The method takes as input a `ConstraintSystem` struct, which contains the R1CS matrices `A`, `B`, and `C`. A `ConstraintSystem` can be obtained from the circom generated `.r1cs` and `.wasm` files,via the `read_constraint_system` method.

## Generating R1CS files
In order to generate an `.r1cs` file from a `.circom` one (with name, say, `NAME`), use
```
circom NAME.circom --r1cs
```

In order to generate a `.wasm` file from a `.circom` one, use
```
circom NAME.circom --wasm
```
and take the `.wasm` file from within the newly created folder.
Loading
Loading