halo2 Crates.io

IMPORTANT: This library is being actively developed and should not be used in production software.

Documentation

License

Copyright 2020 The Electric Coin Company.

You may use this package under the Transitive Grace Period Public Licence, version 1.0, or at your option, any later version. See the file LICENSE-TGPPL for the terms of the Transitive Grace Period Public Licence, version 1.0.

The purpose of the TGPPL is to allow commercial improvements to the package while ensuring that all improvements are eventually open source. See here for why the TGPPL exists, graphically illustrated on three slides.

Concepts

User Documentation

You're probably here because you want to write circuits? Excellent!

This section will guide you through the process of creating circuits with halo2.

A simple example

Let's start with a simple circuit, to introduce you to the common APIs and how they are used. The circuit will take a public input , and will prove knowledge of two private inputs and such that


#![allow(unused)]
fn main() {
extern crate halo2;
use halo2::arithmetic::FieldExt;

struct MyCircuit<F: FieldExt> {
    a: F,
    b: F,
}
}

TODO

Lookup tables

In normal programs, you can trade memory for CPU to improve performance, by pre-computing and storing lookup tables for some part of the computation. We can do the same thing in halo2 circuits!

A lookup table can be thought of as enforcing a relation between variables, where the relation is expressed as a table. Assuming we have only one lookup argument in our constraint system, the total size of tables is constrained by the size of the circuit: each table entry costs one row, and it also costs one row to do each lookup.

TODO

Gadgets

Tips and tricks

This section contains various ideas and snippets that you might find useful while writing halo2 circuits.

Small range constraints

A common constraint used in R1CS circuits is the boolean constraint: . This constraint can only be satisfied by or .

In halo2 circuits, you can similarly constrain a cell to have one of a small set of values. For example, to constrain to the range , you would create a gate of the form:

while to constraint to be either 7 or 13, you would use:

The underlying principle here is that we create a polynomial constraint with roots at each value in the set of possible values we want to allow. In R1CS circuits, the maximum supported polynomial degree is 2 (due to all constraints being of the form ). In halo2 circuits, you can use arbitrary-degree polynomials - with the proviso that higher-degree constraints are more expensive to use.

Note that the roots don't have to be constants; for example will constrain to be equal to one of where the latter can be arbitrary polynomials, as long as the whole expression stays within the maximum degree bound.

Design

Permutation argument

Given that gates in halo2 circuits operate "locally" (on cells in the current row or defined relative rows), it is common to need to copy a value from some arbitrary cell into the current row for use in a gate. This is performed with an equality constraint, which enforces that the source and destination cells contain the same value.

We implement these equality constraints by constructing a permutation that represents the constraints, and then using a permutation argument within the proof to enforce them.

Notation

A permutation is a one-to-one and onto mapping of a set onto itself. A permutation can be factored uniquely into a composition of cycles (up to ordering of cycles, and rotation of each cycle).

We sometimes use cycle notation to write permutations. Let denote a cycle where maps to , maps to , and maps to (with the obvious generalisation to arbitrary-sized cycles). Writing two or more cycles next to each other denotes a composition of the corresponding permutations. For example, denotes the permutation that maps to , to , to , and to .

Constructing the permutation

Goal

We want to construct a permutation in which each subset of variables that are in a equality-constraint set form a cycle. For example, suppose that we have a circuit that defines the following equality constraints:

From this we have the equality-constraint sets and . We want to construct the permutation:

which defines the mapping of to .

Algorithm

We need to keep track of the set of cycles, which is a set of disjoint sets. Efficient data structures for this problem are known; for the sake of simplicity we choose one that is not asymptotically optimal but is easy to implement.

We represent the current state as:

  • an array for the permutation itself;
  • an auxiliary array that keeps track of a distinguished element of each cycle;
  • another array that keeps track of the size of each cycle.

We have the invariant that for each element in a given cycle , points to the same element . This allows us to quickly decide whether two given elements and are in the same cycle, by checking whether . Also, gives the size of the cycle containing . (This is guaranteed only for , not for .)

The algorithm starts with a representation of the identity permutation: for all , we set , , and .

To add an equality constraint :

  1. Check whether and are already in the same cycle, i.e. whether . If so, there is nothing to do.
  2. Otherwise, and belong to different cycles. Make the larger cycle and the smaller one, by swapping them iff .
  3. Following the mapping around the right (smaller) cycle, for each element set .
  4. Splice the smaller cycle into the larger one by swapping with .

For example, given two disjoint cycles and :

A +---> B
^       +
|       |
+       v
D <---+ C       E +---> F
                ^       +
                |       |
                +       v
                H <---+ G

After adding constraint the above algorithm produces the cycle:

A +---> B +-------------+
^                       |
|                       |
+                       v
D <---+ C <---+ E       F
                ^       +
                |       |
                +       v
                H <---+ G

Broken alternatives

If we did not check whether and were already in the same cycle, then we could end up undoing an equality constraint. For example, if we have the following constraints:

and we tried to implement adding an equality constraint just using step 4 of the above algorithm, then we would end up constructing the cycle , rather than the correct .

Argument specification

TODO: Document what we do with the permutation once we have it.