AND Constraints
As usual, we write for the full list of prover data (a concatenation of constant, input–output, and witness data). Each component of is a 64-bit word. We saw already that shifted value indices are tuple consisting of an index into the prover's runtime-dependent data, a shift type , and a shift amount .
An AND constraint, by definition, is three lists of shifted value indices, say . We say that the AND constraint holds with respect to candidate prover data if and only if:
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 of AND constraints; it will moreover supply triples of the form already given above, for . We will say that the prover data fulfills the constraint system's AND constraints if and only if for each , the above equality holds over with respect to the th triple .
The Constraint Arrays
We now apply the constraint array formalism to this condition. Applying it, we get arrays , and , containing 64-bit words, defined by the equalities:
Having defined these arrays, we can now say that our constraint system's AND constraints are fulfilled if and only if
holds for each .
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 and .
In order to constrain that a wire equals the bitwise XOR of wires and , we can add a constraint to the effect of
x ⊕ y & 0xFFFFFFFFFFFFFFFF = z.
Bitwise NOT is similar; to obtain a wire , we can constrain
x & 0xFFFFFFFFFFFFFFFF = y ⊕ 0xFFFFFFFFFFFFFFFF.
Since is equivalent to , we can use
x ⊕ 0xFFFFFFFFFFFFFFFF & y ⊕ 0xFFFFFFFFFFFFFFFF = z ⊕ 0xFFFFFFFFFFFFFFFF
to get bitwise OR. Alternatively, the expression
x & y = x ⊕ y ⊕ z
also works.