Skip to main content

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 parameters(&self) -> Vec<(DataType, String)> {
10        vec![
11            (DataType::U32, "lhs".to_owned()),
12            (DataType::U32, "rhs".to_owned()),
13        ]
14    }
15
16    fn return_values(&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>) -> Result<(), RustShadowError> {
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            Ok(())
53        }
54
55        fn pseudorandom_args(
56            &self,
57            seed: [u8; 32],
58            bench_case: Option<BenchmarkCase>,
59        ) -> Self::Args {
60            match bench_case {
61                Some(BenchmarkCase::CommonCase) => (1 << 31, (1 << 31) - 1),
62                Some(BenchmarkCase::WorstCase) => (1 << 31, 1 << 31),
63                None => StdRng::from_seed(seed).random(),
64            }
65        }
66    }
67
68    #[macro_rules_attr::apply(test)]
69    fn u32_overflowing_add_pbt() {
70        ShadowedClosure::new(OverflowingAdd).test()
71    }
72
73    #[macro_rules_attr::apply(test)]
74    fn u32_overflowing_add_unit_test() {
75        for (lhs, rhs) in [
76            (0, 0),
77            (0, 1),
78            (1, 0),
79            (1, 1),
80            (1 << 16, 1 << 16),
81            (1 << 31, 1 << 31),
82            (u32::MAX, u32::MAX),
83        ] {
84            let initial_stack = OverflowingAdd.set_up_test_stack((lhs, rhs));
85
86            let mut expected_final_stack = initial_stack.clone();
87            OverflowingAdd
88                .rust_shadow(&mut expected_final_stack)
89                .unwrap();
90
91            let _vm_output_state = test_rust_equivalence_given_complete_state(
92                &ShadowedClosure::new(OverflowingAdd),
93                &initial_stack,
94                &[],
95                &NonDeterminism::default(),
96                &None,
97                Some(&expected_final_stack),
98            );
99        }
100    }
101}
102
103#[cfg(test)]
104mod benches {
105    use super::*;
106    use crate::test_prelude::*;
107
108    #[macro_rules_attr::apply(test)]
109    fn benchmark() {
110        ShadowedClosure::new(OverflowingAdd).bench()
111    }
112}