Basic Math Constraints
Constraining validity of basic logical and arithmetic computations made in zero knowledge
You can perform basic arithmetic operations as expected to variables in the Circom language. However, ensuring the circuit constrains execution according to a specified calculation with target signal values requires boilerplate code. The following libraries provide the patterns you need to accomplish these goals.
Logical gates are, according to Wikipedia:
an idealized or physical device implementing a Boolean function, a logical operation performed on one or more binary inputs that produces a single binary output.
An in exhaustive list of gate operands you may be used to: ||
, &&
, !
You would extend one of the gates.circom
components when you want to constrain the circuit to only generate a valid proof if one of these logical assertions holds true. For instance, take the OR()
component:
By using the OR()
component, we assume a
and b
input signals are binary. We can use the out
ouput signal with confidence that it is a constrained binary evaluation of the ||
operator.
We can see the implementation of the OR()
gate component in shot.circom
from the BattleZips V1 codebase (abridged):
In this snippet, in our shot proof we are checking whether or not the publicly inputted shot
x/y coordinate pair collides with the privately inputted board arrangement (specifically the first and second ships). circomlib did not include a MultiOR()
as it does with MultiAND()
so we four OR()
components together to reach a single boolean value representing whether or not any ships collide with the shot.
Wikipedia defines a comparator as a function:
that takes two numbers as input in binary form and determines whether one number is greater than, less than or equal to the other number
An in exhaustive list of gate operands you may be used to: >=
, ==
, !=
, >
For example, let us take the toggled equality comparator component ForceEqualIfEnabled()
(which relies on the simple IsZero()
comparator component):
We can see the implementation of ForceEqualIfEnabled()
in if_gadgets.circom
in the BattleZips RollupNC repository via IfBothHighForceEqualEnabled()
:
IfHighForceEqualIfEnabled()
in RollupNC demonstrates constrained conditional computation and evaluation of state by an equality comparator.
A "high" signal value is a value >= 1. In the context of RollupNC, update_state_verifier.circom
contains a check if a transaction's send and receipt token type are the same or not. I
If
toTokenType
andfromTokenType
are equal, debit fromto
and credit tofrom
If
fromTokenType
is 0, debit fromto
but do not debit from burn addressIf
from
is not0x00
address orfromTokenType
is not 0 and does not matchtoTokenType
, fail verification at unrelated point
For many reasons, you may need to access the bits that compose an integer value contained in a signal. In low level cryptographic applications this can be seen in the eddsa.circom
template:
This may be incredibly confusing, but that is okay! Using the circomlibjs library abstracts away the worst of the cryptographic expertise needed. Alternatively, lets look at another simple use-case for num2bits in the BattleZips V1 placeShip.circom
component used in the main board.circom
componnt (abridged to only show state change basics):
In the Solidity verifier contract generated for you by SnarkJS, each additional input incurs additional gas cost in the EVM. This demonstrates a straight-forward use of the bitify.circom
component file to accomplish state computation in Zero Knowledge as effectively as presently possible given these tools.
Last updated