winter_air/proof/ood_frame.rs
1// Copyright (c) Facebook, Inc. and its affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6use alloc::vec::Vec;
7
8use math::FieldElement;
9use utils::{
10 ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, SliceReader,
11};
12
13use crate::EvaluationFrame;
14
15// OUT-OF-DOMAIN FRAME
16// ================================================================================================
17
18/// Trace and constraint polynomial evaluations at an out-of-domain point.
19///
20/// This struct contains the following evaluations:
21/// * Evaluations of all trace polynomials at *z*.
22/// * Evaluations of all trace polynomials at *z * g*.
23/// * Evaluations of constraint composition column polynomials at *z*.
24/// * Evaluations of constraint composition column polynomials at *z * g*.
25///
26/// where *z* is an out-of-domain point and *g* is the generator of the trace domain.
27///
28/// Internally, the evaluations are stored as a sequence of bytes. Thus, to retrieve the
29/// evaluations, [parse()](OodFrame::parse) function should be used.
30#[derive(Clone, Debug, Default, Eq, PartialEq)]
31pub struct OodFrame {
32 trace_states: Vec<u8>,
33 quotient_states: Vec<u8>,
34}
35
36impl OodFrame {
37 // UPDATERS
38 // --------------------------------------------------------------------------------------------
39
40 /// Updates the trace state portion of this out-of-domain frame.
41 ///
42 /// The out-of-domain frame is stored as one vector built from the concatenation of values of
43 /// two vectors, the current row vector and the next row vector. Given the input frame
44 ///
45 /// +-------+-------+-------+-------+-------+-------+-------+-------+
46 /// | a1 | a2 | ... | an | c1 | c2 | ... | cm |
47 /// +-------+-------+-------+-------+-------+-------+-------+-------+
48 /// | b1 | b2 | ... | bn | d1 | d2 | ... | dm |
49 /// +-------+-------+-------+-------+-------+-------+-------+-------+
50 ///
51 /// with n being the main trace width and m the auxiliary trace width, the values are stored as
52 ///
53 /// [a1, ..., an, c1, ..., cm, b1, ..., bn, d1, ..., dm]
54 ///
55 /// into `Self::trace_states` (as byte values).
56 ///
57 /// # Panics
58 /// Panics if evaluation frame has already been set.
59 pub fn set_trace_states<E>(&mut self, trace_ood_frame: &TraceOodFrame<E>)
60 where
61 E: FieldElement,
62 {
63 assert!(self.trace_states.is_empty(), "trace sates have already been set");
64
65 // save the evaluations of the current and then next evaluations for each polynomial
66 let main_and_aux_trace_states = trace_ood_frame.to_trace_states();
67
68 // there are 2 frames: current and next
69 let frame_size: u8 = 2;
70 self.trace_states.write_u8(frame_size);
71 self.trace_states.write_many(&main_and_aux_trace_states);
72 }
73
74 /// Updates constraints composition polynomials (i.e., quotient polynomials) state portion of
75 /// this out-of-domain frame.
76 ///
77 /// The out-of-domain frame is stored as one vector built from the concatenation of values of
78 /// two vectors, the current row vector and the next row vector. Given the input frame
79 ///
80 /// +-------+-------+-------+-------+-------+-------+-------+-------+
81 /// | a1 | a2 | ... | ... | ... | ... | ... | an |
82 /// +-------+-------+-------+-------+-------+-------+-------+-------+
83 /// | b1 | b2 | ... | ... | ... | ... | ... | bn |
84 /// +-------+-------+-------+-------+-------+-------+-------+-------+
85 ///
86 /// with n being the number of constraints composition polynomials, the values are stored as
87 ///
88 /// [a1, ..., an, b1, ..., bn]
89 ///
90 /// into `Self::quotient_states` (as byte values).
91 ///
92 /// # Panics
93 /// Panics if:
94 /// * Constraint evaluations have already been set.
95 pub fn set_quotient_states<E>(&mut self, quotients_ood_frame: &QuotientOodFrame<E>)
96 where
97 E: FieldElement,
98 {
99 assert!(self.quotient_states.is_empty(), "constraint evaluations have already been set");
100
101 // save the the current evaluations and then next evaluations for each quotient polynomial
102 let quotient_states = quotients_ood_frame.to_trace_states();
103
104 // there are 2 frames: current and next
105 let frame_size: u8 = 2;
106 self.quotient_states.write_u8(frame_size);
107 self.quotient_states.write_many("ient_states);
108 }
109
110 // PARSER
111 // --------------------------------------------------------------------------------------------
112 /// Returns an out-of-domain trace frame and an out-of-domain constraints evaluations frame.
113 /// contained in `self`.
114 ///
115 /// # Panics
116 /// Panics if either `main_trace_width` or `num_evaluations` are equal to zero.
117 ///
118 /// # Errors
119 /// Returns an error if:
120 /// * Valid [`TraceOodFrame`]s for the specified `main_trace_width` and `aux_trace_width`
121 /// could not be parsed from the internal bytes.
122 /// * Valid [`QuotientOodFrame`]s for the specified `num_quotients` could not be parsed
123 /// from the internal bytes.
124 /// * Any unconsumed bytes remained after the parsing was complete.
125 pub fn parse<E: FieldElement>(
126 self,
127 main_trace_width: usize,
128 aux_trace_width: usize,
129 num_quotients: usize,
130 ) -> Result<(TraceOodFrame<E>, QuotientOodFrame<E>), DeserializationError> {
131 assert!(main_trace_width > 0, "trace width cannot be zero");
132 assert!(num_quotients > 0, "number of evaluations cannot be zero");
133
134 // parse main and auxiliary trace evaluation frames. This does the reverse operation done in
135 // `set_trace_states()`.
136 let (trace_current_row, trace_next_row) = {
137 let mut reader = SliceReader::new(&self.trace_states);
138 let frame_size = reader.read_u8()? as usize;
139 assert_eq!(frame_size, 2);
140 let mut trace = reader.read_many((main_trace_width + aux_trace_width) * frame_size)?;
141
142 if reader.has_more_bytes() {
143 return Err(DeserializationError::UnconsumedBytes);
144 }
145
146 let next_row = trace.split_off(main_trace_width + aux_trace_width);
147 let current_row = trace;
148 (current_row, next_row)
149 };
150
151 // parse the constraint evaluations. This does the reverse operation done in
152 // `set_quotient_states()`.
153 let (quotients_current_row, quotients_next_row) = {
154 let mut reader = SliceReader::new(&self.quotient_states);
155 let frame_size = reader.read_u8()? as usize;
156 assert_eq!(frame_size, 2);
157 let mut quotients_evaluations = reader.read_many(num_quotients * frame_size)?;
158
159 if reader.has_more_bytes() {
160 return Err(DeserializationError::UnconsumedBytes);
161 }
162
163 let quotients_next_row = quotients_evaluations.split_off(num_quotients);
164 let quotients_current_row = quotients_evaluations;
165 (quotients_current_row, quotients_next_row)
166 };
167
168 Ok((
169 TraceOodFrame::new(trace_current_row, trace_next_row, main_trace_width),
170 QuotientOodFrame::new(quotients_current_row, quotients_next_row),
171 ))
172 }
173}
174
175// SERIALIZATION
176// ================================================================================================
177
178impl Serializable for OodFrame {
179 /// Serializes `self` and writes the resulting bytes into the `target`.
180 fn write_into<W: ByteWriter>(&self, target: &mut W) {
181 // write trace rows
182 target.write_u16(self.trace_states.len() as u16);
183 target.write_bytes(&self.trace_states);
184
185 // write constraint evaluations row
186 target.write_u16(self.quotient_states.len() as u16);
187 target.write_bytes(&self.quotient_states)
188 }
189
190 /// Returns an estimate of how many bytes are needed to represent self.
191 fn get_size_hint(&self) -> usize {
192 self.trace_states.len() + self.quotient_states.len() + 4
193 }
194}
195
196impl Deserializable for OodFrame {
197 /// Reads a OOD frame from the specified `source` and returns the result
198 ///
199 /// # Errors
200 /// Returns an error of a valid OOD frame could not be read from the specified `source`.
201 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
202 // read trace rows
203 let num_trace_state_bytes = source.read_u16()? as usize;
204 let trace_states = source.read_vec(num_trace_state_bytes)?;
205
206 // read constraint evaluations row
207 let num_constraint_evaluation_bytes = source.read_u16()? as usize;
208 let evaluations = source.read_vec(num_constraint_evaluation_bytes)?;
209
210 Ok(OodFrame {
211 trace_states,
212 quotient_states: evaluations,
213 })
214 }
215}
216
217// OOD FRAME TRACE STATES
218// ================================================================================================
219
220/// Trace evaluation frame at the out-of-domain point.
221///
222/// Stores the trace evaluations at `z` and `gz`, where `z` is a random Field element in
223/// `current_row` and `next_row`, respectively.
224pub struct TraceOodFrame<E: FieldElement> {
225 current_row: Vec<E>,
226 next_row: Vec<E>,
227 main_trace_width: usize,
228}
229
230impl<E: FieldElement> TraceOodFrame<E> {
231 /// Creates a new [`TraceOodFrame`] from current, next.
232 pub fn new(current_row: Vec<E>, next_row: Vec<E>, main_trace_width: usize) -> Self {
233 assert_eq!(current_row.len(), next_row.len());
234
235 Self { current_row, next_row, main_trace_width }
236 }
237
238 /// Returns the number of columns for the current and next frames.
239 pub fn num_columns(&self) -> usize {
240 self.current_row.len()
241 }
242
243 /// Returns the current row, consisting of both main and auxiliary columns.
244 pub fn current_row(&self) -> &[E] {
245 &self.current_row
246 }
247
248 /// Returns the next frame, consisting of both main and auxiliary columns.
249 pub fn next_row(&self) -> &[E] {
250 &self.next_row
251 }
252
253 /// Returns the evaluation frame for the main trace
254 pub fn main_frame(&self) -> EvaluationFrame<E> {
255 let current = self.current_row[0..self.main_trace_width].to_vec();
256 let next = self.next_row[0..self.main_trace_width].to_vec();
257
258 EvaluationFrame::from_rows(current, next)
259 }
260
261 /// Returns the evaluation frame for the auxiliary trace
262 pub fn aux_frame(&self) -> Option<EvaluationFrame<E>> {
263 if self.has_aux_frame() {
264 let current = self.current_row[self.main_trace_width..].to_vec();
265 let next = self.next_row[self.main_trace_width..].to_vec();
266
267 Some(EvaluationFrame::from_rows(current, next))
268 } else {
269 None
270 }
271 }
272
273 /// Returns true if an auxiliary frame is present
274 fn has_aux_frame(&self) -> bool {
275 self.current_row.len() > self.main_trace_width
276 }
277
278 /// Returns the main/aux frames as a vector of elements described in
279 /// [`OodFrame::set_trace_states`].
280 pub fn to_trace_states(&self) -> Vec<E> {
281 let mut main_and_aux_frame_states = Vec::new();
282 main_and_aux_frame_states.extend_from_slice(&self.current_row);
283 main_and_aux_frame_states.extend_from_slice(&self.next_row);
284
285 main_and_aux_frame_states
286 }
287}
288
289// QUOTIENTS OOD FRAME
290// ================================================================================================
291
292/// Quotient polynomial evaluation frame at the out-of-domain points.
293///
294/// Stores the quotient polynomials evaluations at `z` and `g * z`, where `z` is a random Field
295/// element in `current_row` and `next_row`, respectively.
296pub struct QuotientOodFrame<E: FieldElement> {
297 current_row: Vec<E>,
298 next_row: Vec<E>,
299}
300
301impl<E: FieldElement> QuotientOodFrame<E> {
302 /// Creates a new [`QuotientOodFrame`] from current, next.
303 pub fn new(current_row: Vec<E>, next_row: Vec<E>) -> Self {
304 assert_eq!(current_row.len(), next_row.len());
305
306 Self { current_row, next_row }
307 }
308
309 /// Returns the current row.
310 pub fn current_row(&self) -> &[E] {
311 &self.current_row
312 }
313
314 /// Returns the next frame.
315 pub fn next_row(&self) -> &[E] {
316 &self.next_row
317 }
318
319 /// Returns the frame as a vector of elements.
320 pub fn to_trace_states(&self) -> Vec<E> {
321 let mut quotients_frame_states = Vec::new();
322 quotients_frame_states.extend_from_slice(&self.current_row);
323 quotients_frame_states.extend_from_slice(&self.next_row);
324
325 quotients_frame_states
326 }
327}
328
329// HELPER
330// ================================================================================================
331
332/// Given trace and constraints polynomials OOD evaluations, returns the vector containing their
333/// concatenation, with the evaluations at `z` grouped together and coming first and followed
334/// by the evaluations at `z * g`.
335pub fn merge_ood_evaluations<E>(
336 trace_ood_frame: &TraceOodFrame<E>,
337 constraints_ood_frame: &QuotientOodFrame<E>,
338) -> Vec<E>
339where
340 E: FieldElement,
341{
342 let mut current_row = trace_ood_frame.current_row().to_vec();
343 current_row.extend_from_slice(constraints_ood_frame.current_row());
344 let mut next_row = trace_ood_frame.next_row().to_vec();
345 next_row.extend_from_slice(constraints_ood_frame.next_row());
346
347 let mut ood_evals = current_row;
348 ood_evals.extend_from_slice(&next_row);
349
350 ood_evals
351}