tasm_lib/arithmetic/u32/
or.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/// [Bitwise “or”][bitor] (“`|`”) for `u32`s.
10///
11/// ### Behavior
12///
13/// ```text
14/// BEFORE: _ [right: u32] [left: u32]
15/// AFTER:  _ [left | right: u32]
16/// ```
17///
18/// ### Preconditions
19///
20/// - all input arguments are properly [`BFieldCodec`] encoded
21///
22/// ### Postconditions
23///
24/// - the output is the bitwise “or” of the input
25/// - the output is properly [`BFieldCodec`] encoded
26///
27/// [bitor]: core::ops::BitOr
28#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
29pub struct Or;
30
31impl BasicSnippet for Or {
32    fn inputs(&self) -> Vec<(DataType, String)> {
33        ["right", "left"]
34            .map(|s| (DataType::U32, s.to_string()))
35            .to_vec()
36    }
37
38    fn outputs(&self) -> Vec<(DataType, String)> {
39        vec![(DataType::U32, "left | right".to_string())]
40    }
41
42    fn entrypoint(&self) -> String {
43        "tasmlib_arithmetic_u32_or".to_string()
44    }
45
46    fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
47        triton_asm!(
48            // BEFORE: _ right left
49            // AFTER:  _ (left | right)
50            {self.entrypoint()}:
51                dup 1
52                dup 1       // _ right left right left
53                xor         // _ right left (right ^ left)
54                place 2
55                and         // _ (right ^ left) (right & left)
56                add
57                return
58        )
59    }
60
61    fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
62        let mut sign_offs = HashMap::new();
63        sign_offs.insert(Reviewer("ferdinand"), 0x78bc3071bcc44a84.into());
64        sign_offs
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71    use crate::test_prelude::*;
72
73    impl Closure for Or {
74        type Args = (u32, u32);
75
76        fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) {
77            let (right, left) = pop_encodable::<Self::Args>(stack);
78            let or = left | right;
79            push_encodable(stack, &or);
80        }
81
82        fn pseudorandom_args(
83            &self,
84            seed: [u8; 32],
85            bench_case: Option<BenchmarkCase>,
86        ) -> Self::Args {
87            match bench_case {
88                Some(BenchmarkCase::CommonCase) => (1 << 15, 1 << 16),
89                Some(BenchmarkCase::WorstCase) => (u32::MAX, u32::MAX),
90                None => StdRng::from_seed(seed).random(),
91            }
92        }
93
94        fn corner_case_args(&self) -> Vec<Self::Args> {
95            let edges = [0, 1, 2, 0b1110, 0b11110, 1 << 30, 1 << 31, u32::MAX];
96
97            edges.into_iter().cartesian_product(edges).collect()
98        }
99    }
100
101    #[test]
102    fn rust_shadow() {
103        ShadowedClosure::new(Or).test();
104    }
105}
106
107#[cfg(test)]
108mod benches {
109    use super::*;
110    use crate::test_prelude::*;
111
112    #[test]
113    fn benchmark() {
114        ShadowedClosure::new(Or).bench();
115    }
116}