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}