Selector combining

Heavy use of custom gates can lead to a circuit defining many binary selectors, which would increase proof size and verification time.

This page describes an optimization, applied automatically by halo2, that combines binary selector columns into fewer fixed columns.

The basic idea is that if we have

binary selectors labelled
1,,
that are enabled on disjoint sets of rows, then under some additional conditions we can combine them into a single fixed column, say
q
, such that:
q={k,if the selector labelled k is 10,if all selectors are 0.

However, the devil is in the detail.

The halo2 API allows defining some selectors to be "simple selectors", subject to the following condition:

Every polynomial constraint involving a simple selector

s must be of the form
st=0,
where
t
is a polynomial involving no simple selectors.

Suppose that

s has label
k
in some set of
simple selectors that are combined into
q
as above. Then this condition ensures that replacing
s
by
q1h,hk(hq)
will not change the meaning of any constraints.

It would be possible to relax this condition by ensuring that every use of a binary selector is substituted by a precise interpolation of its value from the corresponding combined selector. However,

  • the restriction simplifies the implementation, developer tooling, and human understanding and debugging of the resulting constraint system;
  • the scope to apply the optimization is not impeded very much by this restriction for typical circuits.

Note that replacing

s by
q1h,hk(hq)
will increase the degree of constraints selected by
s
by
1
, and so we must choose the selectors that are combined in such a way that the maximum degree bound is not exceeded.

Identifying selectors that can be combined

We need a partition of the overall set of selectors

s0,,sm1 into subsets (called "combinations"), such that no two selectors in a combination are enabled on the same row.

Labels must be unique within a combination, but they are not unique across combinations. Do not confuse a selector's index with its label.

Suppose that we are given

max_degree, the degree bound of the circuit.

We use the following algorithm:

  1. Leave nonsimple selectors unoptimized, i.e. map each of them to a separate fixed column.
  2. Check (or ensure by construction) that all polynomial constraints involving each simple selector
    si
    are of the form
    siti,j=0
    where
    ti,j
    do not involve any simple selectors. For each
    i
    , record the maximum degree of any
    ti,j
    as
    dimax
    .
  3. Compute a binary "exclusion matrix"
    X
    such that
    Xj,i
    is
    1
    whenever
    ij
    and
    si
    and
    sj
    are enabled on the same row; and
    0
    otherwise.

    Since

    X is symmetric and is zero on the diagonal, we can represent it by either its upper or lower triangular entries. The rest of the algorithm is guaranteed only to access only the entries
    Xj,i
    where
    j>i
    .

  4. Initialize a boolean array
    added0..k1
    to all
    false
    .

    addedi will record whether
    si
    has been included in any combination.

  5. Iterate over the
    si
    that have not yet been added to any combination:
    • a. Add
      si
      to a fresh combination
      c
      , and set
      addedi=true
      .
    • b. Let mut
      d:=dimax1
      .

      d is used to keep track of the largest degree, excluding the selector expression, of any gate involved in the combination
      c
      so far.

    • c. Iterate over all the selectors
      sj
      for
      j>i
      that can potentially join
      c
      , i.e. for which
      addedj
      is false:
      • i. (Optimization) If
        d+len(c)=max_degree
        , break to the outer loop, since no more selectors can be added to
        c
        .
      • ii. Let
        dnew=max(d,djmax1)
        .
      • iii. If
        Xj,i
        is
        true
        for any
        i
        in
        c
        , or if
        dnew+(len(c)+1)>max_degree
        , break to the outer loop.

        dnew+(len(c)+1) is the maximum degree, including the selector expression, of any constraint that would result from adding
        sj
        to the combination
        c
        .

      • iv. Set
        d:=dnew
        .
      • v. Add
        sj
        to
        c
        and set
        addedj:=true
        .
    • d. Allocate a fixed column
      qc
      , initialized to all-zeroes.
    • e. For each selector
      sc
      :
      • i. Label
        s
        with a distinct index
        k
        where
        1klen(c)
        .
      • ii. Record that
        s
        should be substituted with
        qc1hlen(c),hk(hqc)
        in all gate constraints.
      • iii. For each row
        r
        such that
        s
        is enabled at
        r
        , assign the value
        k
        to
        qc
        at row
        r
        .

The above algorithm is implemented in halo2_proofs/src/plonk/circuit/compress_selectors.rs. This is used by the compress_selectors function of halo2_proofs/src/plonk/circuit.rs which does the actual substitutions.

Writing circuits to make best use of selector combining

It is beneficial for this optimization to use simple selectors as far as possible, rather than fixed columns. It is usually not beneficial to do manual combining of selectors, because the resulting fixed columns cannot take part in the automatic combining. That means that to get comparable results you would need to do a global optimization manually, which would interfere with writing composable gadgets.

Whether two selectors are enabled on the same row (and so are inhibited from being combined) depends on how regions are laid out by the floor planner. The currently implemented floor planners do not attempt to take this into account. We suggest not worrying about it too much — the gains that can be obtained by cajoling a floor planner to shuffle around regions in order to improve combining are likely to be relatively small.