tasm_lib/arithmetic/u32/
overflowing_add.rs

1use triton_vm::prelude::*;
2
3use crate::prelude::*;
4
5#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
6pub struct OverflowingAdd;
7
8impl BasicSnippet for OverflowingAdd {
9    fn inputs(&self) -> Vec<(DataType, String)> {
10        vec![
11            (DataType::U32, "lhs".to_owned()),
12            (DataType::U32, "rhs".to_owned()),
13        ]
14    }
15
16    fn outputs(&self) -> Vec<(DataType, String)> {
17        vec![
18            (DataType::U32, "wrapped_sum".to_owned()),
19            (DataType::Bool, "is_overflow".to_owned()),
20        ]
21    }
22
23    fn entrypoint(&self) -> String {
24        "tasmlib_arithmetic_u32_overflowing_add".to_string()
25    }
26
27    fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
28        triton_asm!(
29            {self.entrypoint()}:
30                add
31                split
32                swap 1
33                return
34        )
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41    use crate::test_prelude::*;
42
43    impl Closure for OverflowingAdd {
44        type Args = (u32, u32);
45
46        fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) {
47            let (left, right) = pop_encodable::<Self::Args>(stack);
48            let (sum, is_overflow) = left.overflowing_add(right);
49
50            push_encodable(stack, &sum);
51            push_encodable(stack, &is_overflow);
52        }
53
54        fn pseudorandom_args(
55            &self,
56            seed: [u8; 32],
57            bench_case: Option<BenchmarkCase>,
58        ) -> Self::Args {
59            match bench_case {
60                Some(BenchmarkCase::CommonCase) => (1 << 31, (1 << 31) - 1),
61                Some(BenchmarkCase::WorstCase) => (1 << 31, 1 << 31),
62                None => StdRng::from_seed(seed).random(),
63            }
64        }
65    }
66
67    #[test]
68    fn u32_overflowing_add_pbt() {
69        ShadowedClosure::new(OverflowingAdd).test()
70    }
71
72    #[test]
73    fn u32_overflowing_add_unit_test() {
74        for (lhs, rhs) in [
75            (0, 0),
76            (0, 1),
77            (1, 0),
78            (1, 1),
79            (1 << 16, 1 << 16),
80            (1 << 31, 1 << 31),
81            (u32::MAX, u32::MAX),
82        ] {
83            let initial_stack = OverflowingAdd.set_up_test_stack((lhs, rhs));
84
85            let mut expected_final_stack = initial_stack.clone();
86            OverflowingAdd.rust_shadow(&mut expected_final_stack);
87
88            let _vm_output_state = test_rust_equivalence_given_complete_state(
89                &ShadowedClosure::new(OverflowingAdd),
90                &initial_stack,
91                &[],
92                &NonDeterminism::default(),
93                &None,
94                Some(&expected_final_stack),
95            );
96        }
97    }
98}
99
100#[cfg(test)]
101mod benches {
102    use super::*;
103    use crate::test_prelude::*;
104
105    #[test]
106    fn benchmark() {
107        ShadowedClosure::new(OverflowingAdd).bench()
108    }
109}