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(&quotient_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}