Replies: 5 comments 2 replies
-
I think @mrmr1993 had some thoughts about using dynamic coefficients instead of increasing the degree of all of the gates. As an aside: what is the issue in increasing the degree of all the gates? I always have a hard time remembering. I think the poseidon gate is annoying because there's an Also, that's multiplied with the poseidon selector polynomial which is also of degree And multiplied with our new selector that'd be The degree of these polynomials impact two things:
My proposal shouldn't increase the domain size we need to handle the poseidon gate (or other gates) because we'd evaluate the new selector polynomial. For the same reason, it shouldn't increase the degree in (2). (This is effectively working in the same way as the poseidon selector polynomial not affecting both of these points.) |
Beta Was this translation helpful? Give feedback.
-
one question @mrmr1993 asked me is how to deal with the permutation. I can see two problems:
Here's an example that meets both problems (in some rust-like DSL): if cond {
x = x + 1
} else {
x = x + 2
}
Hope this example illustrates the issue.
solution to the first problem. I think there's two ways to tackle that problem, one over-engineered way would be to modify the permutation argument to cancel terms dynamically if they're in a non-active rows. I haven't thought much about that, but I don't think it's necessary. The easy solution is to simply write the expected values in the cells of non-active rows. That is, if a cell is wired to some cell in an active-row, just have that cell store the same value as the same in the active row. solution to the second problem. The problem can be solved in the same manner. If the output or the reassignment needs to be the value 6, for example, because that's what the active branch says; then the non-active branch can store the value 6 in the cell implicated in the output/reassignment. This might not be really clear, and I probably need to draw a diagram or do a better job at explaining what's happening, but basically the idea is to fill the non-active rows with values that make sense with what's happening in the active rows and the permutation (not values that make sense in the non-active rows). One problem I can imagine: there's a contradiction in the values we use to solve problem 1, and the values we use to solve problem 2. In other word, in the system of equations that we need to solve to fill the cells of the non-active rows (of the permutation columns) might not have a solution. Is this true in practice? I don't think so, or at least I can't find an example where this would be a problem. Worst case we have a solution that is not complete, and we can test it with a number of use-cases and see if we often run into issues like the one I described. |
Beta Was this translation helpful? Give feedback.
-
Interestingly, Noir also supports if/else statements, might be a good idea to see what they're doing there. |
Beta Was this translation helpful? Give feedback.
-
Another way is to make all the gate selector polynomials masked runtime polynomials. (Thanks to @mrmr1993 for the idea again) Let me explain using a fictive custom gate which has been assigned the selector polynomial Instead of multiplying the custom gate equation with We also apply the following constraints: This constraint makes sure that:
With this approach, we need to pay the cost of X additional |
Beta Was this translation helpful? Give feedback.
-
A not-so-well-thought-idea: maybe we don't need to use the permutation for
and add a constraint to ensure that it starts with the value 1 (similar to the permutation) |
Beta Was this translation helpful? Give feedback.
-
I find it annoying that I can't easily write if/else blocks, or even early returns. I think the notion of blocks/branches/control flow in PLONK would be really nice to have.
I drafted a documentation that talks about that here
I guess now that Github supports LaTex I should be able to copy/paste it here:
Control flow in PLONK
Problem: Circuits making use of branches (for example, using if/else and early returns) are notoriously hard to encode in PLONK.
Proposition: Introduce an extra control-flow witness
fg
to enable the notion of blocks (i.e. sets of continuous statements that are executed, or not).High-level explanation
We implement the special
fg
witness following 4 ideas.1.
fg
is multiplied to all gates. This is the main technique, which allows us to cancel rows that are not executed/ran during runtime (and thus we don't have to figure out a way to make them "work" when running the prover).2.$1$ ) or disabled ($0$ ) (TODO: is this necessary?)
fg
is constrained to be either a boolean. Blocks are either enabled (3.
fg
is constrained to be 1 for essential rows. At compile time, we ensure that we can constrain thefg
column to "activate" essential rows:x
inif x then ...
)We can do this by:
fg_selector
selector column at compile timefg_selector
tofg
must be enabledfg
) : $(\text{fg} - \text{fg_selector}) \cdot \text{fg_selector} = 0$4.
fg
's consistency is checked at runtime via the permutation argument. This is the second technique, this allows us to wire its values to the booleans cells (see 3)Control rows
When entering an if condition, a control row is created to enable or disable the associated block. That row simply stores the boolean in a register (and can constrain that it is a boolean).
When entering an if/else condition, two control rows are created to store both
cond
andnot_cond = 1 - cond
. Then wiring is used to constrainfg = cond
in rows associated to the first block andfg = not_cond
in rows associated to the second block.Note that early returns can be seen as an if/else. For example, the following pseudo code:
can be transpiled as:
Nested blocks
Nested blocks are also activated via control cells. A control cell for a nested block is constructed differently though: it is the
AND
bitwise operation of its own variable with all the parent control cells.For example, in the following pseudo-code:
the control cell
control_z
that representsz
must be constrained asAs such, if branch 1 is not taken, then both$0$ (as $0$ ).
control_y
andcontrol_z
will be constrained to bex
will beHow to apply the technique on the execution trace table
Here's a high-level diagram that shows how if/else and nested if/else work:
How does this change impact the protocol?
We added two things:
fg
.fg_selector
.Beta Was this translation helpful? Give feedback.
All reactions