tasm_lib/arithmetic/u32/
is_odd.rs

1use std::collections::HashMap;
2
3use triton_vm::prelude::*;
4
5use crate::prelude::*;
6use crate::traits::basic_snippet::Reviewer;
7use crate::traits::basic_snippet::SignOffFingerprint;
8
9/// Is the top of the stack an odd u32?
10///
11/// ### Behavior
12///
13/// ```text
14/// BEFORE: _ [value: u32]
15/// AFTER:  _ [is_odd: bool]
16/// ```
17///
18/// ### Preconditions
19///
20/// - all input arguments are properly [`BFieldCodec`] encoded
21///
22/// ### Postconditions
23///
24/// - the output is properly [`BFieldCodec`] encoded
25#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
26pub struct IsOdd;
27
28impl BasicSnippet for IsOdd {
29    fn parameters(&self) -> Vec<(DataType, String)> {
30        vec![(DataType::U32, "value".to_string())]
31    }
32
33    fn return_values(&self) -> Vec<(DataType, String)> {
34        vec![(DataType::Bool, "value % 2".to_string())]
35    }
36
37    fn entrypoint(&self) -> String {
38        "tasmlib_arithmetic_u32_is_odd".to_string()
39    }
40
41    fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
42        triton_asm!(
43            // BEFORE: _ value
44            // AFTER:  _ (value % 2)
45            {self.entrypoint()}:
46                push 2
47                pick 1
48                div_mod
49                pick 1
50                pop 1
51                return
52        )
53    }
54
55    fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
56        let mut sign_offs = HashMap::new();
57        sign_offs.insert(Reviewer("ferdinand"), 0xa573894027409e47.into());
58        sign_offs
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65    use crate::test_prelude::*;
66
67    impl Closure for IsOdd {
68        type Args = u32;
69
70        fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) {
71            let v = pop_encodable::<Self::Args>(stack);
72            let is_odd = v % 2 == 1;
73            push_encodable(stack, &is_odd);
74        }
75
76        fn pseudorandom_args(
77            &self,
78            seed: [u8; 32],
79            bench_case: Option<BenchmarkCase>,
80        ) -> Self::Args {
81            match bench_case {
82                Some(BenchmarkCase::CommonCase) => 1 << 16,
83                Some(BenchmarkCase::WorstCase) => u32::MAX,
84                None => StdRng::from_seed(seed).random(),
85            }
86        }
87
88        fn corner_case_args(&self) -> Vec<Self::Args> {
89            (0..32).chain(u32::MAX - 32..=u32::MAX).collect_vec()
90        }
91    }
92
93    #[test]
94    fn rust_shadow() {
95        ShadowedClosure::new(IsOdd).test();
96    }
97}
98
99#[cfg(test)]
100mod benches {
101    use super::*;
102    use crate::test_prelude::*;
103
104    #[test]
105    fn benchmark() {
106        ShadowedClosure::new(IsOdd).bench();
107    }
108}