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