tasm_lib/arithmetic/u32/
is_odd.rs

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