1#[cfg(test)]
2use alloc::vec::Vec;
3
4use miden_air::{MIDEN_AIR_COUNT, PcsParams, memory, trace::MIN_TRACE_LEN};
5
6use super::chiplets::Chiplets;
7use crate::{Felt, ONE};
8#[cfg(test)]
9use crate::{operation::Operation, utils::ToElements};
10
11#[derive(Debug)]
20pub struct RowMajorTraceWriter<'a, E> {
21 data: &'a mut [E],
22 payload: usize,
23 stride: usize,
24}
25
26impl<'a, E: Copy> RowMajorTraceWriter<'a, E> {
27 #[cfg(test)]
29 pub(super) fn new(data: &'a mut [E], width: usize) -> Self {
30 Self::with_stride(data, width, width)
31 }
32
33 pub fn with_stride(data: &'a mut [E], payload: usize, stride: usize) -> Self {
36 debug_assert!(stride >= payload, "stride must be >= payload");
37 debug_assert_eq!(data.len() % stride, 0, "buffer length must be a multiple of stride");
38 Self { data, payload, stride }
39 }
40
41 #[inline(always)]
43 pub fn write_row(&mut self, row: usize, values: &[E]) {
44 debug_assert_eq!(values.len(), self.payload);
45 let start = row * self.stride;
46 self.data[start..start + self.payload].copy_from_slice(values);
47 }
48}
49
50pub struct ChipletTraceFragment<'a> {
59 band: &'a mut [Felt],
61 stride: usize,
62 col_start: usize,
63 num_rows: usize,
64 num_cols: usize,
65 row_offset: usize,
67 prefix_one_cols: &'static [usize],
69 write_chip_clk: bool,
71}
72
73impl<'a> ChipletTraceFragment<'a> {
74 pub fn row_major(
76 band: &'a mut [Felt],
77 stride: usize,
78 col_start: usize,
79 num_cols: usize,
80 ) -> Self {
81 Self::new(band, stride, col_start, num_cols, 0, &[], false)
82 }
83
84 pub fn with_overheads(
87 band: &'a mut [Felt],
88 stride: usize,
89 col_start: usize,
90 num_cols: usize,
91 row_offset: usize,
92 prefix_one_cols: &'static [usize],
93 ) -> Self {
94 Self::new(
95 band,
96 stride,
97 col_start,
98 num_cols,
99 row_offset,
100 prefix_one_cols,
101 stride > col_start + num_cols,
102 )
103 }
104
105 fn new(
106 band: &'a mut [Felt],
107 stride: usize,
108 col_start: usize,
109 num_cols: usize,
110 row_offset: usize,
111 prefix_one_cols: &'static [usize],
112 write_chip_clk: bool,
113 ) -> Self {
114 debug_assert_eq!(band.len() % stride, 0, "band length must be a multiple of stride");
115 debug_assert!(col_start + num_cols <= stride, "column band overruns the row stride");
116 debug_assert!(
117 prefix_one_cols.iter().all(|&col| col < col_start),
118 "prefix_one_cols must lie before col_start",
119 );
120 let num_rows = band.len() / stride;
121 Self {
122 band,
123 stride,
124 col_start,
125 num_rows,
126 num_cols,
127 row_offset,
128 prefix_one_cols,
129 write_chip_clk,
130 }
131 }
132
133 pub fn width(&self) -> usize {
138 self.num_cols
139 }
140
141 pub fn len(&self) -> usize {
143 self.num_rows
144 }
145
146 pub fn copy_rows_from(&mut self, src: &[Felt]) {
152 debug_assert_eq!(src.len(), self.num_rows * self.num_cols, "source buffer size mismatch");
153 self.copy_rows_into(0, src);
154 }
155
156 pub fn copy_rows_into(&mut self, row_offset: usize, src: &[Felt]) {
159 debug_assert_eq!(src.len() % self.num_cols, 0, "source buffer size not row-aligned");
160 let chunk_rows = src.len() / self.num_cols;
161 debug_assert!(
162 row_offset + chunk_rows <= self.num_rows,
163 "chunk overruns fragment row range",
164 );
165 let clk_col = self.stride - 1;
166 for r in 0..chunk_rows {
167 let dst_row = row_offset + r;
168 let row_start = dst_row * self.stride;
169 let row = &mut self.band[row_start..row_start + self.stride];
170 for &col in self.prefix_one_cols {
171 row[col] = ONE;
172 }
173 let src_row = &src[r * self.num_cols..(r + 1) * self.num_cols];
174 row[self.col_start..self.col_start + self.num_cols].copy_from_slice(src_row);
175 if self.write_chip_clk {
176 row[clk_col] = Felt::from_u32((self.row_offset + dst_row + 1) as u32);
177 }
178 }
179 }
180}
181
182#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
192pub struct TraceLenSummary {
193 core_trace_len: usize,
194 range_trace_len: usize,
195 chiplets_trace_len: ChipletsLengths,
196 poseidon2_permutation_trace_len: usize,
197 padded_heights: Option<[usize; MIDEN_AIR_COUNT]>,
201}
202
203impl TraceLenSummary {
204 pub fn new(
205 core_trace_len: usize,
206 range_trace_len: usize,
207 chiplets_trace_len: ChipletsLengths,
208 ) -> Self {
209 TraceLenSummary {
210 core_trace_len,
211 range_trace_len,
212 chiplets_trace_len,
213 poseidon2_permutation_trace_len: 0,
214 padded_heights: None,
215 }
216 }
217
218 pub fn new_with_padded(
221 core_trace_len: usize,
222 range_trace_len: usize,
223 chiplets_trace_len: ChipletsLengths,
224 poseidon2_permutation_trace_len: usize,
225 padded_heights: [usize; MIDEN_AIR_COUNT],
226 ) -> Self {
227 TraceLenSummary {
228 core_trace_len,
229 range_trace_len,
230 chiplets_trace_len,
231 poseidon2_permutation_trace_len,
232 padded_heights: Some(padded_heights),
233 }
234 }
235
236 pub fn core_trace_len(&self) -> usize {
238 self.core_trace_len
239 }
240
241 pub fn range_trace_len(&self) -> usize {
243 self.range_trace_len
244 }
245
246 pub fn chiplets_trace_len(&self) -> ChipletsLengths {
248 self.chiplets_trace_len
249 }
250
251 pub fn poseidon2_permutation_trace_len(&self) -> usize {
253 self.poseidon2_permutation_trace_len
254 }
255
256 pub fn trace_len(&self) -> usize {
258 self.range_trace_len
259 .max(self.core_trace_len)
260 .max(self.chiplets_trace_len.trace_len())
261 .max(self.poseidon2_permutation_trace_len)
262 }
263
264 pub fn padded_trace_len(&self) -> usize {
266 self.padded_heights
267 .map(|heights| heights.into_iter().max().expect("heights is non-empty"))
268 .unwrap_or_else(|| self.trace_len().next_power_of_two().max(MIN_TRACE_LEN))
269 }
270
271 pub fn padded_heights(&self) -> Option<&[usize; MIDEN_AIR_COUNT]> {
273 self.padded_heights.as_ref()
274 }
275
276 pub fn prover_memory_bytes(&self, params: &PcsParams) -> Option<u64> {
279 memory::prover_peak_bytes(self.padded_heights()?, params)
280 }
281
282 pub fn padding_percentage(&self) -> usize {
284 (self.padded_trace_len() - self.trace_len()) * 100 / self.padded_trace_len()
285 }
286}
287
288#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
293pub struct ChipletsLengths {
294 hash_chiplet_len: usize,
295 bitwise_chiplet_len: usize,
296 memory_chiplet_len: usize,
297 ace_chiplet_len: usize,
298 kernel_rom_len: usize,
299}
300
301impl ChipletsLengths {
302 pub fn new(chiplets: &Chiplets) -> Self {
303 ChipletsLengths {
304 hash_chiplet_len: chiplets.bitwise_start().into(),
305 bitwise_chiplet_len: chiplets.memory_start() - chiplets.bitwise_start(),
306 memory_chiplet_len: chiplets.ace_start() - chiplets.memory_start(),
307 ace_chiplet_len: chiplets.kernel_rom_start() - chiplets.ace_start(),
308 kernel_rom_len: chiplets.padding_start() - chiplets.kernel_rom_start(),
309 }
310 }
311
312 pub fn from_parts(
313 hash_len: usize,
314 bitwise_len: usize,
315 memory_len: usize,
316 ace_len: usize,
317 kernel_len: usize,
318 ) -> Self {
319 ChipletsLengths {
320 hash_chiplet_len: hash_len,
321 bitwise_chiplet_len: bitwise_len,
322 memory_chiplet_len: memory_len,
323 ace_chiplet_len: ace_len,
324 kernel_rom_len: kernel_len,
325 }
326 }
327
328 pub fn hash_chiplet_len(&self) -> usize {
330 self.hash_chiplet_len
331 }
332
333 pub fn bitwise_chiplet_len(&self) -> usize {
335 self.bitwise_chiplet_len
336 }
337
338 pub fn memory_chiplet_len(&self) -> usize {
340 self.memory_chiplet_len
341 }
342
343 pub fn ace_chiplet_len(&self) -> usize {
345 self.ace_chiplet_len
346 }
347
348 pub fn kernel_rom_len(&self) -> usize {
350 self.kernel_rom_len
351 }
352
353 pub fn trace_len(&self) -> usize {
357 self.hash_chiplet_len()
358 + self.bitwise_chiplet_len()
359 + self.memory_chiplet_len()
360 + self.ace_chiplet_len()
361 + self.kernel_rom_len()
362 + 1
363 }
364}
365
366pub(crate) fn split_element_u32_into_u16(value: Felt) -> (Felt, Felt) {
372 let (hi, lo) = split_u32_into_u16(value.as_canonical_u64());
373 (Felt::new_unchecked(hi as u64), Felt::new_unchecked(lo as u64))
374}
375
376pub(crate) fn split_u32_into_u16(value: u64) -> (u16, u16) {
381 const U32MAX: u64 = u32::MAX as u64;
382 debug_assert!(value <= U32MAX, "not a 32-bit value");
383
384 let lo = value as u16;
385 let hi = (value >> 16) as u16;
386
387 (hi, lo)
388}
389
390#[cfg(test)]
397pub(super) fn build_span_with_respan_ops() -> (Vec<Operation>, Vec<Felt>) {
398 let iv = [1, 3, 5, 7, 9, 11, 13, 15, 17].to_elements();
399 let ops = alloc::vec![
400 Operation::Push(iv[0]),
401 Operation::Push(iv[1]),
402 Operation::Push(iv[2]),
403 Operation::Push(iv[3]),
404 Operation::Push(iv[4]),
405 Operation::Push(iv[5]),
406 Operation::Push(iv[6]),
407 Operation::Push(iv[7]),
409 Operation::Push(iv[8]),
410 Operation::Add,
411 Operation::Drop,
413 Operation::Drop,
414 Operation::Drop,
415 Operation::Drop,
416 Operation::Drop,
417 Operation::Drop,
418 Operation::Drop,
419 Operation::Drop,
420 ];
421 (ops, iv)
422}