Skip to content

AND Constraints

Bitwise-AND relations on shifted value indices

As usual, we write ww for the full list of prover data (a concatenation of constant, input–output, and witness data). Each component of ww is a 64-bit word. We saw already that shifted value indices are tuple (y,op,s)W×{sll,srl,sra}×{0,,63}(y, \text{op}, s) \in W \times \{\mathsf{sll}, \mathsf{srl}, \mathsf{sra}\} \times \{0, \ldots , 63\} consisting of an index yy into the prover's runtime-dependent data, a shift type op\text{op}, and a shift amount ss.

An AND constraint, by definition, is three lists of shifted value indices, say (La,Lb,Lc)(L^a, L^b, L^c). We say that the AND constraint (La,Lb,Lc)(L^a, L^b, L^c) holds with respect to candidate prover data ww if and only if:

((y,op,s)Laop(w[y],s))&((y,op,s)Lbop(w[y],s))=?((y,op,s)Lcop(w[y],s)).\begin{equation*}\left( \bigoplus_{(y, \text{op}, s) \in L^a} \text{op}(w[y], s) \right) \& \left( \bigoplus_{(y, \text{op}, s) \in L^b} \text{op}(w[y], s) \right) \stackrel{?}= \left( \bigoplus_{(y, \text{op}, s) \in L^c} \text{op}(w[y], s) \right).\end{equation*}

Note that both sides of this equality are 64-bit words; the symbol &\& is a bitwise AND of 64-bit words.

Each given constraint system will specify, first, the total number nandn_\text{and} of AND constraints; it will moreover supply nandn_\text{and} triples (Lxa,Lxb,Lxc)(L^a_x, L^b_x, L^c_x) of the form already given above, for x{0,,nand1}x \in \{0, \ldots , n_\text{and} - 1\}. We will say that the prover data ww fulfills the constraint system's AND constraints if and only if for each x{0,,nand1}x \in \{0, \ldots , n_\text{and} - 1\}, the above equality holds over ww with respect to the xxth triple (Lxa,Lxb,Lxc)(L^a_x, L^b_x, L^c_x).

The Constraint Arrays

We now apply the constraint array formalism to this condition. Applying it, we get arrays aa, bb and cc, containing nandn_\text{and} 64-bit words, defined by the equalities:

a[x](y,op,s)Lxaop(w[y],s),b[x](y,op,s)Lxbop(w[y],s),c[x](y,op,s)Lxcop(w[y],s).\begin{align*} a[x] \coloneqq \bigoplus_{(y, \text{op}, s) \in L^a_x} \text{op}(w[y], s), \\ b[x] \coloneqq \bigoplus_{(y, \text{op}, s) \in L^b_x} \text{op}(w[y], s), \\ c[x] \coloneqq \bigoplus_{(y, \text{op}, s) \in L^c_x} \text{op}(w[y], s). \end{align*}

Having defined these arrays, we can now say that our constraint system's AND constraints are fulfilled if and only if

a[x]&b[x]=c[x]\begin{equation*}a[x] \mathbin{\&} b[x] = c[x]\end{equation*}

holds for each x{0,,nand1}x \in \{0, \ldots , n_\text{and} - 1\}.

Completeness

We pause here to argue that our constraint system is at least as powerful as a complete system of boolean circuits on 64-bit words (in fact, it's much more powerful, in concrete terms).

Bitwise AND is supported at the native level. Note that, technically, we can only act on values that have been shifted "somehow"; in order to get non-shifts, we can just use op=sll\text{op} = \textsf{sll} and s=0s = 0.

In order to constrain that a wire zz equals the bitwise XOR of wires xx and yy, we can add a constraint to the effect of

x ⊕ y & 0xFFFFFFFFFFFFFFFF = z.

Bitwise NOT is similar; to obtain a wire y=xy = \overline{x}, we can constrain

x & 0xFFFFFFFFFFFFFFFF = y ⊕ 0xFFFFFFFFFFFFFFFF.

Since z=xyz = x \vee y is equivalent to z=x&y\overline{z} = \overline{x} \mathrel{\&} \overline{y}, we can use

x ⊕ 0xFFFFFFFFFFFFFFFF & y ⊕ 0xFFFFFFFFFFFFFFFF = z ⊕ 0xFFFFFFFFFFFFFFFF

to get bitwise OR. Alternatively, the expression

x & y = x ⊕ y ⊕ z

also works.