Multiplexing
MANDATORY use of the first party conditional signal selector. Do not skip!
For a detailed explanation on why you *need* to use multiplexers, visit the Circom Language > Conditional Statements section:
Conditional StatementsConventions
Given N
in a gadget MuxN
, you can consider the multiplexer to have the following properties:
N
selectors used to to toggle between signals2^n
possible input signals
There will always be a single output signal. Given the overwhelming need for Mux1()
for general computation where higher order multiplexers are niche, the rest of the section will only consider the use of a 2 input multiplexer. As mentioned in the Conditional Statements section, use of higher order multiplexers could facilitate the need for something like a switch case.
Mux1
There has been a lot of use of multiplexers around this GitBook, so we will keep this example short and to the point. At the risk of beating a dead horse, we want to reiterate that MUX1 IS A REQUIREMENT FOR COMPUTING BINARY CONDITIONAL LOGIC IN CIRCOM.
The mux1.circom
component provides a relatively simple interface for a developer to input two signals and return one or the other based on a boolean condition (selector). In order to avoid non-quadratic expressions as cryptically explained in the official Circom docs, a developer using the Circom DSL must entirely compute both branches to their resulting end signal value, then use the multiplexer to toggle between the two signals based on a specific case. The component is shown below:
This simple gadget can quickly be extended in your code base to facilitate most branching logical conclusions as is expected of a turing-complete programming language. For instance, BattleZips V1 makes use of a multiplexer to choose between the horizontal and vertical axis when compute whether a shot intersects with a ship placement. This is shown in the helper hitShip.circom
component:
Consider the goal of having ships that can be placed either horizontally or vertically. Given the carrier ship (length 5, 0th index in 5-tuple) placed vertically on the board at (7, 7). This data can be represented as a 3-tuple (x, y, z) where the order inclusion of the ship 3-tuple in the board 5-tuple (see Examples > BattleZips V1) encodes the length of the ship.
The placeShip.circom
code computes whether or not a ship placement is legal according to our own (arbitrarily defined to our needs) rules. In the BattleZip rule set, ignoring the concept of ship collisions, all cells covered by a ship placement must be within the 10x10 grid. Therefore, situations like the above diagram arise.
As is shown in placeShip.circom
or hitShip.circom
, we compute both the horizontal and vertical collision and boundary checks. At /// MUX TO CHOOSE OUTPUT ///
the z
coordinate for the ship placement is used as the Mux1()
selector, properly outputting the signal that passes constraints while discarding the signal that fails. Of course, we expect this property to hold in the reverse direction as well, constraining proof generation based on the z axis.
The BattleZips V1 circom-tester test/circuits.js
unit testing proves the intended functionality of using Mux1()
in shot proofs for horizontal/ verital ship orientation:
Intra-Circuit Incremental State Building
"Intra-Circuit Incremental State Building" is quite verbose. Put more directly:
Iterative/ loop over data repeatedly with potentially different parameters each time
Mutate stored state each time such that a new loop's beginning picks up where previous loop left off
All computation is contained within a main component (top level ZK circuit)
Beyond the z
axis orientation multiplexer, Mux1()
is the interface by which conditional state updates computed in Zero Knowledge are communicated between iterations of the placeShip.circom
component. Consider the snippet of this component where the two conditions are computed and then multiplexed:
Given the board placement computations above, the last "paragraph" of the circuit handles the conditional selection of the horizontal or vertical board signal as generated in a 10x10 variable array, encoded by Bits2Num. Using the multiplexer, we are able to witness a conditional commitment to some encoded piece of data, then work with that new state on the next loop/ increment.
Last updated