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("ient_states);
117
118 H::hash_elements("ient_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}