Skip to main content

tasm_lib/structure/
manual_tasm_object_implementations.rs

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                // _ *elem[0]
28
29                pop 1
30                push {static_size}
31                // _ own_size
32            );
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        // `unwrap()` needs `T` to implement `Debug` – unwrap manually instead
48        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            // Assert length is bounded such that `len * elem_size` cannot
69            // wrap around modulus p.
70            let assert_len_is_u32 = if static_size == 1 {
71                // _ nop because check is not needed, and because it would
72                // change downstream program hashes in committed-to UTXOs.
73                triton_asm!()
74            } else {
75                triton_asm!(
76                    // _ list_len g
77
78                    push {DEFAULT_MAX_DYN_FIELD_SIZE}
79                    dup 2
80                    lt
81                    // _ list_len g (max > list_len)
82
83                    assert error_id {VEC_LEN_EXCEEDS_MAX}
84                    // _ list_len g
85                )
86            };
87
88            return triton_asm!(
89                // _ *list_len
90
91                read_mem 1
92                // _ list_len *elem[0]
93
94                {&assert_len_is_u32}
95                // _ list_len *elem[0]
96
97                {&T::compute_size_and_assert_valid_size_indicator(library)}
98                // _ list_len elem_size
99
100                mul
101                addi 1
102                // _ (list_len * elem_size + 1)
103                // _ calculated_size
104            );
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            // INVARIANT: _ remaining_elements acc_size *element_si
114            {loop_label}:
115
116                dup 2
117                push 0
118                eq
119                skiz
120                    return
121                // _ remaining_elements acc_size *element_si
122
123                read_mem 1
124                // _ remaining_elements acc_size element_si (*element_si-1)
125
126                /* Verify that max allowed size is not exceeded */
127                push {T::MAX_OFFSET}
128                dup 2
129                lt
130                assert error_id 210
131                // _ remaining_elements acc_size element_si (*element_si-1)
132
133                addi 2
134                // _ remaining_elements acc_size element_si *element
135
136                dup 0
137                {&T::compute_size_and_assert_valid_size_indicator(library)}
138                // _ remaining_elements acc_size element_si *element calculated_elem_size
139
140                dup 2
141                eq
142                assert error_id 211
143                // _ remaining_elements acc_size element_si *element
144
145                pick 2
146                dup 2
147                add
148                // _ remaining_elements element_si *element acc_size'
149
150                /* Account for element's size indicator, since it's dynamically sized */
151                addi 1
152                // _ remaining_elements element_si *element acc_size'
153
154                place 2
155                // _ remaining_elements acc_size' element_si *element
156
157                add
158                // _ remaining_elements acc_size' *next_element
159
160                pick 2
161                addi -1
162                place 2
163                // _ (remaining_elements-1) acc_size' *next_element
164
165                recurse
166        );
167
168        library.explicit_import(&loop_label, &loop_code);
169        triton_asm!(
170            // _ *list_len
171
172            read_mem 1
173            hint remaining_elements = stack[1]
174            // _ list_len (*list_len - 1)
175
176            addi 2
177            hint elem_si_ptr = stack[0]
178            // _ list_len           (*list_len + 1)
179            // _ remaining_elements *element[0]_si
180
181            push 0
182            hint acc_size = stack[0]
183            // _ remaining_elements *element[0]_si acc_size
184
185            place 1
186            // _ remaining_elements acc_size *element[0]_si
187
188            call {loop_label}
189            // _ 0 acc_size *EOF
190
191            pick 2
192            pop 2
193            // _ acc_size
194
195            /* Add size of (outer) list's length indicator */
196            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                // _ *left_si
361                hint left_si_ptr = stack[0]
362
363                read_mem 1
364                addi 2
365                // _ left_si *left
366
367                {&T::compute_size_and_assert_valid_size_indicator(library)}
368                hint calculated_left = stack[0]
369                // _ left_si calculated_left
370
371                dup 1
372                eq
373                assert error_id 220
374                // _ left_size
375
376                addi 1
377                // _ (left_size + 1)
378            )
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                // _ *right_si
386                hint right_si_ptr = stack[0]
387
388                read_mem 1
389                hint right_si = stack[1]
390                // _ right_si (*right_si - 1)
391
392
393                addi 2
394                // _ right_size *right
395
396                {&S::compute_size_and_assert_valid_size_indicator(library)}
397                hint calculated_right = stack[0]
398                // _ right_size calculated_right_size
399
400                dup 1
401                eq
402                assert error_id 221
403                // _ right_size
404
405                /* Include size of size-indicator */
406                addi 1
407                // _ (right_size+1)
408            )
409        };
410
411        triton_asm!(
412            // _ *tuple
413
414            dup 0
415            {&size_right}
416            hint right_ptr_or_right_si = stack[1]
417            hint right_size_incl_pot_si = stack[0]
418            // _ *right right_size'
419
420            pick 1
421            dup 1
422            add
423            hint left: Pointer = stack[0]
424            // _ right_size' (*right + right_size')
425            // _ right_size' *left
426
427            {&size_left}
428            hint left_size_incl_si = stack[0]
429            // _ right_size' left_size'
430
431            add
432            // _ total_tuple_size <-- includes tuple-element's size-indicators (if dyn-sized)
433        )
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        // Assert length is bounded such that `len * 3` cannot
458        // wrap around modulus p.
459        let assert_len_is_u32 = triton_asm!(
460            // _ list_len g
461
462            push {DEFAULT_MAX_DYN_FIELD_SIZE}
463            dup 2
464            lt
465            // _ list_len g (max > list_len)
466
467            assert error_id {POLYNOMIAL_LEN_EXCEEDS_MAX}
468        );
469
470        triton_asm!(
471            // _ *field_size
472
473            addi 1
474            // _ *list_length
475
476            read_mem 2
477            pop 1
478            // _ list_length field_size
479
480            {&assert_len_is_u32}
481
482            push {Self::MAX_OFFSET}
483            dup 1
484            lt
485            assert
486            // _ list_length field_size
487
488            pick 1
489            push {EXTENSION_DEGREE}
490            mul
491            addi 1
492            // _ field_size calculated_field_size
493
494            dup 1
495            eq
496            assert
497            // _ field_size
498
499            /* Account for a size-indicator */
500            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        // Proofs are special, as the fields of a proof is only accessed through
524        // the [`DequeueNextAs`](crate::verifier::vm_proof_iter::dequeue_next_as)
525        // snippet which does some checks itself. So we just report the total size
526        // here.
527
528        triton_asm!(
529            // _ *proof
530
531            read_mem 1
532            pop 1
533            // _ field_0_len
534
535            addi 1
536            // _ own_size
537        )
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                // _ *value 1
565                pop 1
566
567                {&T::compute_size_and_assert_valid_size_indicator(library)}
568                // _ value_size
569
570                /* Push 0 to avoid `None` branch from being taken */
571                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                // _ *ptr
580
581                pop 1
582                push 0
583                // _ value_size
584
585                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            // _ *discriminant
593            read_mem 1
594            addi 2
595            // _ discriminant (*discriminant + 1)
596
597            /* Ensure discriminant has legal value */
598            dup 1
599            push 0
600            eq
601            dup 2
602            push 1
603            eq
604            add
605            // _ discriminant (*discriminant + 1) ((discriminant == 0) || (discriminant == 1))
606
607            assert error_id 200
608            // _ discriminant (*discriminant + 1)
609
610            push 1
611            // _ discriminant (*discriminant + 1) 1
612
613            pick 2
614            push 1
615            eq
616            // _ (*discriminant + 1) 1 (discriminant == 1)
617
618            skiz
619                call {some_branch_label}
620            skiz
621                call {none_branch_label}
622
623            // _ value_size
624            addi 1
625
626            // _ total_size
627        )
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    /// Generate a test case with the specified name for the specified type.
676    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}