1use alloc::{string::ToString, vec::Vec};
7
8use math::{StarkField, ToElements};
9use utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
10
11#[derive(Debug, Clone, Eq, PartialEq)]
24pub struct TraceInfo {
25 main_segment_width: usize,
26 aux_segment_width: usize,
27 num_aux_segment_rands: usize,
28 trace_length: usize,
29 trace_meta: Vec<u8>,
30}
31
32impl TraceInfo {
33 pub const MIN_TRACE_LENGTH: usize = 8;
35 pub const MAX_TRACE_WIDTH: usize = 255;
37 pub const MAX_META_LENGTH: usize = 65535;
39 pub const MAX_RAND_SEGMENT_ELEMENTS: usize = 255;
41
42 pub fn new(width: usize, length: usize) -> Self {
54 Self::with_meta(width, length, vec![])
55 }
56
57 pub fn with_meta(width: usize, length: usize, meta: Vec<u8>) -> Self {
67 assert!(width > 0, "trace width must be greater than 0");
68 Self::new_multi_segment(width, 0, 0, length, meta)
69 }
70
71 pub fn new_multi_segment(
85 main_segment_width: usize,
86 aux_segment_width: usize,
87 num_aux_segment_rands: usize,
88 trace_length: usize,
89 trace_meta: Vec<u8>,
90 ) -> Self {
91 assert!(
92 trace_length >= Self::MIN_TRACE_LENGTH,
93 "trace length must be at least {}, but was {}",
94 Self::MIN_TRACE_LENGTH,
95 trace_length
96 );
97 assert!(
98 trace_length.is_power_of_two(),
99 "trace length must be a power of two, but was {trace_length}"
100 );
101 assert!(
102 trace_meta.len() <= Self::MAX_META_LENGTH,
103 "number of metadata bytes cannot be greater than {}, but was {}",
104 Self::MAX_META_LENGTH,
105 trace_meta.len()
106 );
107
108 assert!(main_segment_width > 0, "main trace segment must consist of at least one column");
110 let full_width = main_segment_width + aux_segment_width;
111 assert!(
112 full_width <= TraceInfo::MAX_TRACE_WIDTH,
113 "total number of columns in the trace cannot be greater than {}, but was {}",
114 TraceInfo::MAX_TRACE_WIDTH,
115 full_width
116 );
117
118 if aux_segment_width == 0 {
120 assert!(
121 num_aux_segment_rands == 0,
122 "number of random elements for an empty auxiliary trace segment must be zero"
123 );
124 }
125 assert!(
126 num_aux_segment_rands <= TraceInfo::MAX_RAND_SEGMENT_ELEMENTS,
127 "number of random elements required by a segment cannot exceed {}, but was {}",
128 TraceInfo::MAX_RAND_SEGMENT_ELEMENTS,
129 num_aux_segment_rands
130 );
131
132 TraceInfo {
133 main_segment_width,
134 aux_segment_width,
135 num_aux_segment_rands,
136 trace_length,
137 trace_meta,
138 }
139 }
140
141 pub fn width(&self) -> usize {
148 self.main_segment_width + self.aux_segment_width
149 }
150
151 pub fn length(&self) -> usize {
155 self.trace_length
156 }
157
158 pub fn meta(&self) -> &[u8] {
160 &self.trace_meta
161 }
162
163 pub fn is_multi_segment(&self) -> bool {
165 self.aux_segment_width > 0
166 }
167
168 pub fn main_trace_width(&self) -> usize {
172 self.main_segment_width
173 }
174
175 pub fn aux_segment_width(&self) -> usize {
177 self.aux_segment_width
178 }
179
180 pub fn num_segments(&self) -> usize {
182 if self.is_multi_segment() {
183 2
184 } else {
185 1
186 }
187 }
188
189 pub fn num_aux_segments(&self) -> usize {
191 if self.is_multi_segment() {
192 1
193 } else {
194 0
195 }
196 }
197
198 pub fn get_aux_segment_width(&self) -> usize {
200 self.aux_segment_width
201 }
202
203 pub fn get_num_aux_segment_rand_elements(&self) -> usize {
205 self.num_aux_segment_rands
206 }
207}
208
209impl<E: StarkField> ToElements<E> for TraceInfo {
210 fn to_elements(&self) -> Vec<E> {
211 let mut result = Vec::new();
212
213 let mut buf = self.main_segment_width as u32;
217 buf = (buf << 8) | self.num_aux_segments() as u32;
218 if self.num_aux_segments() == 1 {
219 buf = (buf << 8) | self.aux_segment_width as u32;
220 buf = (buf << 8) | self.num_aux_segment_rands as u32;
221 }
222 result.push(E::from(buf));
223
224 result.push(E::from(self.trace_length as u32));
226
227 if !self.trace_meta.is_empty() {
231 for chunk in self.trace_meta.chunks(E::ELEMENT_BYTES - 1) {
232 result.push(E::from_bytes_with_padding(chunk));
233 }
234 }
235
236 result
237 }
238}
239
240impl Serializable for TraceInfo {
241 fn write_into<W: ByteWriter>(&self, target: &mut W) {
243 target.write_u8(self.main_segment_width as u8);
245
246 debug_assert!(
247 self.aux_segment_width <= u8::MAX as usize,
248 "aux segment width does not fit into u8 value"
249 );
250 target.write_u8(self.aux_segment_width as u8);
251 debug_assert!(
252 self.num_aux_segment_rands <= u8::MAX as usize,
253 "aux segment random element count does not fit into u8 value"
254 );
255 target.write_u8(self.num_aux_segment_rands as u8);
256
257 target.write_u8(self.trace_length.ilog2() as u8);
259
260 target.write_u16(self.trace_meta.len() as u16);
262 target.write_bytes(&self.trace_meta);
263 }
264}
265
266impl Deserializable for TraceInfo {
267 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
273 let main_segment_width = source.read_u8()? as usize;
274 if main_segment_width == 0 {
275 return Err(DeserializationError::InvalidValue(
276 "main trace segment width must be greater than zero".to_string(),
277 ));
278 }
279
280 let aux_segment_width = source.read_u8()? as usize;
282
283 let full_trace_width = main_segment_width + aux_segment_width;
284 if full_trace_width >= TraceInfo::MAX_TRACE_WIDTH {
285 return Err(DeserializationError::InvalidValue(format!(
286 "full trace width cannot be greater than {}, but was {}",
287 TraceInfo::MAX_TRACE_WIDTH,
288 full_trace_width
289 )));
290 }
291
292 let num_aux_segment_rands = source.read_u8()? as usize;
294 if aux_segment_width != 0 && num_aux_segment_rands == 0 {
295 return Err(DeserializationError::InvalidValue(
296 "a non-empty trace segment must require at least one random element".to_string(),
297 ));
298 } else if num_aux_segment_rands > TraceInfo::MAX_RAND_SEGMENT_ELEMENTS {
299 return Err(DeserializationError::InvalidValue(format!(
300 "number of random elements required by a segment cannot exceed {}, but was {}",
301 TraceInfo::MAX_RAND_SEGMENT_ELEMENTS,
302 num_aux_segment_rands
303 )));
304 }
305
306 let trace_length = source.read_u8()?;
308 if trace_length < TraceInfo::MIN_TRACE_LENGTH.ilog2() as u8 {
309 return Err(DeserializationError::InvalidValue(format!(
310 "trace length cannot be smaller than 2^{}, but was 2^{}",
311 TraceInfo::MIN_TRACE_LENGTH.ilog2(),
312 trace_length
313 )));
314 }
315 let trace_length = 2_usize.pow(trace_length as u32);
316
317 let num_meta_bytes = source.read_u16()? as usize;
319 let trace_meta = if num_meta_bytes != 0 {
320 source.read_vec(num_meta_bytes)?
321 } else {
322 vec![]
323 };
324
325 Ok(Self::new_multi_segment(
326 main_segment_width,
327 aux_segment_width,
328 num_aux_segment_rands,
329 trace_length,
330 trace_meta,
331 ))
332 }
333}
334
335#[cfg(test)]
339mod tests {
340 use math::{fields::f64::BaseElement, FieldElement};
341
342 use super::{ToElements, TraceInfo};
343
344 #[test]
345 fn trace_info_to_elements() {
346 let main_width = 20;
348 let trace_length = 64_u32;
349 let num_aux_segments = 0;
350
351 let expected = {
352 let first_ele = u32::from_le_bytes([num_aux_segments, main_width as u8, 0, 0]);
353
354 vec![BaseElement::from(first_ele), BaseElement::from(trace_length)]
355 };
356
357 let info = TraceInfo::new(main_width, trace_length as usize);
358 assert_eq!(expected, info.to_elements());
359
360 let main_width = 20;
362 let trace_length = 64_u32;
363 let num_aux_segments = 1;
364 let aux_width = 9;
365 let aux_rands = 12;
366 let trace_meta = vec![1_u8, 2, 3, 4];
367
368 let expected = {
369 let first_ele =
370 u32::from_le_bytes([aux_rands as u8, aux_width, num_aux_segments, main_width]);
371
372 let mut meta_bytes = trace_meta.clone();
374 meta_bytes.resize(BaseElement::ELEMENT_BYTES, 0);
375 let meta_ele = BaseElement::try_from(meta_bytes.as_slice()).unwrap();
376
377 vec![BaseElement::from(first_ele), BaseElement::from(trace_length), meta_ele]
378 };
379
380 let info = TraceInfo::new_multi_segment(
381 main_width as usize,
382 aux_width as usize,
383 aux_rands,
384 trace_length as usize,
385 trace_meta,
386 );
387
388 assert_eq!(expected, info.to_elements());
389 }
390}