Multiplexing
Multiplexing is a technique to select one of many signals based on a control signal. It is often used to switch between different signals or to select a signal based on a condition.
Mux1
template Mux1() {
signal input in[2];
signal input sel;
signal output out;
out <== (in[1] - in[0]) * sel + in[0];
}
Mux1
is actually the same circuit as IfElse
we defined in this section. Its just that the naming is a bit different, such that it is generalizable to higher multiplexers.
in[0]
isifFalse
in[1]
isifTrue
sel
iscond
out
isout
The main idea here is that in
has number of values equal to the number of bits of sel
, and out = in[sel]
.
Mux2
template Mux2() {
signal input in[4];
signal input sel[2];
signal output out;
// due to multiplication we need an auxiliary signal
signal sel_0_sel_1 <== sel[1] * sel[0];
signal a11 <== (in[3] - in[2] - in[1] + in[0]) * sel_0_sel_1;
signal a10 <== (in[2] - in[0]) * sel[1];
signal a01 <== (in[1] - in[0]) * sel[0];
signal a00 <== in[0];
out <== (a11 + a10 + a01 + a00);
}
Mux2
is a 2-bit multiplexer, which means it can select one of four inputs based on two control signals. The arithmetic above may look weird, but its actually simple to derive. Just think of the sel
cases in order (note that the bits are in little-endian):
sel = [0, 0]
: You needin[0]
here, and sincesel
multiplications will be 0, you needin[0]
added by default.sel = [1, 0]
: You needin[1]
, butin[0]
was added already as a constant so you needin[1] - in[0]
in total.sel = [0, 1]
: Similar to the previous case, you needin[2]
, butin[0]
was added already as a constant so you needin[2] - in[0]
in total.sel = [1, 1]
: You needin[3]
, but now we have all things from the previous cases added together, which is a total:in[0] + (in[1] - in[0]) + (in[2] - in[0])
. We need to addin[3]
and get rid of evertyhing else here, which gives usin[3] - in[2] - in[1] + in[0]
.
You can actually construct a
Mux2
using threeMux1
circuits.template Mux2() { signal input in[4]; signal input sel[2]; signal output out; signal inA <== Mux1()([in[0], in[1]], sel[0]); signal inB <== Mux1()([in[2], in[3]], sel[0]); out <== Mux1()([inA, inB], sel[1]); }
In fact, this has 3 non-linear constraints while the previous implementation has 4 non-linear constraints!
Larger Multiplexers
There are larger multiplexing circuits, e.g. Mux3
, Mux4
, etc. but we will not cover them here. You can construct them with a similar approach as we did for Mux2
, i.e. by using smaller multiplexers and combining them.