1use itertools::Itertools;
2use num_traits::Zero;
3use triton_vm::prelude::*;
4use twenty_first::error::BFieldCodecError;
5use twenty_first::error::PolynomialBFieldCodecError;
6use twenty_first::math::x_field_element::EXTENSION_DEGREE;
7use twenty_first::prelude::*;
8
9use super::tasm_object::Result;
10use crate::prelude::*;
11use crate::structure::tasm_object::DEFAULT_MAX_DYN_FIELD_SIZE;
12
13const VEC_LEN_EXCEEDS_MAX: i128 = 212;
14const POLYNOMIAL_LEN_EXCEEDS_MAX: i128 = 213;
15
16impl<const N: usize, T> TasmObject for [T; N]
17where
18 T: TasmObject,
19{
20 fn label_friendly_name() -> String {
21 format!("array{N}___{}", T::label_friendly_name())
22 }
23
24 fn compute_size_and_assert_valid_size_indicator(_: &mut Library) -> Vec<LabelledInstruction> {
25 if let Some(static_size) = Self::static_length() {
26 return triton_asm!(
27 pop 1
30 push {static_size}
31 );
33 }
34
35 todo!()
36 }
37
38 fn decode_iter<Itr: Iterator<Item = BFieldElement>>(iterator: &mut Itr) -> Result<Box<Self>> {
39 let mut vector = Vec::with_capacity(N);
40 for _ in 0..N {
41 if T::static_length().is_none() {
42 iterator.next().ok_or(BFieldCodecError::SequenceTooShort)?;
43 };
44 vector.push(*T::decode_iter(iterator)?);
45 }
46
47 let Ok(array) = vector.try_into() else {
49 unreachable!()
50 };
51
52 Ok(Box::new(array))
53 }
54}
55
56impl<T> TasmObject for Vec<T>
57where
58 T: TasmObject,
59{
60 fn label_friendly_name() -> String {
61 format!("vec___{}", T::label_friendly_name())
62 }
63
64 fn compute_size_and_assert_valid_size_indicator(
65 library: &mut Library,
66 ) -> Vec<LabelledInstruction> {
67 if let Some(static_size) = T::static_length() {
68 let assert_len_is_u32 = if static_size == 1 {
71 triton_asm!()
74 } else {
75 triton_asm!(
76 push {DEFAULT_MAX_DYN_FIELD_SIZE}
79 dup 2
80 lt
81 assert error_id {VEC_LEN_EXCEEDS_MAX}
84 )
86 };
87
88 return triton_asm!(
89 read_mem 1
92 {&assert_len_is_u32}
95 {&T::compute_size_and_assert_valid_size_indicator(library)}
98 mul
101 addi 1
102 );
105 }
106
107 let loop_label = format!(
108 "tasmlib_structure_tasmobject_verify_size_indicators_dyn_elem_sizes___{}",
109 T::label_friendly_name()
110 );
111
112 let loop_code = triton_asm!(
113 {loop_label}:
115
116 dup 2
117 push 0
118 eq
119 skiz
120 return
121 read_mem 1
124 push {T::MAX_OFFSET}
128 dup 2
129 lt
130 assert error_id 210
131 addi 2
134 dup 0
137 {&T::compute_size_and_assert_valid_size_indicator(library)}
138 dup 2
141 eq
142 assert error_id 211
143 pick 2
146 dup 2
147 add
148 addi 1
152 place 2
155 add
158 pick 2
161 addi -1
162 place 2
163 recurse
166 );
167
168 library.explicit_import(&loop_label, &loop_code);
169 triton_asm!(
170 read_mem 1
173 hint remaining_elements = stack[1]
174 addi 2
177 hint elem_si_ptr = stack[0]
178 push 0
182 hint acc_size = stack[0]
183 place 1
186 call {loop_label}
189 pick 2
192 pop 2
193 addi 1
197 )
198 }
199
200 fn decode_iter<Itr: Iterator<Item = BFieldElement>>(iterator: &mut Itr) -> Result<Box<Self>> {
201 let vec_length = iterator.next().ok_or(BFieldCodecError::SequenceTooShort)?;
202 let mut vector = vec![];
203 for _ in 0..vec_length.value() {
204 if T::static_length().is_none() {
205 iterator.next().ok_or(BFieldCodecError::SequenceTooShort)?;
206 };
207 vector.push(*T::decode_iter(iterator)?);
208 }
209
210 Ok(Box::new(vector))
211 }
212}
213
214impl TasmObject for BFieldElement {
215 fn label_friendly_name() -> String {
216 DataType::Bfe.label_friendly_name()
217 }
218
219 fn compute_size_and_assert_valid_size_indicator(_: &mut Library) -> Vec<LabelledInstruction> {
220 triton_asm!(pop 1 push {Self::static_length().unwrap()})
221 }
222
223 fn decode_iter<Itr: Iterator<Item = BFieldElement>>(iterator: &mut Itr) -> Result<Box<Self>> {
224 let word = iterator.next().ok_or(BFieldCodecError::SequenceTooShort)?;
225 Ok(Box::new(word))
226 }
227}
228
229impl TasmObject for XFieldElement {
230 fn label_friendly_name() -> String {
231 DataType::Xfe.label_friendly_name()
232 }
233
234 fn compute_size_and_assert_valid_size_indicator(_: &mut Library) -> Vec<LabelledInstruction> {
235 triton_asm!(pop 1 push {Self::static_length().unwrap()})
236 }
237
238 fn decode_iter<Itr: Iterator<Item = BFieldElement>>(iterator: &mut Itr) -> Result<Box<Self>> {
239 let (c_0, c_1, c_2) = iterator
240 .next_tuple()
241 .ok_or(BFieldCodecError::SequenceTooShort)?;
242
243 Ok(Box::new(xfe!([c_0, c_1, c_2])))
244 }
245}
246
247impl TasmObject for Digest {
248 fn label_friendly_name() -> String {
249 DataType::Digest.label_friendly_name()
250 }
251
252 fn compute_size_and_assert_valid_size_indicator(_: &mut Library) -> Vec<LabelledInstruction> {
253 triton_asm!(pop 1 push {Self::static_length().unwrap()})
254 }
255
256 fn decode_iter<Itr: Iterator<Item = BFieldElement>>(iterator: &mut Itr) -> Result<Box<Self>> {
257 let (d_0, d_1, d_2, d_3, d_4) = iterator
258 .next_tuple()
259 .ok_or(BFieldCodecError::SequenceTooShort)?;
260
261 Ok(Box::new(Digest::new([d_0, d_1, d_2, d_3, d_4])))
262 }
263}
264
265impl TasmObject for bool {
266 fn label_friendly_name() -> String {
267 DataType::Bool.label_friendly_name()
268 }
269
270 fn compute_size_and_assert_valid_size_indicator(_: &mut Library) -> Vec<LabelledInstruction> {
271 triton_asm!(pop 1 push {Self::static_length().unwrap()})
272 }
273
274 fn decode_iter<Itr: Iterator<Item = BFieldElement>>(iterator: &mut Itr) -> Result<Box<Self>> {
275 let the_bool = iterator.next().ok_or(BFieldCodecError::SequenceTooShort)?;
276 match the_bool.value() {
277 0 => Ok(Box::new(false)),
278 1 => Ok(Box::new(true)),
279 _ => Err(Box::new(BFieldCodecError::ElementOutOfRange)),
280 }
281 }
282}
283
284impl TasmObject for u32 {
285 fn label_friendly_name() -> String {
286 DataType::U32.label_friendly_name()
287 }
288
289 fn compute_size_and_assert_valid_size_indicator(_: &mut Library) -> Vec<LabelledInstruction> {
290 triton_asm!(pop 1 push {Self::static_length().unwrap()})
291 }
292
293 fn decode_iter<Itr: Iterator<Item = BFieldElement>>(iterator: &mut Itr) -> Result<Box<Self>> {
294 let word = iterator
295 .next()
296 .ok_or(BFieldCodecError::SequenceTooShort)?
297 .try_into()
298 .map_err(|_| BFieldCodecError::ElementOutOfRange)?;
299
300 Ok(Box::new(word))
301 }
302}
303
304impl TasmObject for u64 {
305 fn label_friendly_name() -> String {
306 DataType::U64.label_friendly_name()
307 }
308
309 fn compute_size_and_assert_valid_size_indicator(_: &mut Library) -> Vec<LabelledInstruction> {
310 triton_asm!(pop 1 push {Self::static_length().unwrap()})
311 }
312
313 fn decode_iter<Itr: Iterator<Item = BFieldElement>>(iterator: &mut Itr) -> Result<Box<Self>> {
314 let (val_lo, val_hi) = iterator
315 .next_tuple()
316 .ok_or(BFieldCodecError::SequenceTooShort)?;
317
318 Ok(Self::decode(&[val_lo, val_hi])?)
319 }
320}
321
322impl TasmObject for u128 {
323 fn label_friendly_name() -> String {
324 DataType::U128.label_friendly_name()
325 }
326
327 fn compute_size_and_assert_valid_size_indicator(_: &mut Library) -> Vec<LabelledInstruction> {
328 triton_asm!(pop 1 push {Self::static_length().unwrap()})
329 }
330
331 fn decode_iter<Itr: Iterator<Item = BFieldElement>>(iterator: &mut Itr) -> Result<Box<Self>> {
332 let (lo_lo, lo_hi, hi_lo, hi_hi) = iterator
333 .next_tuple()
334 .ok_or(BFieldCodecError::SequenceTooShort)?;
335
336 Ok(Self::decode(&[lo_lo, lo_hi, hi_lo, hi_hi])?)
337 }
338}
339
340impl<T, S> TasmObject for (T, S)
341where
342 T: TasmObject,
343 S: TasmObject,
344{
345 fn label_friendly_name() -> String {
346 format!(
347 "tuple_L_{}_{}_R",
348 T::label_friendly_name(),
349 S::label_friendly_name()
350 )
351 }
352
353 fn compute_size_and_assert_valid_size_indicator(
354 library: &mut Library,
355 ) -> Vec<LabelledInstruction> {
356 let size_left = if T::static_length().is_some() {
357 T::compute_size_and_assert_valid_size_indicator(library)
358 } else {
359 triton_asm!(
360 hint left_si_ptr = stack[0]
362
363 read_mem 1
364 addi 2
365 {&T::compute_size_and_assert_valid_size_indicator(library)}
368 hint calculated_left = stack[0]
369 dup 1
372 eq
373 assert error_id 220
374 addi 1
377 )
379 };
380
381 let size_right = if S::static_length().is_some() {
382 S::compute_size_and_assert_valid_size_indicator(library)
383 } else {
384 triton_asm!(
385 hint right_si_ptr = stack[0]
387
388 read_mem 1
389 hint right_si = stack[1]
390 addi 2
394 {&S::compute_size_and_assert_valid_size_indicator(library)}
397 hint calculated_right = stack[0]
398 dup 1
401 eq
402 assert error_id 221
403 addi 1
407 )
409 };
410
411 triton_asm!(
412 dup 0
415 {&size_right}
416 hint right_ptr_or_right_si = stack[1]
417 hint right_size_incl_pot_si = stack[0]
418 pick 1
421 dup 1
422 add
423 hint left: Pointer = stack[0]
424 {&size_left}
428 hint left_size_incl_si = stack[0]
429 add
432 )
434 }
435
436 fn decode_iter<Itr: Iterator<Item = BFieldElement>>(iterator: &mut Itr) -> Result<Box<Self>> {
437 if S::static_length().is_none() {
438 iterator.next().ok_or(BFieldCodecError::SequenceTooShort)?;
439 }
440 let s = *S::decode_iter(iterator)?;
441
442 if T::static_length().is_none() {
443 iterator.next().ok_or(BFieldCodecError::SequenceTooShort)?;
444 }
445 let t = *T::decode_iter(iterator)?;
446
447 Ok(Box::new((t, s)))
448 }
449}
450
451impl TasmObject for Polynomial<'static, XFieldElement> {
452 fn label_friendly_name() -> String {
453 "polynomial_xfe".to_owned()
454 }
455
456 fn compute_size_and_assert_valid_size_indicator(_: &mut Library) -> Vec<LabelledInstruction> {
457 let assert_len_is_u32 = triton_asm!(
460 push {DEFAULT_MAX_DYN_FIELD_SIZE}
463 dup 2
464 lt
465 assert error_id {POLYNOMIAL_LEN_EXCEEDS_MAX}
468 );
469
470 triton_asm!(
471 addi 1
474 read_mem 2
477 pop 1
478 {&assert_len_is_u32}
481
482 push {Self::MAX_OFFSET}
483 dup 1
484 lt
485 assert
486 pick 1
489 push {EXTENSION_DEGREE}
490 mul
491 addi 1
492 dup 1
495 eq
496 assert
497 addi 1
501 )
502 }
503
504 fn decode_iter<Itr: Iterator<Item = BFieldElement>>(iterator: &mut Itr) -> Result<Box<Self>> {
505 iterator.next().ok_or(BFieldCodecError::SequenceTooShort)?;
506 let coefficients = *Vec::<XFieldElement>::decode_iter(iterator)?;
507 if coefficients.last().is_some_and(|c| c.is_zero()) {
508 return Err(Box::new(
509 PolynomialBFieldCodecError::TrailingZerosInPolynomialEncoding,
510 ));
511 }
512
513 Ok(Box::new(Self::new(coefficients)))
514 }
515}
516
517impl TasmObject for Proof {
518 fn label_friendly_name() -> String {
519 "tvm_proof".to_owned()
520 }
521
522 fn compute_size_and_assert_valid_size_indicator(_: &mut Library) -> Vec<LabelledInstruction> {
523 triton_asm!(
529 read_mem 1
532 pop 1
533 addi 1
536 )
538 }
539
540 fn decode_iter<Itr: Iterator<Item = BFieldElement>>(iterator: &mut Itr) -> Result<Box<Self>> {
541 let _ = iterator.next().ok_or(BFieldCodecError::SequenceTooShort)?;
542 Ok(Box::new(Self(*Vec::decode_iter(iterator)?)))
543 }
544}
545
546impl<T> TasmObject for Option<T>
547where
548 T: TasmObject,
549{
550 fn label_friendly_name() -> String {
551 format!("option_L_{}_R", T::label_friendly_name())
552 }
553
554 fn compute_size_and_assert_valid_size_indicator(
555 library: &mut Library,
556 ) -> Vec<LabelledInstruction> {
557 let some_branch_label = format!(
558 "tasmlib_tasmobject_size_verifier_option_some_branch___{}",
559 T::label_friendly_name()
560 );
561 let some_branch = triton_asm!(
562 {some_branch_label}:
563
564 pop 1
566
567 {&T::compute_size_and_assert_valid_size_indicator(library)}
568 push 0
572
573 return
574 );
575
576 let none_branch_label = "tasmlib_tasmobject_size_verifier_option_none".to_owned();
577 let none_branch = triton_asm!(
578 {none_branch_label}:
579 pop 1
582 push 0
583 return
586 );
587
588 library.explicit_import(&some_branch_label, &some_branch);
589 library.explicit_import(&none_branch_label, &none_branch);
590
591 triton_asm!(
592 read_mem 1
594 addi 2
595 dup 1
599 push 0
600 eq
601 dup 2
602 push 1
603 eq
604 add
605 assert error_id 200
608 push 1
611 pick 2
614 push 1
615 eq
616 skiz
619 call {some_branch_label}
620 skiz
621 call {none_branch_label}
622
623 addi 1
625
626 )
628 }
629
630 fn decode_iter<Itr: Iterator<Item = BFieldElement>>(iterator: &mut Itr) -> Result<Box<Self>> {
631 let is_some = *bool::decode_iter(iterator)?;
632 let the_option = is_some.then(|| T::decode_iter(iterator)).transpose()?;
633 Ok(Box::new(the_option.map(|t| *t)))
634 }
635}
636
637#[cfg(test)]
638mod tests {
639 use std::collections::HashMap;
640 use std::fmt::Debug;
641
642 use super::*;
643 use crate::memory::encode_to_memory;
644 use crate::test_prelude::*;
645
646 #[derive(Debug, Clone, Arbitrary)]
647 struct TestObject<T>
648 where
649 T: TasmObject + Debug + Clone + Eq + for<'a> arbitrary::Arbitrary<'a> + 'static,
650 {
651 #[strategy(arb())]
652 t: T,
653
654 #[strategy(arb())]
655 address: BFieldElement,
656 }
657
658 impl<T> TestObject<T>
659 where
660 T: TasmObject + Debug + Clone + Eq + for<'a> arbitrary::Arbitrary<'a>,
661 {
662 fn verify_decoding_properties(&self) -> TestCaseResult {
663 let mut memory = HashMap::default();
664 encode_to_memory(&mut memory, self.address, &self.t);
665 let decoding_result = T::decode_from_memory(&memory, self.address);
666 prop_assert!(decoding_result.is_ok());
667
668 let obj_read = *decoding_result.unwrap();
669 prop_assert_eq!(&self.t, &obj_read);
670
671 Ok(())
672 }
673 }
674
675 macro_rules! gen_test {
677 (fn $test_fn:ident for $type:ty) => {
678 #[macro_rules_attr::apply(proptest)]
679 fn $test_fn(test_object: TestObject<$type>) {
680 test_object.verify_decoding_properties()?;
681 }
682 };
683 }
684
685 gen_test!(fn decode_bfe for BFieldElement);
686 gen_test!(fn decode_xfe for XFieldElement);
687 gen_test!(fn decode_digest for Digest);
688 gen_test!(fn decode_bool for bool);
689 gen_test!(fn decode_u32 for u32);
690 gen_test!(fn decode_u64 for u64);
691 gen_test!(fn decode_u128 for u128);
692 gen_test!(fn decode_poly_xfe for Polynomial<'static, XFieldElement>);
693 gen_test!(fn decode_proof for Proof);
694
695 gen_test!(fn decode_array_bfe_0 for [BFieldElement; 0]);
696 gen_test!(fn decode_array_bfe_2 for [BFieldElement; 2]);
697 gen_test!(fn decode_array_bfe_10 for [BFieldElement; 10]);
698 gen_test!(fn decode_array_bfe_25 for [BFieldElement; 25]);
699 gen_test!(fn decode_array_xfe_0 for [BFieldElement; 0]);
700 gen_test!(fn decode_array_xfe_2 for [BFieldElement; 2]);
701 gen_test!(fn decode_array_xfe_10 for [BFieldElement; 10]);
702 gen_test!(fn decode_array_xfe_25 for [BFieldElement; 25]);
703 gen_test!(fn decode_array_vec_bfe_0 for [Vec<BFieldElement>; 0]);
704 gen_test!(fn decode_array_vec_bfe_2 for [Vec<BFieldElement>; 2]);
705 gen_test!(fn decode_array_vec_vec_bfe_2 for [Vec<Vec<BFieldElement>>; 2]);
706 gen_test!(fn decode_array_tuple_l_bfe_bfe_r_0 for [(BFieldElement, BFieldElement); 0]);
707 gen_test!(fn decode_array_tuple_l_bfe_bfe_r_2 for [(BFieldElement, BFieldElement); 2]);
708 gen_test!(fn decode_array_tuple_l_u64_u128_r_0 for [(u64, u128); 0]);
709 gen_test!(fn decode_array_tuple_l_u64_u128_r_2 for [(u64, u128); 2]);
710 gen_test!(fn decode_array_tuple_l_vec_u64_vec_u64_r_2 for [(Vec<u64>, Vec<u64>); 2]);
711 gen_test!(fn decode_array_option_bfe_0 for [Option<BFieldElement>; 0]);
712 gen_test!(fn decode_array_option_bfe_5 for [Option<BFieldElement>; 5]);
713 gen_test!(fn decode_array_option_vec_u64_5 for [Option<Vec<u64>>; 5]);
714
715 gen_test!(fn decode_vec_bfe for Vec<BFieldElement>);
716 gen_test!(fn decode_vec_xfe for Vec<XFieldElement>);
717 gen_test!(fn decode_vec_digest for Vec<Digest>);
718 gen_test!(fn decode_vec_array_u32_0 for Vec<[u32; 0]>);
719 gen_test!(fn decode_vec_array_u32_7 for Vec<[u32; 7]>);
720 gen_test!(fn decode_vec_array_u64_0 for Vec<[u64; 0]>);
721 gen_test!(fn decode_vec_array_u64_7 for Vec<[u64; 7]>);
722 gen_test!(fn decode_vec_vec_digest for Vec<Vec<Digest>>);
723 gen_test!(fn decode_vec_tuple_l_u32_u64_r for Vec<(u32, u64)>);
724 gen_test!(fn decode_vec_vec_tuple_l_u32_u64_r for Vec<Vec<(u32, u64)>>);
725 gen_test!(fn decode_vec_tuple_l_vec_u32_vec_u64_r for Vec<(Vec<u32>, Vec<u64>)>);
726 gen_test!(fn decode_vec_option_bfe for Vec<Option<BFieldElement>>);
727 gen_test!(fn decode_vec_option_tuple_l_u128_vec_digest_r for Vec<Option<(u128, Vec<Digest>)>>);
728
729 gen_test!(fn decode_tuple_l_bfe_bfe_r for (BFieldElement, BFieldElement));
730 gen_test!(fn decode_tuple_l_bfe_xfe_r for (BFieldElement, XFieldElement));
731 gen_test!(fn decode_tuple_l_digest_xfe_r for (Digest, XFieldElement));
732 gen_test!(fn decode_tuple_l_digest_vec_xfe_r for (Digest, Vec<XFieldElement>));
733 gen_test!(fn decode_tuple_l_vec_digest_xfe_r for (Vec<Digest>, XFieldElement));
734 gen_test!(fn decode_tuple_l_digest_array_xfe_0_r for (Digest, [XFieldElement; 0]));
735 gen_test!(fn decode_tuple_l_digest_array_xfe_5_r for (Digest, [XFieldElement; 5]));
736 gen_test!(fn decode_tuple_l_array_xfe_0_digest_r for ([XFieldElement; 0], Digest));
737 gen_test!(fn decode_tuple_l_array_xfe_5_digest_r for ([XFieldElement; 5], Digest));
738 gen_test!(fn decode_tuple_l_array_u128_5_u64_5_digest_r for ([u128; 5], [u64; 5]));
739 gen_test!(fn decode_tuple_l_vec_u64_array_xfe_5_r for (Vec<u64>, [XFieldElement; 5]));
740 gen_test!(fn decode_tuple_l_tuple_l_u32_u64_r_u128_r for ((u32, u64), u128));
741 gen_test!(fn decode_tuple_l_u32_tuple_l_u64_u128_r_r for (u32, (u64, u128)));
742 gen_test!(fn decode_tuple_l_tuple_l_u32_u64_r_tuple_l_u64_u32_r_r for ((u32, u64), (u64, u32)));
743 gen_test!(fn decode_tuple_l_vec_vec_u32_vec_vec_u128_r for (Vec<Vec<u32>>, Vec<Vec<u128>>));
744 gen_test!(fn decode_tuple_l_option_u32_option_u64_r for (Option<u32>, Option<u64>));
745 gen_test!(fn decode_tuple_l_option_vec_u32_option_u64_r for (Option<Vec<u32>>, Option<u64>));
746
747 gen_test!(fn decode_option_bfe for Option<BFieldElement>);
748 gen_test!(fn decode_option_xfe for Option<XFieldElement>);
749 gen_test!(fn decode_option_digest for Option<Digest>);
750 gen_test!(fn decode_option_vec_bfe for Option<Vec<BFieldElement>>);
751 gen_test!(fn decode_option_vec_xfe for Option<Vec<XFieldElement>>);
752 gen_test!(fn decode_option_option_bfe for Option<Option<BFieldElement>>);
753 gen_test!(fn decode_option_array_bfe_0 for Option<[BFieldElement; 0]>);
754 gen_test!(fn decode_option_array_xfe_5 for Option<[XFieldElement; 5]>);
755 gen_test!(fn decode_option_tuple_l_bfe_xfe_r for Option<(BFieldElement, XFieldElement)>);
756 gen_test!(fn decode_option_tuple_l_u32_u64_r for Option<(u32, u64)>);
757 gen_test!(fn decode_option_vec_tuple_l_bfe_u128_r for Option<Vec<(BFieldElement, u128)>>);
758 gen_test!(fn decode_option_tuple_l_vec_u32_vec_u64_r for Option<(Vec<u32>, Vec<u64>)>);
759 gen_test!(fn decode_option_tuple_l_array_u128_5_u64_5_r for Option<([u128; 5], [u64; 5])>);
760}