Figure 1: Prover workflow: Constraints
C
to our spreadsheet that computes the product of the previous columns plus the first column.
We can set C1
as A1 * B1 + A1
.
In the same vein, we can create a new column in our table that computes the sum of the two previous columns.
And we can constrain the value of the third column by creating an equation that must equal 0: col1_row1 * col2_row1 + col1_row1 - col3_row1 = 0
.
Figure 2: Proving spreadsheet functions as constraints
col1_row1 * col2_row1 + col1_row1 - col3_row1 = 0
becomes .
col_3
that contains the result of the computation: col_1 * col_2 + col_1
.
Then, to create a constraint over the trace polynomials, we first create a TestEval
struct that implements the FrameworkEval
trait.
Then, we add our constraint logic in the FrameworkEval::evaluate
function.
Note that this function is called for every row in the table, so we only need to define the constraint once.
Inside FrameworkEval::evaluate
, we call eval.next_trace_mask()
consecutively three times, retrieving the cell values of all three columns.
Once we retrieve all three column values, we add a constraint of the form col_1 * col_2 + col_1 - col_3
, which should equal 0.
Figure 3: Evaluate function
FrameworkEval::max_constraint_log_degree_bound(&self)
for FrameworkEval
.
As mentioned in the Composition Polynomial section, we need to expand the trace polynomial evaluations because the degree of our composition polynomial is higher than the trace polynomial.
Expanding it by the lowest value CONSTRAINT_EVAL_BLOWUP_FACTOR=1
is sufficient for our example as the degree of our composition polynomial is not very high, so we can return self.log_size + CONSTRAINT_EVAL_BLOWUP_FACTOR
.
For those who are interested in how to set this value in general, we leave a detailed note below.
max_constraint_log_degree_bound(&self)
?self.log_size + max(1, ceil(log2(max_degree - 1)))
, where max_degree
is the maximum degree of all defined constraint polynomials.e.g.self.log_size + 1
self.log_size + 2
self.log_size + 3
self.log_size + 4
log_size
of the domain set to log_num_rows + CONSTRAINT_EVAL_BLOWUP_FACTOR + config.fri_config.log_blowup_factor
here?
Once we have the composition polynomial, we need to expand it again for before committing to it for the FRI step.
Thus, the maximum size of the domain that we need in the entire proving process is the FRI blow-up factor times the degree of the composition polynomial.TestEval
struct, we can create a new FrameworkComponent::<TestEval>
component, which the prover will use to evaluate the constraint.
For now, we can ignore the other parameters of the FrameworkComponent::<TestEval>
constructor.
We now move on to the final section where we finally create and verify a proof.