1use crate::errors;
19use crate::poly::variant::PolyVariant;
20use alloc::vec;
21use alloc::vec::Vec;
22use core::any::TypeId;
23use core::fmt;
24use core::mem::transmute;
25use hekate_math::{
26 Bit, Block8, Block16, Block32, Block64, Block128, CanonicalSerialize, Flat, FlatPromote,
27 HardwareField, PackableField, TowerField,
28};
29use zeroize::Zeroize;
30#[cfg(feature = "secure-memory")]
31use zeroize::ZeroizeOnDrop;
32
33#[derive(Clone, Copy, Debug, Eq, PartialEq)]
34pub enum Error {
35 InvalidParameters {
36 message: &'static str,
37 },
38 ColumnLengthMismatch {
39 expected_len: usize,
40 got_len: usize,
41 },
42 ColumnIndexOutOfBounds {
43 col_idx: usize,
44 num_cols: usize,
45 },
46 RowIndexOutOfBounds {
47 row_idx: usize,
48 num_rows: usize,
49 },
50 PointDimensionMismatch {
51 expected_len: usize,
52 got_len: usize,
53 },
54 ColumnTypeMismatch {
55 col_idx: usize,
56 expected: &'static str,
57 got: &'static str,
58 },
59}
60
61impl fmt::Display for Error {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 match self {
64 Self::InvalidParameters { message } => {
65 write!(f, "Trace invalid parameters: {message}")
66 }
67 Self::ColumnLengthMismatch {
68 expected_len,
69 got_len,
70 } => write!(
71 f,
72 "Trace column length mismatch: expected {expected_len}, got {got_len}",
73 ),
74 Self::ColumnIndexOutOfBounds { col_idx, num_cols } => write!(
75 f,
76 "Trace column index out of bounds: col_idx={col_idx}, num_cols={num_cols}",
77 ),
78 Self::RowIndexOutOfBounds { row_idx, num_rows } => write!(
79 f,
80 "Trace row index out of bounds: row_idx={row_idx}, num_rows={num_rows}",
81 ),
82 Self::PointDimensionMismatch {
83 expected_len,
84 got_len,
85 } => write!(
86 f,
87 "Trace evaluation point dimension mismatch: expected {expected_len}, got {got_len}",
88 ),
89 Self::ColumnTypeMismatch {
90 col_idx,
91 expected,
92 got,
93 } => write!(
94 f,
95 "Trace column type mismatch at col_idx={col_idx}: expected {expected}, got {got}",
96 ),
97 }
98 }
99}
100
101pub trait TraceCompatibleField:
106 TowerField
107 + HardwareField
108 + PackableField
109 + FlatPromote<Block8>
110 + FlatPromote<Block16>
111 + FlatPromote<Block32>
112 + FlatPromote<Block64>
113 + FlatPromote<Block128>
114 + From<Bit>
115 + From<Block8>
116 + From<Block16>
117 + From<Block32>
118 + From<Block64>
119 + From<Block128>
120 + Send
121 + Sync
122{
123}
124
125impl<T> TraceCompatibleField for T where
126 T: TowerField
127 + HardwareField
128 + PackableField
129 + FlatPromote<Block8>
130 + FlatPromote<Block16>
131 + FlatPromote<Block32>
132 + FlatPromote<Block64>
133 + FlatPromote<Block128>
134 + From<Bit>
135 + From<Block8>
136 + From<Block16>
137 + From<Block32>
138 + From<Block64>
139 + From<Block128>
140 + Send
141 + Sync
142{
143}
144
145pub trait Trace: Send + Sync {
153 fn num_vars(&self) -> usize;
155
156 fn columns(&self) -> &[TraceColumn];
157
158 fn num_rows(&self) -> errors::Result<usize> {
160 num_rows_from_num_vars(self.num_vars())
161 }
162
163 fn num_cols(&self) -> usize {
164 self.columns().len()
165 }
166
167 fn column_layout(&self) -> Vec<ColumnType> {
168 self.columns().iter().map(|col| col.column_type()).collect()
169 }
170
171 fn get_element<F: TraceCompatibleField>(
174 &self,
175 col_idx: usize,
176 row_idx: usize,
177 ) -> errors::Result<Flat<F>> {
178 let cols = self.columns();
179 let num_cols = self.num_cols();
180
181 if col_idx >= num_cols {
182 return Err(Error::ColumnIndexOutOfBounds { col_idx, num_cols }.into());
183 }
184
185 let num_rows = self.num_rows()?;
186 if row_idx >= num_rows {
187 return Err(Error::RowIndexOutOfBounds { row_idx, num_rows }.into());
188 }
189
190 match &cols[col_idx] {
191 TraceColumn::Bit(v) => Ok(Flat::from_raw(F::from(v[row_idx]))),
192 TraceColumn::B8(v) => Ok(F::promote_flat(v[row_idx])),
193 TraceColumn::B16(v) => Ok(F::promote_flat(v[row_idx])),
194 TraceColumn::B32(v) => Ok(F::promote_flat(v[row_idx])),
195 TraceColumn::B64(v) => Ok(F::promote_flat(v[row_idx])),
196 TraceColumn::B128(v) => Ok(F::promote_flat(v[row_idx])),
197 }
198 }
199
200 fn get_column_slice<F: 'static>(&self, col_idx: usize) -> errors::Result<&[F]> {
204 let cols = self.columns();
205 let num_cols = self.num_cols();
206
207 if col_idx >= num_cols {
208 return Err(Error::ColumnIndexOutOfBounds { col_idx, num_cols }.into());
209 }
210
211 let got = core::any::type_name::<F>();
212
213 match &cols[col_idx] {
214 TraceColumn::Bit(vec) => {
215 if TypeId::of::<F>() != TypeId::of::<Bit>() {
216 return Err(Error::ColumnTypeMismatch {
217 col_idx,
218 expected: "Bit",
219 got,
220 }
221 .into());
222 }
223
224 Ok(unsafe { transmute::<&[Bit], &[F]>(vec.as_slice()) })
227 }
228 TraceColumn::B8(vec) => {
229 if TypeId::of::<F>() != TypeId::of::<Flat<Block8>>() {
230 return Err(Error::ColumnTypeMismatch {
231 col_idx,
232 expected: "Flat<Block8>",
233 got,
234 }
235 .into());
236 }
237 Ok(unsafe { transmute::<&[Flat<Block8>], &[F]>(vec.as_slice()) })
238 }
239 TraceColumn::B16(vec) => {
240 if TypeId::of::<F>() != TypeId::of::<Flat<Block16>>() {
241 return Err(Error::ColumnTypeMismatch {
242 col_idx,
243 expected: "Flat<Block16>",
244 got,
245 }
246 .into());
247 }
248 Ok(unsafe { transmute::<&[Flat<Block16>], &[F]>(vec.as_slice()) })
249 }
250 TraceColumn::B32(vec) => {
251 if TypeId::of::<F>() != TypeId::of::<Flat<Block32>>() {
252 return Err(Error::ColumnTypeMismatch {
253 col_idx,
254 expected: "Flat<Block32>",
255 got,
256 }
257 .into());
258 }
259 Ok(unsafe { transmute::<&[Flat<Block32>], &[F]>(vec.as_slice()) })
260 }
261 TraceColumn::B64(vec) => {
262 if TypeId::of::<F>() != TypeId::of::<Flat<Block64>>() {
263 return Err(Error::ColumnTypeMismatch {
264 col_idx,
265 expected: "Flat<Block64>",
266 got,
267 }
268 .into());
269 }
270 Ok(unsafe { transmute::<&[Flat<Block64>], &[F]>(vec.as_slice()) })
271 }
272 TraceColumn::B128(vec) => {
273 if TypeId::of::<F>() != TypeId::of::<Flat<Block128>>() {
274 return Err(Error::ColumnTypeMismatch {
275 col_idx,
276 expected: "Flat<Block128>",
277 got,
278 }
279 .into());
280 }
281 Ok(unsafe { transmute::<&[Flat<Block128>], &[F]>(vec.as_slice()) })
282 }
283 }
284 }
285
286 fn get_poly_variants<F>(&'_ self) -> errors::Result<Vec<PolyVariant<'_, F>>>
292 where
293 F: TraceCompatibleField + 'static,
294 {
295 let cols = self.columns();
296 let mut variants = Vec::with_capacity(cols.len());
297
298 for (i, col) in cols.iter().enumerate() {
299 if i >= self.num_cols() {
300 return Err(errors::Error::Protocol {
301 protocol: "air",
302 message: "trace has fewer columns than required by AIR",
303 });
304 }
305
306 let variant = if let Some(s) = col.as_bit_slice() {
307 PolyVariant::BitSlice(s)
308 } else if let Some(s) = col.as_b8_slice() {
309 PolyVariant::B8Slice(s)
310 } else if let Some(s) = col.as_b16_slice() {
311 PolyVariant::B16Slice(s)
312 } else if let Some(s) = col.as_b32_slice() {
313 PolyVariant::B32Slice(s)
314 } else if let Some(s) = col.as_b64_slice() {
315 PolyVariant::B64Slice(s)
316 } else if let Some(s) = col.as_b128_slice() {
317 PolyVariant::B128Slice(s)
318 } else {
319 return Err(errors::Error::Protocol {
320 protocol: "air",
321 message: "unsupported trace column variant",
322 });
323 };
324
325 variants.push(variant);
326 }
327
328 Ok(variants)
329 }
330}
331
332#[derive(Clone, Copy, Debug, PartialEq, Eq)]
341pub enum ColumnType {
342 Bit,
347 B8,
348 B16,
349 B32,
350 B64,
351 B128,
352}
353
354impl ColumnType {
355 #[inline]
356 pub const fn byte_size(&self) -> usize {
357 match self {
358 Self::Bit => 1,
359 Self::B8 => 1,
360 Self::B16 => 2,
361 Self::B32 => 4,
362 Self::B64 => 8,
363 Self::B128 => 16,
364 }
365 }
366
367 pub fn parse_from_bytes<F>(&self, bytes: &[u8]) -> Flat<F>
371 where
372 F: TraceCompatibleField,
373 {
374 match self {
375 Self::Bit => Flat::from_raw(F::from(Bit(bytes[0]))),
376 Self::B8 => F::promote_flat(Flat::from_raw(Block8(bytes[0]))),
377 Self::B16 => {
378 let mut buf = [0u8; 2];
379 buf.copy_from_slice(&bytes[0..2]);
380
381 F::promote_flat(Flat::from_raw(Block16(u16::from_le_bytes(buf))))
382 }
383 Self::B32 => {
384 let mut buf = [0u8; 4];
385 buf.copy_from_slice(&bytes[0..4]);
386
387 F::promote_flat(Flat::from_raw(Block32(u32::from_le_bytes(buf))))
388 }
389 Self::B64 => {
390 let mut buf = [0u8; 8];
391 buf.copy_from_slice(&bytes[0..8]);
392
393 F::promote_flat(Flat::from_raw(Block64(u64::from_le_bytes(buf))))
394 }
395 Self::B128 => {
396 let mut buf = [0u8; 16];
397 buf.copy_from_slice(&bytes[0..16]);
398
399 F::promote_flat(Flat::from_raw(Block128(u128::from_le_bytes(buf))))
400 }
401 }
402 }
403}
404
405#[derive(Clone, Debug, Zeroize)]
409#[cfg_attr(feature = "secure-memory", derive(ZeroizeOnDrop))]
410pub enum TraceColumn {
411 Bit(Vec<Bit>),
412 B8(Vec<Flat<Block8>>),
413 B16(Vec<Flat<Block16>>),
414 B32(Vec<Flat<Block32>>),
415 B64(Vec<Flat<Block64>>),
416 B128(Vec<Flat<Block128>>),
417}
418
419impl TraceColumn {
420 pub fn from_data(data: Vec<Block128>, target_type: ColumnType) -> Self {
423 match target_type {
424 ColumnType::Bit => {
425 let converted: Vec<Bit> = data
426 .iter()
427 .map(|val| {
428 let bytes = val.to_bytes();
429 Bit::from(bytes[0] & 1)
430 })
431 .collect();
432 TraceColumn::Bit(converted)
433 }
434 ColumnType::B8 => {
435 let converted: Vec<Flat<Block8>> = data
436 .iter()
437 .map(|val| {
438 let bytes = val.to_bytes();
439 Block8::from(bytes[0]).to_hardware()
440 })
441 .collect();
442 TraceColumn::B8(converted)
443 }
444 ColumnType::B16 => {
445 let converted: Vec<Flat<Block16>> = data
446 .iter()
447 .map(|val| {
448 let bytes = val.to_bytes();
449 let mut chunk = [0u8; 2];
450 chunk.copy_from_slice(&bytes[0..2]);
451
452 Block16::from(u16::from_le_bytes(chunk)).to_hardware()
453 })
454 .collect();
455 TraceColumn::B16(converted)
456 }
457 ColumnType::B32 => {
458 let converted: Vec<Flat<Block32>> = data
459 .iter()
460 .map(|val| {
461 let bytes = val.to_bytes();
462 let mut chunk = [0u8; 4];
463 chunk.copy_from_slice(&bytes[0..4]);
464
465 Block32::from(u32::from_le_bytes(chunk)).to_hardware()
466 })
467 .collect();
468 TraceColumn::B32(converted)
469 }
470 ColumnType::B64 => {
471 let converted: Vec<Flat<Block64>> = data
472 .iter()
473 .map(|val| {
474 let bytes = val.to_bytes();
475 let mut chunk = [0u8; 8];
476 chunk.copy_from_slice(&bytes[0..8]);
477
478 Block64::from(u64::from_le_bytes(chunk)).to_hardware()
479 })
480 .collect();
481 TraceColumn::B64(converted)
482 }
483 ColumnType::B128 => {
484 TraceColumn::B128(data.into_iter().map(|value| value.to_hardware()).collect())
485 }
486 }
487 }
488
489 pub fn len(&self) -> usize {
490 match self {
491 Self::Bit(v) => v.len(),
492 Self::B8(v) => v.len(),
493 Self::B16(v) => v.len(),
494 Self::B32(v) => v.len(),
495 Self::B64(v) => v.len(),
496 Self::B128(v) => v.len(),
497 }
498 }
499
500 pub fn is_empty(&self) -> bool {
501 self.len() == 0
502 }
503
504 pub fn is_all_zeros(&self) -> bool {
505 match self {
506 Self::Bit(v) => v.iter().all(|x| x.0 == 0),
507 Self::B8(v) => v.iter().all(|x| x.into_raw().0 == 0),
508 Self::B16(v) => v.iter().all(|x| x.into_raw().0 == 0),
509 Self::B32(v) => v.iter().all(|x| x.into_raw().0 == 0),
510 Self::B64(v) => v.iter().all(|x| x.into_raw().0 == 0),
511 Self::B128(v) => v.iter().all(|x| x.into_raw() == Block128::ZERO),
512 }
513 }
514
515 pub fn column_type(&self) -> ColumnType {
517 match self {
518 Self::Bit(_) => ColumnType::Bit,
519 Self::B8(_) => ColumnType::B8,
520 Self::B16(_) => ColumnType::B16,
521 Self::B32(_) => ColumnType::B32,
522 Self::B64(_) => ColumnType::B64,
523 Self::B128(_) => ColumnType::B128,
524 }
525 }
526
527 pub fn append_bytes_at(&self, row_idx: usize, buf: &mut Vec<u8>) {
531 match self {
532 Self::Bit(v) => {
533 buf.push(v[row_idx].0);
534 }
535 Self::B8(v) => {
536 buf.push(v[row_idx].into_raw().0);
537 }
538 Self::B16(v) => {
539 buf.extend_from_slice(&v[row_idx].into_raw().0.to_le_bytes());
540 }
541 Self::B32(v) => {
542 buf.extend_from_slice(&v[row_idx].into_raw().0.to_le_bytes());
543 }
544 Self::B64(v) => {
545 buf.extend_from_slice(&v[row_idx].into_raw().0.to_le_bytes());
546 }
547 Self::B128(v) => {
548 buf.extend_from_slice(&v[row_idx].into_raw().0.to_le_bytes());
549 }
550 }
551 }
552
553 pub fn as_bit_slice(&self) -> Option<&[Bit]> {
558 if let Self::Bit(v) = self {
559 Some(v)
560 } else {
561 None
562 }
563 }
564
565 pub fn as_b8_slice(&self) -> Option<&[Flat<Block8>]> {
566 if let Self::B8(v) = self {
567 Some(v)
568 } else {
569 None
570 }
571 }
572 pub fn as_b16_slice(&self) -> Option<&[Flat<Block16>]> {
573 if let Self::B16(v) = self {
574 Some(v)
575 } else {
576 None
577 }
578 }
579 pub fn as_b32_slice(&self) -> Option<&[Flat<Block32>]> {
580 if let Self::B32(v) = self {
581 Some(v)
582 } else {
583 None
584 }
585 }
586 pub fn as_b64_slice(&self) -> Option<&[Flat<Block64>]> {
587 if let Self::B64(v) = self {
588 Some(v)
589 } else {
590 None
591 }
592 }
593 pub fn as_b128_slice(&self) -> Option<&[Flat<Block128>]> {
594 if let Self::B128(v) = self {
595 Some(v)
596 } else {
597 None
598 }
599 }
600}
601
602#[derive(Clone, Debug, Zeroize)]
605#[cfg_attr(feature = "secure-memory", derive(ZeroizeOnDrop))]
606pub struct ColumnTrace {
607 pub columns: Vec<TraceColumn>,
608 pub num_vars: usize,
609}
610
611impl Trace for ColumnTrace {
612 fn num_vars(&self) -> usize {
613 self.num_vars
614 }
615
616 fn columns(&self) -> &[TraceColumn] {
617 &self.columns
618 }
619}
620
621impl ColumnTrace {
622 pub fn new(num_vars: usize) -> errors::Result<Self> {
623 let num_rows = num_rows_from_num_vars(num_vars)?;
624 if num_rows == 0 {
625 return Err(Error::InvalidParameters {
626 message: "trace height is zero",
627 }
628 .into());
629 }
630
631 Ok(Self {
632 num_vars,
633 columns: Vec::new(),
634 })
635 }
636
637 pub fn into_columns(mut self) -> Vec<TraceColumn> {
640 core::mem::take(&mut self.columns)
641 }
642
643 pub fn add_column(&mut self, col: TraceColumn) -> errors::Result<()> {
644 let expected_len = self.num_rows()?;
645 let got_len = col.len();
646
647 if got_len != expected_len {
648 return Err(Error::ColumnLengthMismatch {
649 expected_len,
650 got_len,
651 }
652 .into());
653 }
654
655 self.columns.push(col);
656
657 Ok(())
658 }
659}
660
661pub trait IntoTraceColumn {
662 fn into_trace_column(self) -> TraceColumn;
663}
664
665impl IntoTraceColumn for Vec<Bit> {
666 fn into_trace_column(self) -> TraceColumn {
667 TraceColumn::Bit(self)
668 }
669}
670
671impl IntoTraceColumn for Vec<Block8> {
672 fn into_trace_column(self) -> TraceColumn {
673 TraceColumn::B8(self.into_iter().map(|value| value.to_hardware()).collect())
674 }
675}
676
677impl IntoTraceColumn for Vec<Block16> {
678 fn into_trace_column(self) -> TraceColumn {
679 TraceColumn::B16(self.into_iter().map(|value| value.to_hardware()).collect())
680 }
681}
682
683impl IntoTraceColumn for Vec<Block32> {
684 fn into_trace_column(self) -> TraceColumn {
685 TraceColumn::B32(self.into_iter().map(|value| value.to_hardware()).collect())
686 }
687}
688
689impl IntoTraceColumn for Vec<Block64> {
690 fn into_trace_column(self) -> TraceColumn {
691 TraceColumn::B64(self.into_iter().map(|value| value.to_hardware()).collect())
692 }
693}
694
695impl IntoTraceColumn for Vec<Block128> {
696 fn into_trace_column(self) -> TraceColumn {
697 TraceColumn::B128(self.into_iter().map(|value| value.to_hardware()).collect())
698 }
699}
700
701impl IntoTraceColumn for Vec<Flat<Block8>> {
702 fn into_trace_column(self) -> TraceColumn {
703 TraceColumn::B8(self)
704 }
705}
706
707impl IntoTraceColumn for Vec<Flat<Block16>> {
708 fn into_trace_column(self) -> TraceColumn {
709 TraceColumn::B16(self)
710 }
711}
712
713impl IntoTraceColumn for Vec<Flat<Block32>> {
714 fn into_trace_column(self) -> TraceColumn {
715 TraceColumn::B32(self)
716 }
717}
718
719impl IntoTraceColumn for Vec<Flat<Block64>> {
720 fn into_trace_column(self) -> TraceColumn {
721 TraceColumn::B64(self)
722 }
723}
724
725impl IntoTraceColumn for Vec<Flat<Block128>> {
726 fn into_trace_column(self) -> TraceColumn {
727 TraceColumn::B128(self)
728 }
729}
730
731pub fn get_col_views(columns: &[TraceColumn]) -> Vec<(&[u8], usize)> {
735 columns
736 .iter()
737 .map(|col| match col {
738 TraceColumn::Bit(v) => (
739 unsafe { core::slice::from_raw_parts(v.as_ptr() as *const u8, v.len()) },
740 1,
741 ),
742 TraceColumn::B8(v) => (
743 unsafe { core::slice::from_raw_parts(v.as_ptr() as *const u8, v.len()) },
744 1,
745 ),
746 TraceColumn::B16(v) => (
747 unsafe { core::slice::from_raw_parts(v.as_ptr() as *const u8, v.len() * 2) },
748 2,
749 ),
750 TraceColumn::B32(v) => (
751 unsafe { core::slice::from_raw_parts(v.as_ptr() as *const u8, v.len() * 4) },
752 4,
753 ),
754 TraceColumn::B64(v) => (
755 unsafe { core::slice::from_raw_parts(v.as_ptr() as *const u8, v.len() * 8) },
756 8,
757 ),
758 TraceColumn::B128(v) => (
759 unsafe { core::slice::from_raw_parts(v.as_ptr() as *const u8, v.len() * 16) },
760 16,
761 ),
762 })
763 .collect()
764}
765
766pub struct TraceBuilder {
774 columns: Vec<TraceColumn>,
775 num_vars: usize,
776 num_rows: usize,
777 cursors: Vec<usize>,
778}
779
780impl TraceBuilder {
781 pub fn new(layout: &[ColumnType], num_vars: usize) -> errors::Result<Self> {
782 let num_rows = num_rows_from_num_vars(num_vars)?;
783 let columns = layout
784 .iter()
785 .map(|ct| match ct {
786 ColumnType::Bit => TraceColumn::Bit(vec![Bit::ZERO; num_rows]),
787 ColumnType::B8 => TraceColumn::B8(vec![Block8::ZERO.to_hardware(); num_rows]),
788 ColumnType::B16 => TraceColumn::B16(vec![Block16::ZERO.to_hardware(); num_rows]),
789 ColumnType::B32 => TraceColumn::B32(vec![Block32::ZERO.to_hardware(); num_rows]),
790 ColumnType::B64 => TraceColumn::B64(vec![Block64::ZERO.to_hardware(); num_rows]),
791 ColumnType::B128 => TraceColumn::B128(vec![Block128::ZERO.to_hardware(); num_rows]),
792 })
793 .collect();
794
795 Ok(Self {
796 columns,
797 num_vars,
798 num_rows,
799 cursors: vec![0; layout.len()],
800 })
801 }
802
803 #[inline]
805 pub fn num_rows(&self) -> usize {
806 self.num_rows
807 }
808
809 #[inline]
814 pub fn set_bit(&mut self, col: usize, row: usize, val: Bit) -> errors::Result<()> {
815 let num_rows = self.num_rows;
816 let data = self.expect_bit_col(col)?;
817 let slot = data.get_mut(row).ok_or(Error::RowIndexOutOfBounds {
818 row_idx: row,
819 num_rows,
820 })?;
821
822 *slot = val;
823
824 Ok(())
825 }
826
827 #[inline]
828 pub fn set_b8(&mut self, col: usize, row: usize, val: Block8) -> errors::Result<()> {
829 let num_rows = self.num_rows;
830 let data = self.expect_b8_col(col)?;
831 let slot = data.get_mut(row).ok_or(Error::RowIndexOutOfBounds {
832 row_idx: row,
833 num_rows,
834 })?;
835
836 *slot = val.to_hardware();
837
838 Ok(())
839 }
840
841 #[inline]
842 pub fn set_b16(&mut self, col: usize, row: usize, val: Block16) -> errors::Result<()> {
843 let num_rows = self.num_rows;
844 let data = self.expect_b16_col(col)?;
845 let slot = data.get_mut(row).ok_or(Error::RowIndexOutOfBounds {
846 row_idx: row,
847 num_rows,
848 })?;
849
850 *slot = val.to_hardware();
851
852 Ok(())
853 }
854
855 #[inline]
856 pub fn set_b32(&mut self, col: usize, row: usize, val: Block32) -> errors::Result<()> {
857 let num_rows = self.num_rows;
858 let data = self.expect_b32_col(col)?;
859 let slot = data.get_mut(row).ok_or(Error::RowIndexOutOfBounds {
860 row_idx: row,
861 num_rows,
862 })?;
863
864 *slot = val.to_hardware();
865
866 Ok(())
867 }
868
869 #[inline]
870 pub fn set_b64(&mut self, col: usize, row: usize, val: Block64) -> errors::Result<()> {
871 let num_rows = self.num_rows;
872 let data = self.expect_b64_col(col)?;
873 let slot = data.get_mut(row).ok_or(Error::RowIndexOutOfBounds {
874 row_idx: row,
875 num_rows,
876 })?;
877
878 *slot = val.to_hardware();
879
880 Ok(())
881 }
882
883 #[inline]
884 pub fn set_b128(&mut self, col: usize, row: usize, val: Block128) -> errors::Result<()> {
885 let num_rows = self.num_rows;
886 let data = self.expect_b128_col(col)?;
887 let slot = data.get_mut(row).ok_or(Error::RowIndexOutOfBounds {
888 row_idx: row,
889 num_rows,
890 })?;
891
892 *slot = val.to_hardware();
893
894 Ok(())
895 }
896
897 #[inline]
902 pub fn push_bit(&mut self, col: usize, val: Bit) -> errors::Result<()> {
903 let row = self.cursor(col)?;
904 self.set_bit(col, row, val)?;
905
906 self.cursors[col] = row + 1;
907
908 Ok(())
909 }
910
911 #[inline]
912 pub fn push_b8(&mut self, col: usize, val: Block8) -> errors::Result<()> {
913 let row = self.cursor(col)?;
914 self.set_b8(col, row, val)?;
915
916 self.cursors[col] = row + 1;
917
918 Ok(())
919 }
920
921 #[inline]
922 pub fn push_b16(&mut self, col: usize, val: Block16) -> errors::Result<()> {
923 let row = self.cursor(col)?;
924 self.set_b16(col, row, val)?;
925
926 self.cursors[col] = row + 1;
927
928 Ok(())
929 }
930
931 #[inline]
932 pub fn push_b32(&mut self, col: usize, val: Block32) -> errors::Result<()> {
933 let row = self.cursor(col)?;
934 self.set_b32(col, row, val)?;
935
936 self.cursors[col] = row + 1;
937
938 Ok(())
939 }
940
941 #[inline]
942 pub fn push_b64(&mut self, col: usize, val: Block64) -> errors::Result<()> {
943 let row = self.cursor(col)?;
944 self.set_b64(col, row, val)?;
945
946 self.cursors[col] = row + 1;
947
948 Ok(())
949 }
950
951 #[inline]
952 pub fn push_b128(&mut self, col: usize, val: Block128) -> errors::Result<()> {
953 let row = self.cursor(col)?;
954 self.set_b128(col, row, val)?;
955
956 self.cursors[col] = row + 1;
957
958 Ok(())
959 }
960
961 pub fn set_bit_array(&mut self, base: usize, row: usize, values: &[Bit]) -> errors::Result<()> {
966 for (i, &val) in values.iter().enumerate() {
967 self.set_bit(base + i, row, val)?;
968 }
969
970 Ok(())
971 }
972
973 pub fn set_b8_array(
974 &mut self,
975 base: usize,
976 row: usize,
977 values: &[Block8],
978 ) -> errors::Result<()> {
979 for (i, &val) in values.iter().enumerate() {
980 self.set_b8(base + i, row, val)?;
981 }
982
983 Ok(())
984 }
985
986 pub fn set_b16_array(
987 &mut self,
988 base: usize,
989 row: usize,
990 values: &[Block16],
991 ) -> errors::Result<()> {
992 for (i, &val) in values.iter().enumerate() {
993 self.set_b16(base + i, row, val)?;
994 }
995
996 Ok(())
997 }
998
999 pub fn set_b32_array(
1000 &mut self,
1001 base: usize,
1002 row: usize,
1003 values: &[Block32],
1004 ) -> errors::Result<()> {
1005 for (i, &val) in values.iter().enumerate() {
1006 self.set_b32(base + i, row, val)?;
1007 }
1008
1009 Ok(())
1010 }
1011
1012 pub fn set_b64_array(
1013 &mut self,
1014 base: usize,
1015 row: usize,
1016 values: &[Block64],
1017 ) -> errors::Result<()> {
1018 for (i, &val) in values.iter().enumerate() {
1019 self.set_b64(base + i, row, val)?;
1020 }
1021
1022 Ok(())
1023 }
1024
1025 pub fn set_b128_array(
1026 &mut self,
1027 base: usize,
1028 row: usize,
1029 values: &[Block128],
1030 ) -> errors::Result<()> {
1031 for (i, &val) in values.iter().enumerate() {
1032 self.set_b128(base + i, row, val)?;
1033 }
1034
1035 Ok(())
1036 }
1037
1038 pub fn fill_selector(&mut self, col: usize, active_rows: usize) -> errors::Result<()> {
1045 let limit = active_rows.min(self.num_rows);
1046 let data = self.expect_bit_col(col)?;
1047
1048 for slot in data.iter_mut().take(limit) {
1049 *slot = Bit::ONE;
1050 }
1051
1052 Ok(())
1053 }
1054
1055 pub fn build(self) -> ColumnTrace {
1062 ColumnTrace {
1063 columns: self.columns,
1064 num_vars: self.num_vars,
1065 }
1066 }
1067
1068 #[inline]
1073 fn cursor(&self, col: usize) -> errors::Result<usize> {
1074 self.cursors.get(col).copied().ok_or_else(|| {
1075 Error::ColumnIndexOutOfBounds {
1076 col_idx: col,
1077 num_cols: self.columns.len(),
1078 }
1079 .into()
1080 })
1081 }
1082
1083 #[inline]
1084 fn expect_bit_col(&mut self, col: usize) -> errors::Result<&mut Vec<Bit>> {
1085 let num_cols = self.columns.len();
1086 let tc = self
1087 .columns
1088 .get_mut(col)
1089 .ok_or(Error::ColumnIndexOutOfBounds {
1090 col_idx: col,
1091 num_cols,
1092 })?;
1093
1094 match tc {
1095 TraceColumn::Bit(data) => Ok(data),
1096 other => Err(Error::ColumnTypeMismatch {
1097 col_idx: col,
1098 expected: "Bit",
1099 got: other.column_type_name(),
1100 }
1101 .into()),
1102 }
1103 }
1104
1105 #[inline]
1106 fn expect_b8_col(&mut self, col: usize) -> errors::Result<&mut Vec<Flat<Block8>>> {
1107 let num_cols = self.columns.len();
1108 let tc = self
1109 .columns
1110 .get_mut(col)
1111 .ok_or(Error::ColumnIndexOutOfBounds {
1112 col_idx: col,
1113 num_cols,
1114 })?;
1115
1116 match tc {
1117 TraceColumn::B8(data) => Ok(data),
1118 other => Err(Error::ColumnTypeMismatch {
1119 col_idx: col,
1120 expected: "B8",
1121 got: other.column_type_name(),
1122 }
1123 .into()),
1124 }
1125 }
1126
1127 #[inline]
1128 fn expect_b16_col(&mut self, col: usize) -> errors::Result<&mut Vec<Flat<Block16>>> {
1129 let num_cols = self.columns.len();
1130 let tc = self
1131 .columns
1132 .get_mut(col)
1133 .ok_or(Error::ColumnIndexOutOfBounds {
1134 col_idx: col,
1135 num_cols,
1136 })?;
1137
1138 match tc {
1139 TraceColumn::B16(data) => Ok(data),
1140 other => Err(Error::ColumnTypeMismatch {
1141 col_idx: col,
1142 expected: "B16",
1143 got: other.column_type_name(),
1144 }
1145 .into()),
1146 }
1147 }
1148
1149 #[inline]
1150 fn expect_b32_col(&mut self, col: usize) -> errors::Result<&mut Vec<Flat<Block32>>> {
1151 let num_cols = self.columns.len();
1152 let tc = self
1153 .columns
1154 .get_mut(col)
1155 .ok_or(Error::ColumnIndexOutOfBounds {
1156 col_idx: col,
1157 num_cols,
1158 })?;
1159
1160 match tc {
1161 TraceColumn::B32(data) => Ok(data),
1162 other => Err(Error::ColumnTypeMismatch {
1163 col_idx: col,
1164 expected: "B32",
1165 got: other.column_type_name(),
1166 }
1167 .into()),
1168 }
1169 }
1170
1171 #[inline]
1172 fn expect_b64_col(&mut self, col: usize) -> errors::Result<&mut Vec<Flat<Block64>>> {
1173 let num_cols = self.columns.len();
1174 let tc = self
1175 .columns
1176 .get_mut(col)
1177 .ok_or(Error::ColumnIndexOutOfBounds {
1178 col_idx: col,
1179 num_cols,
1180 })?;
1181
1182 match tc {
1183 TraceColumn::B64(data) => Ok(data),
1184 other => Err(Error::ColumnTypeMismatch {
1185 col_idx: col,
1186 expected: "B64",
1187 got: other.column_type_name(),
1188 }
1189 .into()),
1190 }
1191 }
1192
1193 #[inline]
1194 fn expect_b128_col(&mut self, col: usize) -> errors::Result<&mut Vec<Flat<Block128>>> {
1195 let num_cols = self.columns.len();
1196 let tc = self
1197 .columns
1198 .get_mut(col)
1199 .ok_or(Error::ColumnIndexOutOfBounds {
1200 col_idx: col,
1201 num_cols,
1202 })?;
1203
1204 match tc {
1205 TraceColumn::B128(data) => Ok(data),
1206 other => Err(Error::ColumnTypeMismatch {
1207 col_idx: col,
1208 expected: "B128",
1209 got: other.column_type_name(),
1210 }
1211 .into()),
1212 }
1213 }
1214}
1215
1216impl TraceColumn {
1217 fn column_type_name(&self) -> &'static str {
1218 match self {
1219 Self::Bit(_) => "Bit",
1220 Self::B8(_) => "B8",
1221 Self::B16(_) => "B16",
1222 Self::B32(_) => "B32",
1223 Self::B64(_) => "B64",
1224 Self::B128(_) => "B128",
1225 }
1226 }
1227}
1228
1229fn num_rows_from_num_vars(num_vars: usize) -> errors::Result<usize> {
1230 let num_vars_u32 = match u32::try_from(num_vars) {
1231 Ok(v) => v,
1232 Err(_) => {
1233 return Err(Error::InvalidParameters {
1234 message: "num_vars too large",
1235 }
1236 .into());
1237 }
1238 };
1239
1240 let Some(num_rows) = 1usize.checked_shl(num_vars_u32) else {
1241 return Err(Error::InvalidParameters {
1242 message: "num_rows overflow",
1243 }
1244 .into());
1245 };
1246
1247 if num_rows == 0 {
1248 return Err(Error::InvalidParameters {
1249 message: "num_rows is zero",
1250 }
1251 .into());
1252 }
1253
1254 Ok(num_rows)
1255}
1256
1257#[cfg(test)]
1262mod tests {
1263 use super::*;
1264 use crate::errors;
1265 use hekate_math::HardwareField;
1266
1267 fn create_mock_trace(num_vars: usize) -> ColumnTrace {
1268 ColumnTrace::new(num_vars).unwrap()
1269 }
1270
1271 #[test]
1272 fn trace_construction_basic() {
1273 let num_vars = 3;
1274 let mut trace = create_mock_trace(num_vars);
1275
1276 let col_data = vec![Block128::from(1u8); 8];
1277 trace.add_column(col_data.into_trace_column()).unwrap();
1278
1279 assert_eq!(trace.num_rows().unwrap(), 8);
1280 assert_eq!(trace.num_cols(), 1);
1281 assert_eq!(trace.num_vars, 3);
1282 }
1283
1284 #[test]
1285 fn trace_add_column_wrong_len() {
1286 let num_vars = 2;
1287 let mut trace = create_mock_trace(num_vars);
1288
1289 let col_data = vec![Block128::ZERO; 5];
1290 let err = trace
1291 .add_column(col_data.into_trace_column())
1292 .expect_err("Expected length mismatch error");
1293
1294 assert!(matches!(
1295 err,
1296 errors::Error::Trace(Error::ColumnLengthMismatch { .. })
1297 ));
1298 }
1299
1300 #[test]
1301 fn trace_get_element_mixed_types() {
1302 let num_vars = 1;
1303 let mut trace = create_mock_trace(num_vars);
1304
1305 trace
1306 .add_column(TraceColumn::Bit(vec![Bit::new(0), Bit::new(1)]))
1307 .unwrap();
1308 trace
1309 .add_column(vec![Block32::from(10u32), Block32::from(20u32)].into_trace_column())
1310 .unwrap();
1311
1312 let val0_r0: Flat<Block128> = trace.get_element(0, 0).unwrap();
1313 let val0_r1: Flat<Block128> = trace.get_element(0, 1).unwrap();
1314 let val1_r0: Flat<Block128> = trace.get_element(1, 0).unwrap();
1315 let val1_r1: Flat<Block128> = trace.get_element(1, 1).unwrap();
1316
1317 assert_eq!(val0_r0.into_raw(), Block128::ZERO);
1318 assert_eq!(val0_r1.into_raw(), Block128::ONE);
1319
1320 let expected_10 = Block128::promote_flat(Block32::from(10u32).to_hardware()).into_raw();
1321 let expected_20 = Block128::promote_flat(Block32::from(20u32).to_hardware()).into_raw();
1322
1323 assert_eq!(val1_r0.into_raw(), expected_10);
1324 assert_eq!(val1_r1.into_raw(), expected_20);
1325 }
1326
1327 #[test]
1328 fn get_element_oob_row() {
1329 let mut trace = create_mock_trace(1);
1330 trace
1331 .add_column(TraceColumn::Bit(vec![Bit::ZERO; 2]))
1332 .unwrap();
1333 trace
1334 .get_element::<Block128>(0, 2)
1335 .expect_err("Expected out-of-bounds row error");
1336 }
1337
1338 #[test]
1339 fn get_element_oob_col() {
1340 let trace = create_mock_trace(1);
1341 trace
1342 .get_element::<Block128>(0, 0)
1343 .expect_err("Expected out-of-bounds column error");
1344 }
1345
1346 #[test]
1351 fn get_column_slice_correct_type() {
1352 let mut trace = create_mock_trace(2);
1353 let data = vec![
1354 Block32::from(1u32),
1355 Block32::from(2u32),
1356 Block32::from(3u32),
1357 Block32::from(4u32),
1358 ];
1359 trace.add_column(data.clone().into_trace_column()).unwrap();
1360
1361 let expected_hw: Vec<Flat<Block32>> = data.into_iter().map(|x| x.to_hardware()).collect();
1362
1363 let slice: &[Flat<Block32>] = trace.get_column_slice(0).unwrap();
1364 assert_eq!(slice, expected_hw.as_slice());
1365 }
1366
1367 #[test]
1368 fn get_column_slice_wrong_type() {
1369 let mut trace = create_mock_trace(1);
1370 trace
1371 .add_column(vec![Block128::ZERO; 2].into_trace_column())
1372 .unwrap();
1373
1374 trace
1375 .get_column_slice::<Flat<Block32>>(0)
1376 .expect_err("Expected column type mismatch error");
1377 }
1378
1379 #[test]
1380 fn trace_stores_hardware_basis() {
1381 let mut trace = create_mock_trace(2);
1382
1383 let tower_data = vec![
1384 Block32::from(42u32),
1385 Block32::from(13u32),
1386 Block32::from(255u32),
1387 Block32::from(1u32),
1388 ];
1389
1390 let expected_hardware: Vec<Block32> = tower_data
1391 .iter()
1392 .map(|x| x.to_hardware().into_raw())
1393 .collect();
1394
1395 trace.add_column(tower_data.into_trace_column()).unwrap();
1396
1397 let stored: &[Flat<Block32>] = trace.get_column_slice(0).unwrap();
1398
1399 for (i, (&stored_val, &expected_val)) in
1400 stored.iter().zip(expected_hardware.iter()).enumerate()
1401 {
1402 assert_eq!(
1403 stored_val.into_raw(),
1404 expected_val,
1405 "Row {}: stored value {:?} != expected hardware {:?}",
1406 i,
1407 stored_val,
1408 expected_val
1409 );
1410 }
1411 }
1412
1413 #[test]
1414 fn trace_hardware_basis_homomorphism() {
1415 let mut trace = create_mock_trace(3);
1416
1417 let a_tower = vec![Block32::from(5u32); 8];
1418 let b_tower = vec![Block32::from(7u32); 8];
1419
1420 trace
1421 .add_column(a_tower.clone().into_trace_column())
1422 .unwrap();
1423 trace
1424 .add_column(b_tower.clone().into_trace_column())
1425 .unwrap();
1426
1427 let a_stored: &[Flat<Block32>] = trace.get_column_slice(0).unwrap();
1428 let b_stored: &[Flat<Block32>] = trace.get_column_slice(1).unwrap();
1429
1430 let a_hw_expected = a_tower[0].to_hardware().into_raw();
1431 let b_hw_expected = b_tower[0].to_hardware().into_raw();
1432
1433 assert_eq!(a_stored[0].into_raw(), a_hw_expected);
1434 assert_eq!(b_stored[0].into_raw(), b_hw_expected);
1435
1436 let product_hw = a_stored[0] * b_stored[0];
1437 let product_expected = (a_tower[0] * b_tower[0]).to_hardware().into_raw();
1438
1439 assert_eq!(product_hw.into_raw(), product_expected);
1440 }
1441
1442 #[test]
1447 fn trace_builder_construction_and_auto_padding() {
1448 let layout = &[ColumnType::B32, ColumnType::Bit];
1449 let tb = TraceBuilder::new(layout, 2).unwrap(); assert_eq!(tb.num_rows(), 4);
1451
1452 let trace = tb.build();
1453 assert_eq!(trace.num_cols(), 2);
1454 assert_eq!(trace.num_rows().unwrap(), 4);
1455
1456 assert!(trace.columns[0].is_all_zeros());
1458 assert!(trace.columns[1].is_all_zeros());
1459 }
1460
1461 #[test]
1462 fn trace_builder_set_b32_stores_hardware_basis() {
1463 let layout = &[ColumnType::B32];
1464 let mut tb = TraceBuilder::new(layout, 1).unwrap(); tb.set_b32(0, 0, Block32::from(42u32)).unwrap();
1467 tb.set_b32(0, 1, Block32::from(13u32)).unwrap();
1468
1469 let trace = tb.build();
1470 let stored: &[Flat<Block32>] = trace.get_column_slice(0).unwrap();
1471
1472 assert_eq!(stored[0], Block32::from(42u32).to_hardware());
1473 assert_eq!(stored[1], Block32::from(13u32).to_hardware());
1474 }
1475
1476 #[test]
1477 fn trace_builder_column_ordering_matches_schema() {
1478 let layout = &[ColumnType::Bit, ColumnType::B32, ColumnType::B128];
1479 let mut tb = TraceBuilder::new(layout, 1).unwrap();
1480
1481 tb.set_bit(0, 0, Bit::ONE).unwrap();
1482 tb.set_b32(1, 0, Block32::from(99u32)).unwrap();
1483 tb.set_b128(2, 0, Block128::from(7u8)).unwrap();
1484
1485 let trace = tb.build();
1486 assert_eq!(trace.columns[0].column_type(), ColumnType::Bit);
1487 assert_eq!(trace.columns[1].column_type(), ColumnType::B32);
1488 assert_eq!(trace.columns[2].column_type(), ColumnType::B128);
1489 }
1490
1491 #[test]
1492 fn trace_builder_type_mismatch_returns_error() {
1493 let layout = &[ColumnType::Bit];
1494 let mut tb = TraceBuilder::new(layout, 1).unwrap();
1495
1496 let err = tb.set_b32(0, 0, Block32::ZERO);
1497 assert!(err.is_err());
1498 }
1499
1500 #[test]
1501 fn trace_builder_row_out_of_bounds_returns_error() {
1502 let layout = &[ColumnType::B32];
1503 let mut tb = TraceBuilder::new(layout, 1).unwrap(); let err = tb.set_b32(0, 2, Block32::ZERO);
1506 assert!(err.is_err());
1507 }
1508
1509 #[test]
1510 fn trace_builder_col_out_of_bounds_returns_error() {
1511 let layout = &[ColumnType::B32];
1512 let mut tb = TraceBuilder::new(layout, 1).unwrap();
1513
1514 let err = tb.set_b32(1, 0, Block32::ZERO);
1515 assert!(err.is_err());
1516 }
1517
1518 #[test]
1519 fn trace_builder_fill_selector() {
1520 let layout = &[ColumnType::Bit];
1521 let mut tb = TraceBuilder::new(layout, 2).unwrap(); tb.fill_selector(0, 3).unwrap(); let trace = tb.build();
1526 let bits = trace.columns[0].as_bit_slice().unwrap();
1527 assert_eq!(bits[0], Bit::ONE);
1528 assert_eq!(bits[1], Bit::ONE);
1529 assert_eq!(bits[2], Bit::ONE);
1530 assert_eq!(bits[3], Bit::ZERO); }
1532
1533 #[test]
1534 fn trace_builder_push_mode() {
1535 let layout = &[ColumnType::B32, ColumnType::Bit];
1536 let mut tb = TraceBuilder::new(layout, 1).unwrap(); tb.push_b32(0, Block32::from(10u32)).unwrap();
1539 tb.push_b32(0, Block32::from(20u32)).unwrap();
1540 tb.push_bit(1, Bit::ONE).unwrap();
1541 let trace = tb.build();
1544 let b32s: &[Flat<Block32>] = trace.get_column_slice(0).unwrap();
1545 assert_eq!(b32s[0], Block32::from(10u32).to_hardware());
1546 assert_eq!(b32s[1], Block32::from(20u32).to_hardware());
1547
1548 let bits = trace.columns[1].as_bit_slice().unwrap();
1549 assert_eq!(bits[0], Bit::ONE);
1550 assert_eq!(bits[1], Bit::ZERO);
1551 }
1552
1553 #[test]
1554 fn trace_builder_set_b32_array() {
1555 let layout = &[ColumnType::B32, ColumnType::B32, ColumnType::B32];
1556 let mut tb = TraceBuilder::new(layout, 1).unwrap(); let vals = [
1559 Block32::from(1u32),
1560 Block32::from(2u32),
1561 Block32::from(3u32),
1562 ];
1563 tb.set_b32_array(0, 0, &vals).unwrap();
1564
1565 let trace = tb.build();
1566 for (i, &expected) in vals.iter().enumerate() {
1567 let stored: &[Flat<Block32>] = trace.get_column_slice(i).unwrap();
1568 assert_eq!(stored[0], expected.to_hardware());
1569 }
1570 }
1571
1572 #[test]
1573 fn trace_builder_set_b8() {
1574 let layout = &[ColumnType::B8];
1575 let mut tb = TraceBuilder::new(layout, 1).unwrap();
1576
1577 tb.set_b8(0, 0, Block8(0xAB)).unwrap();
1578 tb.set_b8(0, 1, Block8(0xCD)).unwrap();
1579
1580 let trace = tb.build();
1581 let stored: &[Flat<Block8>] = trace.get_column_slice(0).unwrap();
1582 assert_eq!(stored[0], Block8(0xAB).to_hardware());
1583 assert_eq!(stored[1], Block8(0xCD).to_hardware());
1584 }
1585
1586 #[test]
1587 fn trace_builder_set_b16() {
1588 let layout = &[ColumnType::B16];
1589 let mut tb = TraceBuilder::new(layout, 1).unwrap();
1590
1591 tb.set_b16(0, 0, Block16(1000)).unwrap();
1592 tb.set_b16(0, 1, Block16(2000)).unwrap();
1593
1594 let trace = tb.build();
1595 let stored: &[Flat<Block16>] = trace.get_column_slice(0).unwrap();
1596 assert_eq!(stored[0], Block16(1000).to_hardware());
1597 assert_eq!(stored[1], Block16(2000).to_hardware());
1598 }
1599
1600 #[test]
1601 fn trace_builder_set_b64() {
1602 let layout = &[ColumnType::B64];
1603 let mut tb = TraceBuilder::new(layout, 1).unwrap();
1604
1605 tb.set_b64(0, 0, Block64(0xDEADBEEF_CAFEBABE)).unwrap();
1606
1607 let trace = tb.build();
1608 let stored: &[Flat<Block64>] = trace.get_column_slice(0).unwrap();
1609 assert_eq!(stored[0], Block64(0xDEADBEEF_CAFEBABE).to_hardware());
1610 assert_eq!(stored[1], Block64::ZERO.to_hardware()); }
1612
1613 #[test]
1614 fn trace_builder_set_b128() {
1615 let layout = &[ColumnType::B128];
1616 let mut tb = TraceBuilder::new(layout, 1).unwrap();
1617
1618 let val = Block128::from(0xFFu8);
1619 tb.set_b128(0, 0, val).unwrap();
1620
1621 let trace = tb.build();
1622 let stored: &[Flat<Block128>] = trace.get_column_slice(0).unwrap();
1623 assert_eq!(stored[0], val.to_hardware());
1624 }
1625
1626 #[test]
1627 fn trace_builder_push_all_types() {
1628 let layout = &[
1629 ColumnType::Bit,
1630 ColumnType::B8,
1631 ColumnType::B16,
1632 ColumnType::B32,
1633 ColumnType::B64,
1634 ColumnType::B128,
1635 ];
1636 let mut tb = TraceBuilder::new(layout, 1).unwrap(); tb.push_bit(0, Bit::ONE).unwrap();
1639 tb.push_b8(1, Block8(0x42)).unwrap();
1640 tb.push_b16(2, Block16(1234)).unwrap();
1641 tb.push_b32(3, Block32::from(5678u32)).unwrap();
1642 tb.push_b64(4, Block64(9999)).unwrap();
1643 tb.push_b128(5, Block128::from(77u8)).unwrap();
1644
1645 let trace = tb.build();
1646 assert_eq!(trace.num_cols(), 6);
1647
1648 let bits = trace.columns[0].as_bit_slice().unwrap();
1649 assert_eq!(bits[0], Bit::ONE);
1650 assert_eq!(bits[1], Bit::ZERO); let b8s: &[Flat<Block8>] = trace.get_column_slice(1).unwrap();
1653 assert_eq!(b8s[0], Block8(0x42).to_hardware());
1654
1655 let b16s: &[Flat<Block16>] = trace.get_column_slice(2).unwrap();
1656 assert_eq!(b16s[0], Block16(1234).to_hardware());
1657
1658 let b32s: &[Flat<Block32>] = trace.get_column_slice(3).unwrap();
1659 assert_eq!(b32s[0], Block32::from(5678u32).to_hardware());
1660
1661 let b64s: &[Flat<Block64>] = trace.get_column_slice(4).unwrap();
1662 assert_eq!(b64s[0], Block64(9999).to_hardware());
1663
1664 let b128s: &[Flat<Block128>] = trace.get_column_slice(5).unwrap();
1665 assert_eq!(b128s[0], Block128::from(77u8).to_hardware());
1666 }
1667
1668 #[test]
1669 fn trace_builder_type_mismatch_all_setters() {
1670 let layout = &[ColumnType::B32];
1672 let mut tb = TraceBuilder::new(layout, 1).unwrap();
1673
1674 assert!(tb.set_bit(0, 0, Bit::ONE).is_err());
1675 assert!(tb.set_b8(0, 0, Block8(1)).is_err());
1676 assert!(tb.set_b16(0, 0, Block16(1)).is_err());
1677 assert!(tb.set_b64(0, 0, Block64(1)).is_err());
1678 assert!(tb.set_b128(0, 0, Block128::ONE).is_err());
1679
1680 assert!(tb.set_b32(0, 0, Block32::ONE).is_ok());
1682 }
1683
1684 #[test]
1685 fn trace_builder_array_setters_all_types() {
1686 let layout = &[
1687 ColumnType::Bit,
1688 ColumnType::Bit,
1689 ColumnType::B8,
1690 ColumnType::B8,
1691 ColumnType::B64,
1692 ColumnType::B64,
1693 ColumnType::B128,
1694 ColumnType::B128,
1695 ];
1696 let mut tb = TraceBuilder::new(layout, 1).unwrap();
1697
1698 tb.set_bit_array(0, 0, &[Bit::ONE, Bit::ZERO]).unwrap();
1699 tb.set_b8_array(2, 0, &[Block8(10), Block8(20)]).unwrap();
1700 tb.set_b64_array(4, 0, &[Block64(100), Block64(200)])
1701 .unwrap();
1702 tb.set_b128_array(6, 0, &[Block128::ONE, Block128::from(2u8)])
1703 .unwrap();
1704
1705 let trace = tb.build();
1706
1707 let bits = trace.columns[0].as_bit_slice().unwrap();
1708 assert_eq!(bits[0], Bit::ONE);
1709
1710 let bits1 = trace.columns[1].as_bit_slice().unwrap();
1711 assert_eq!(bits1[0], Bit::ZERO);
1712
1713 let b8s: &[Flat<Block8>] = trace.get_column_slice(2).unwrap();
1714 assert_eq!(b8s[0], Block8(10).to_hardware());
1715
1716 let b8s1: &[Flat<Block8>] = trace.get_column_slice(3).unwrap();
1717 assert_eq!(b8s1[0], Block8(20).to_hardware());
1718 }
1719
1720 #[test]
1721 fn trace_builder_invalid_num_vars() {
1722 let layout = &[ColumnType::B32];
1723 assert!(TraceBuilder::new(layout, 128).is_err());
1725 }
1726}