Skip to content

Commit 43cc888

Browse files
Refactor compute_deep_composition_poly function (#200)
* [WIP] Deep FRI * Finish implementation * Document code * Fix vulnerability tests and add more * Define basic traits and structs for Air * Write basic skeleton of ConstraintEvaluator * Save evaluator progress * Complete evaluator basic methods * Fix some compilation errors * Finish method for computing composition poly from Evaluation Table * More fixes * More progress * Comment out tests * [WIP] Implement verifier * Debugging stuff * Remove debugging stuff as the boundary ood evaluation was correct * Uncomment important line * Start compute_deep_composition_poly refactor * Finish compute_deep_composition_poly refactor * Refactor trace function to take the length as a parameter * Fix hardcoded boundary poly degree on verifier * Some fixes * Fix transition_divisors implementation * Fix transition_divisor once more * Fix calculation of trace primitive root on the verifier * Test finally working * Remove unusued num_assertions field * [WIP] fiat-shamir integration * Comment transcript.append line in fri function * Fix fiat-shamir integration bugs * Fix boundaryconstraints zerofier test * Fix clippy suggestiojns * Remove outdated comments * Rename compute_transition_evaluations * Add Fibonacci AIR test for a 17 finite field * Save refactor WIP * Refactor compute_deep_composition_poly to generalize for a trace with more than one column * Add comments to dummy transcript challenge calls in verifier * Use a better variable name * Remove debug comment * Add comments and documentation * Fix typo --------- Co-authored-by: Javier Chatruc <[email protected]>
1 parent 7bfc8e9 commit 43cc888

File tree

6 files changed

+100
-56
lines changed

6 files changed

+100
-56
lines changed

proving_system/stark/src/air/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
pub struct AirContext {
33
pub options: ProofOptions,
44
pub trace_length: usize,
5-
pub trace_info: (usize, usize),
5+
pub trace_columns: usize,
66
pub transition_degrees: Vec<usize>,
77
/// This is a vector with the indices of all the rows that constitute
88
/// an evaluation frame. Note that, because of how we write all constraints

proving_system/stark/src/air/frame.rs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,31 @@ impl<F: IsField> Frame<F> {
5252
Self::new(data, 1)
5353
}
5454

55+
/// Given a slice of trace polynomials, an evaluation point `x`, the frame offsets
56+
/// corresponding to the computation of the transitions, and a primitive root,
57+
/// outputs the trace evaluations of each trace polynomial over the values used to
58+
/// compute a transition.
59+
/// Example: For a simple Fibonacci computation, if t(x) is the trace polynomial of
60+
/// the computation, this will output evaluations t(x), t(g * x), t(g^2 * z).
61+
pub fn get_trace_evaluations(
62+
trace_polys: &[Polynomial<FieldElement<F>>],
63+
x: &FieldElement<F>,
64+
frame_offsets: &[usize],
65+
primitive_root: &FieldElement<F>,
66+
) -> Vec<Vec<FieldElement<F>>> {
67+
let mut evaluations = Vec::with_capacity(trace_polys.len());
68+
let evaluation_points: Vec<FieldElement<F>> = frame_offsets
69+
.iter()
70+
.map(|offset| x * primitive_root.pow(*offset))
71+
.collect();
72+
73+
trace_polys
74+
.iter()
75+
.for_each(|p| evaluations.push(p.evaluate_slice(&evaluation_points)));
76+
77+
evaluations
78+
}
79+
5580
/// Returns the Out of Domain Frame for the given trace polynomials, out of domain evaluation point (called `z` in the literature),
5681
/// frame offsets given by the AIR and primitive root used for interpolating the trace polynomials.
5782
/// An out of domain frame is nothing more than the evaluation of the trace polynomials in the points required by the
@@ -65,15 +90,7 @@ impl<F: IsField> Frame<F> {
6590
frame_offsets: &[usize],
6691
primitive_root: &FieldElement<F>,
6792
) -> Self {
68-
let mut data = vec![];
69-
let evaluation_points: Vec<FieldElement<F>> = frame_offsets
70-
.iter()
71-
.map(|offset| z * primitive_root.pow(*offset))
72-
.collect();
73-
74-
for poly in trace_polys {
75-
data.push(poly.evaluate_slice(&evaluation_points));
76-
}
93+
let data = Self::get_trace_evaluations(trace_polys, z, frame_offsets, primitive_root);
7794

7895
Self {
7996
data: data.into_iter().flatten().collect(),

proving_system/stark/src/air/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,7 @@ pub trait AIR: Clone {
2828
fn blowup_factor(&self) -> u8 {
2929
self.options().blowup_factor
3030
}
31+
fn num_transition_constraints(&self) -> usize {
32+
self.context().num_transition_constraints
33+
}
3134
}

proving_system/stark/src/lib.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ mod tests {
8585
#[test]
8686
fn test_prove_fib() {
8787
let trace = fibonacci_trace([FE::from(1), FE::from(1)], 4);
88+
let trace_table = TraceTable {
89+
table: trace.clone(),
90+
num_cols: 1,
91+
};
8892

8993
let context = AirContext {
9094
options: ProofOptions {
@@ -93,18 +97,13 @@ mod tests {
9397
coset_offset: 3,
9498
},
9599
trace_length: trace.len(),
96-
trace_info: (trace.len(), 1),
100+
trace_columns: trace_table.num_cols,
97101
transition_degrees: vec![1],
98102
transition_exemptions: vec![trace.len() - 2, trace.len() - 1],
99103
transition_offsets: vec![0, 1, 2],
100104
num_transition_constraints: 1,
101105
};
102106

103-
let trace_table = TraceTable {
104-
table: trace.clone(),
105-
num_cols: 1,
106-
};
107-
108107
let fibonacci_air = FibonacciAIR::new(trace_table, context);
109108

110109
let result = prove(&trace, &fibonacci_air);
@@ -116,25 +115,25 @@ mod tests {
116115
fn test_prove_fib17() {
117116
let trace = fibonacci_trace([FE17::new(1), FE17::new(1)], 4);
118117

118+
let trace_table = TraceTable {
119+
table: trace.clone(),
120+
num_cols: 1,
121+
};
122+
119123
let context = AirContext {
120124
options: ProofOptions {
121125
blowup_factor: 2,
122126
fri_number_of_queries: 1,
123127
coset_offset: 3,
124128
},
125129
trace_length: trace.len(),
126-
trace_info: (trace.len(), 1),
130+
trace_columns: trace_table.num_cols,
127131
transition_degrees: vec![1],
128132
transition_exemptions: vec![trace.len() - 2, trace.len() - 1],
129133
transition_offsets: vec![0, 1, 2],
130134
num_transition_constraints: 1,
131135
};
132136

133-
let trace_table = TraceTable {
134-
table: trace.clone(),
135-
num_cols: 1,
136-
};
137-
138137
let fibonacci_air = Fibonacci17AIR::new(trace_table, context);
139138

140139
let result = prove(&trace, &fibonacci_air);

proving_system/stark/src/prover.rs

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use lambdaworks_math::{
44
element::FieldElement,
55
traits::{IsField, IsTwoAdicField},
66
},
7-
polynomial::{self, Polynomial},
7+
polynomial::Polynomial,
88
traits::ByteConversion,
99
};
1010

@@ -97,11 +97,13 @@ where
9797

9898
// Compute DEEP composition polynomial so we can commit to it using FRI.
9999
let mut deep_composition_poly = compute_deep_composition_poly(
100-
&trace_poly,
100+
air,
101+
&[trace_poly],
101102
&composition_poly_even,
102103
&composition_poly_odd,
103104
&z,
104105
&trace_primitive_root,
106+
transcript,
105107
);
106108

107109
// * Do FRI on the composition polynomials
@@ -118,7 +120,7 @@ where
118120

119121
for _i in 0..air.context().options.fri_number_of_queries {
120122
// * Sample q_1, ..., q_m using Fiat-Shamir
121-
let q_i: usize = transcript_to_usize(transcript) % 2_usize.pow(lde_root_order);
123+
let q_i = transcript_to_usize(transcript) % 2_usize.pow(lde_root_order);
122124
transcript.append(&q_i.to_be_bytes());
123125

124126
// * For every q_i, do FRI decommitment
@@ -146,52 +148,63 @@ where
146148
/// Returns the DEEP composition polynomial that the prover then commits to using
147149
/// FRI. This polynomial is a linear combination of the trace polynomial and the
148150
/// composition polynomial, with coefficients sampled by the verifier (i.e. using Fiat-Shamir).
149-
fn compute_deep_composition_poly<F: IsField>(
150-
trace_poly: &Polynomial<FieldElement<F>>,
151+
fn compute_deep_composition_poly<A: AIR, F: IsField>(
152+
air: &A,
153+
trace_polys: &[Polynomial<FieldElement<F>>],
151154
even_composition_poly: &Polynomial<FieldElement<F>>,
152155
odd_composition_poly: &Polynomial<FieldElement<F>>,
153156
ood_evaluation_point: &FieldElement<F>,
154157
primitive_root: &FieldElement<F>,
158+
transcript: &mut Transcript,
155159
) -> Polynomial<FieldElement<F>> {
156-
// TODO: Fiat-Shamir
157-
let gamma_1 = FieldElement::one();
158-
let gamma_2 = FieldElement::one();
159-
let gamma_3 = FieldElement::one();
160-
let gamma_4 = FieldElement::one();
161-
162-
let first_term = (trace_poly.clone()
163-
- Polynomial::new_monomial(trace_poly.evaluate(ood_evaluation_point), 0))
164-
/ (Polynomial::new_monomial(FieldElement::one(), 1)
165-
- Polynomial::new_monomial(ood_evaluation_point.clone(), 0));
166-
let second_term = (trace_poly.clone()
167-
- Polynomial::new_monomial(
168-
trace_poly.evaluate(&(ood_evaluation_point * primitive_root)),
169-
0,
170-
))
171-
/ (Polynomial::new_monomial(FieldElement::one(), 1)
172-
- Polynomial::new_monomial(ood_evaluation_point * primitive_root, 0));
160+
let transition_offsets = air.context().transition_offsets;
161+
162+
// Get the number of trace terms the DEEP composition poly will have.
163+
// One coefficient will be sampled for each of them.
164+
let n_trace_terms = transition_offsets.len() * trace_polys.len();
165+
let mut trace_term_coeffs = Vec::with_capacity(n_trace_terms);
166+
for _ in 0..n_trace_terms {
167+
trace_term_coeffs.push(transcript_to_field::<F>(transcript));
168+
}
173169

174-
// Evaluate in X^2
175-
let even_composition_poly = polynomial::compose(
176-
even_composition_poly,
177-
&Polynomial::new_monomial(FieldElement::one(), 2),
178-
);
179-
let odd_composition_poly = polynomial::compose(
180-
odd_composition_poly,
181-
&Polynomial::new_monomial(FieldElement::one(), 2),
170+
// Get coefficients for even and odd terms of the composition polynomial H(x)
171+
let gamma_even = transcript_to_field::<F>(transcript);
172+
let gamma_odd = transcript_to_field::<F>(transcript);
173+
174+
// Get trace evaluations needed for the trace terms of the deep composition polynomial
175+
let trace_evaluations = Frame::get_trace_evaluations(
176+
trace_polys,
177+
ood_evaluation_point,
178+
&transition_offsets,
179+
primitive_root,
182180
);
183181

184-
let third_term = (even_composition_poly.clone()
182+
// Compute all the trace terms of the deep composition polynomial. There will be one
183+
// term for every trace polynomial and every trace evaluation.
184+
let mut trace_terms = Polynomial::zero();
185+
for (trace_evaluation, trace_poly) in trace_evaluations.iter().zip(trace_polys) {
186+
for (eval, coeff) in trace_evaluation.iter().zip(&trace_term_coeffs) {
187+
let poly = (trace_poly.clone()
188+
- Polynomial::new_monomial(trace_poly.evaluate(eval), 0))
189+
/ (Polynomial::new_monomial(FieldElement::<F>::one(), 1)
190+
- Polynomial::new_monomial(eval.clone(), 0));
191+
192+
trace_terms = trace_terms + poly * coeff.clone();
193+
}
194+
}
195+
196+
let even_composition_poly_term = (even_composition_poly.clone()
185197
- Polynomial::new_monomial(
186198
even_composition_poly.evaluate(&ood_evaluation_point.clone()),
187199
0,
188200
))
189201
/ (Polynomial::new_monomial(FieldElement::one(), 1)
190202
- Polynomial::new_monomial(ood_evaluation_point * ood_evaluation_point, 0));
191-
let fourth_term = (odd_composition_poly.clone()
203+
204+
let odd_composition_poly_term = (odd_composition_poly.clone()
192205
- Polynomial::new_monomial(odd_composition_poly.evaluate(ood_evaluation_point), 0))
193206
/ (Polynomial::new_monomial(FieldElement::one(), 1)
194207
- Polynomial::new_monomial(ood_evaluation_point * ood_evaluation_point, 0));
195208

196-
first_term * gamma_1 + second_term * gamma_2 + third_term * gamma_3 + fourth_term * gamma_4
209+
trace_terms + even_composition_poly_term * gamma_even + odd_composition_poly_term * gamma_odd
197210
}

proving_system/stark/src/verifier.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,18 @@ where
116116
let lde_root_order =
117117
(air.context().trace_length * air.options().blowup_factor as usize).trailing_zeros();
118118

119+
// We have to make the call to `transcript.challenge()` a number of times since we need
120+
// the transcript to be in the same state as the one in the prover at this stage.
121+
// The prover samples coefficients when building the deep composition polynomial. These
122+
// sampling is not done in the verifier hence we need to make this dummy calls.
123+
// There will be one call for each trace term in the deep composition polynomial + 2 from
124+
// the even and odd terms of the H(x) polynomial.
125+
let deep_poly_challenges =
126+
air.context().transition_offsets.len() * air.context().trace_columns + 2;
127+
(0..deep_poly_challenges).for_each(|_| {
128+
transcript.challenge();
129+
});
130+
119131
// construct vector of betas
120132
let mut beta_list = Vec::new();
121133
let count_betas = proof.fri_layers_merkle_roots.len() - 1;
@@ -137,7 +149,7 @@ where
137149
let last_evaluation_bytes = last_evaluation.to_bytes_be();
138150
transcript.append(&last_evaluation_bytes);
139151

140-
let q_i: usize = transcript_to_usize(transcript) % (2_usize.pow(lde_root_order));
152+
let q_i = transcript_to_usize(transcript) % (2_usize.pow(lde_root_order));
141153
transcript.append(&q_i.to_be_bytes());
142154

143155
let fri_decommitment = &proof_i.fri_decommitment;

0 commit comments

Comments
 (0)