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