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///
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    evaluations: Vec<u8>,
34}
35
36impl OodFrame {
37    // UPDATERS
38    // --------------------------------------------------------------------------------------------
39
40    /// Updates the trace state portion of this out-of-domain frame, and returns the hash of the
41    /// trace states.
42    ///
43    /// The out-of-domain frame is stored as one vector built from the concatenation of values of
44    /// two vectors, the current row vector and the next row vector. Given the input frame
45    ///
46    ///    +-------+-------+-------+-------+-------+-------+-------+-------+
47    ///    |   a1  |   a2  |  ...  |  an   |  c1   |  c2   |  ...  |  cm   |
48    ///    +-------+-------+-------+-------+-------+-------+-------+-------+
49    ///    |   b1  |   b2  |  ...  |  bn   |  d1   |  d2   |  ...  |  dm   |
50    ///    +-------+-------+-------+-------+-------+-------+-------+-------+
51    ///
52    /// with n being the main trace width and m the auxiliary trace width, the values are stored as
53    ///
54    /// [a1, ..., an, c1, ..., cm, b1, ..., bn, d1, ..., dm]
55    ///
56    /// into `Self::trace_states` (as byte values).
57    ///
58    /// # Panics
59    /// Panics if evaluation frame has already been set.
60    pub fn set_trace_states<E, H>(&mut self, trace_ood_frame: &TraceOodFrame<E>) -> H::Digest
61    where
62        E: FieldElement,
63        H: ElementHasher<BaseField = E::BaseField>,
64    {
65        assert!(self.trace_states.is_empty(), "trace sates have already been set");
66
67        // save the evaluations of the current and then next evaluations for each polynomial
68        let main_and_aux_trace_states = trace_ood_frame.to_trace_states();
69
70        // there are 2 frames: current and next
71        let frame_size: u8 = 2;
72        self.trace_states.write_u8(frame_size);
73        self.trace_states.write_many(&main_and_aux_trace_states);
74
75        H::hash_elements(&main_and_aux_trace_states)
76    }
77
78    /// Updates constraint evaluation portion of this out-of-domain frame.
79    ///
80    /// # Panics
81    /// Panics if:
82    /// * Constraint evaluations have already been set.
83    /// * `evaluations` is an empty vector.
84    pub fn set_constraint_evaluations<E: FieldElement>(&mut self, evaluations: &[E]) {
85        assert!(self.evaluations.is_empty(), "constraint evaluations have already been set");
86        assert!(!evaluations.is_empty(), "cannot set to empty constraint evaluations");
87        self.evaluations.write_many(evaluations);
88    }
89
90    // PARSER
91    // --------------------------------------------------------------------------------------------
92    /// Returns an out-of-domain trace frame and a vector of out-of-domain constraint evaluations
93    /// contained in `self`.
94    ///
95    /// # Panics
96    /// Panics if either `main_trace_width` or `num_evaluations` are equal to zero.
97    ///
98    /// # Errors
99    /// Returns an error if:
100    /// * Valid [`crate::EvaluationFrame`]s for the specified `main_trace_width` and
101    ///   `aux_trace_width` could not be parsed from the internal bytes.
102    /// * A vector of evaluations specified by `num_evaluations` could not be parsed from the
103    ///   internal bytes.
104    /// * Any unconsumed bytes remained after the parsing was complete.
105    pub fn parse<E: FieldElement>(
106        self,
107        main_trace_width: usize,
108        aux_trace_width: usize,
109        num_evaluations: usize,
110    ) -> Result<(TraceOodFrame<E>, Vec<E>), DeserializationError> {
111        assert!(main_trace_width > 0, "trace width cannot be zero");
112        assert!(num_evaluations > 0, "number of evaluations cannot be zero");
113
114        // parse main and auxiliary trace evaluation frames. This does the reverse operation done in
115        // `set_trace_states()`.
116        let (current_row, next_row) = {
117            let mut reader = SliceReader::new(&self.trace_states);
118            let frame_size = reader.read_u8()? as usize;
119            let mut trace = reader.read_many((main_trace_width + aux_trace_width) * frame_size)?;
120
121            if reader.has_more_bytes() {
122                return Err(DeserializationError::UnconsumedBytes);
123            }
124
125            let next_row = trace.split_off(main_trace_width + aux_trace_width);
126            let current_row = trace;
127            (current_row, next_row)
128        };
129
130        // parse the constraint evaluations
131        let mut reader = SliceReader::new(&self.evaluations);
132        let evaluations = reader.read_many(num_evaluations)?;
133        if reader.has_more_bytes() {
134            return Err(DeserializationError::UnconsumedBytes);
135        }
136
137        Ok((TraceOodFrame::new(current_row, next_row, main_trace_width), evaluations))
138    }
139}
140
141// SERIALIZATION
142// ================================================================================================
143
144impl Serializable for OodFrame {
145    /// Serializes `self` and writes the resulting bytes into the `target`.
146    fn write_into<W: ByteWriter>(&self, target: &mut W) {
147        // write trace rows
148        target.write_u16(self.trace_states.len() as u16);
149        target.write_bytes(&self.trace_states);
150
151        // write constraint evaluations row
152        target.write_u16(self.evaluations.len() as u16);
153        target.write_bytes(&self.evaluations)
154    }
155
156    /// Returns an estimate of how many bytes are needed to represent self.
157    fn get_size_hint(&self) -> usize {
158        self.trace_states.len() + self.evaluations.len() + 4
159    }
160}
161
162impl Deserializable for OodFrame {
163    /// Reads a OOD frame from the specified `source` and returns the result
164    ///
165    /// # Errors
166    /// Returns an error of a valid OOD frame could not be read from the specified `source`.
167    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
168        // read trace rows
169        let num_trace_state_bytes = source.read_u16()? as usize;
170        let trace_states = source.read_vec(num_trace_state_bytes)?;
171
172        // read constraint evaluations row
173        let num_constraint_evaluation_bytes = source.read_u16()? as usize;
174        let evaluations = source.read_vec(num_constraint_evaluation_bytes)?;
175
176        Ok(OodFrame { trace_states, evaluations })
177    }
178}
179
180// OOD FRAME TRACE STATES
181// ================================================================================================
182
183/// Trace evaluation frame at the out-of-domain point.
184///
185/// Stores the trace evaluations at `z` and `gz`, where `z` is a random Field element in
186/// `current_row` and `next_row`, respectively.
187pub struct TraceOodFrame<E: FieldElement> {
188    current_row: Vec<E>,
189    next_row: Vec<E>,
190    main_trace_width: usize,
191}
192
193impl<E: FieldElement> TraceOodFrame<E> {
194    /// Creates a new [`TraceOodFrame`] from current, next.
195    pub fn new(current_row: Vec<E>, next_row: Vec<E>, main_trace_width: usize) -> Self {
196        assert_eq!(current_row.len(), next_row.len());
197
198        Self { current_row, next_row, main_trace_width }
199    }
200
201    /// Returns the number of columns for the current and next frames.
202    pub fn num_columns(&self) -> usize {
203        self.current_row.len()
204    }
205
206    /// Returns the current row, consisting of both main and auxiliary columns.
207    pub fn current_row(&self) -> &[E] {
208        &self.current_row
209    }
210
211    /// Returns the next frame, consisting of both main and auxiliary columns.
212    pub fn next_row(&self) -> &[E] {
213        &self.next_row
214    }
215
216    /// Returns the evaluation frame for the main trace
217    pub fn main_frame(&self) -> EvaluationFrame<E> {
218        let current = self.current_row[0..self.main_trace_width].to_vec();
219        let next = self.next_row[0..self.main_trace_width].to_vec();
220
221        EvaluationFrame::from_rows(current, next)
222    }
223
224    /// Returns the evaluation frame for the auxiliary trace
225    pub fn aux_frame(&self) -> Option<EvaluationFrame<E>> {
226        if self.has_aux_frame() {
227            let current = self.current_row[self.main_trace_width..].to_vec();
228            let next = self.next_row[self.main_trace_width..].to_vec();
229
230            Some(EvaluationFrame::from_rows(current, next))
231        } else {
232            None
233        }
234    }
235
236    /// Hashes the main, auxiliary frames in a manner consistent with
237    /// [`OodFrame::set_trace_states`], with the purpose of reseeding the public coin.
238    pub fn hash<H: ElementHasher<BaseField = E::BaseField>>(&self) -> H::Digest {
239        let trace_states = self.to_trace_states();
240
241        H::hash_elements(&trace_states)
242    }
243
244    /// Returns true if an auxiliary frame is present
245    fn has_aux_frame(&self) -> bool {
246        self.current_row.len() > self.main_trace_width
247    }
248
249    /// Returns the main/aux frames as a vector of elements described in
250    /// [`OodFrame::set_trace_states`].
251    fn to_trace_states(&self) -> Vec<E> {
252        let mut main_and_aux_frame_states = Vec::new();
253        main_and_aux_frame_states.extend_from_slice(&self.current_row);
254        main_and_aux_frame_states.extend_from_slice(&self.next_row);
255
256        main_and_aux_frame_states
257    }
258}