|
1 |
| -use rand::prelude::*; |
| 1 | +use std::collections::HashMap; |
| 2 | + |
2 | 3 | use triton_vm::prelude::*;
|
3 |
| -use twenty_first::prelude::U32s; |
4 | 4 |
|
5 |
| -use crate::empty_stack; |
6 | 5 | use crate::prelude::*;
|
7 |
| -use crate::push_encodable; |
8 |
| -use crate::traits::deprecated_snippet::DeprecatedSnippet; |
9 |
| -use crate::InitVmState; |
10 |
| - |
11 |
| -#[derive(Clone, Debug)] |
| 6 | +use crate::traits::basic_snippet::Reviewer; |
| 7 | +use crate::traits::basic_snippet::SignOffFingerprint; |
| 8 | + |
| 9 | +/// [Bitwise “or”][bitor] (“`|`”) for `u64`s. |
| 10 | +/// |
| 11 | +/// ### Behavior |
| 12 | +/// |
| 13 | +/// ```text |
| 14 | +/// BEFORE: _ [right: u64] [left: u64] |
| 15 | +/// AFTER: _ [left | right: u64] |
| 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)] |
12 | 29 | pub struct Or;
|
13 | 30 |
|
14 |
| -impl DeprecatedSnippet for Or { |
15 |
| - fn entrypoint_name(&self) -> String { |
16 |
| - "tasmlib_arithmetic_u64_or_u64".to_string() |
17 |
| - } |
18 |
| - |
19 |
| - fn input_field_names(&self) -> Vec<String> { |
20 |
| - vec![ |
21 |
| - "rhs_hi".to_string(), |
22 |
| - "rhs_lo".to_string(), |
23 |
| - "lhs_hi".to_string(), |
24 |
| - "lhs_lo".to_string(), |
25 |
| - ] |
26 |
| - } |
27 |
| - |
28 |
| - fn input_types(&self) -> Vec<DataType> { |
29 |
| - vec![DataType::U64, DataType::U64] |
30 |
| - } |
31 |
| - |
32 |
| - fn output_field_names(&self) -> Vec<String> { |
33 |
| - vec!["(lhs | rhs)_hi".to_string(), "(lhs | rhs)_lo".to_string()] |
34 |
| - } |
35 |
| - |
36 |
| - fn output_types(&self) -> Vec<DataType> { |
37 |
| - vec![DataType::U64] |
38 |
| - } |
39 |
| - |
40 |
| - fn stack_diff(&self) -> isize { |
41 |
| - -2 |
42 |
| - } |
43 |
| - |
44 |
| - fn function_code(&self, _library: &mut crate::library::Library) -> String { |
45 |
| - let entrypoint = self.entrypoint_name(); |
46 |
| - format!( |
47 |
| - " |
48 |
| - // BEFORE: _ rhs_hi rhs_lo lhs_hi lhs_lo |
49 |
| - // AFTER: _ (lhs | rhs)_hi (lhs | rhs)_lo |
50 |
| - {entrypoint}: |
51 |
| - dup 2 |
52 |
| - dup 1 |
53 |
| - xor |
54 |
| - // _ rhs_hi rhs_lo lhs_hi lhs_lo (rhs_lo ^ lhs_lo) |
55 |
| -
|
56 |
| - swap 3 |
57 |
| - and |
58 |
| - // _ rhs_hi (rhs_lo ^ lhs_lo) lhs_hi (lhs_lo & rhs_lo) |
59 |
| -
|
60 |
| - swap 3 |
61 |
| - // _ (lhs_lo & rhs_lo) (rhs_lo ^ lhs_lo) lhs_hi rhs_hi |
62 |
| -
|
63 |
| - dup 1 |
64 |
| - dup 1 |
65 |
| - xor |
66 |
| - // _ (lhs_lo & rhs_lo) (rhs_lo ^ lhs_lo) lhs_hi rhs_hi (lhs_hi ^ rhs_hi) |
67 |
| -
|
68 |
| - swap 2 |
69 |
| - and |
70 |
| - // _ (lhs_lo & rhs_lo) (rhs_lo ^ lhs_lo) (lhs_hi ^ rhs_hi) (rhs_hi & lhs_hi) |
71 |
| -
|
72 |
| - add |
73 |
| - // _ (lhs_lo & rhs_lo) (rhs_lo ^ lhs_lo) (lhs_hi | rhs_hi) |
74 |
| -
|
75 |
| - swap 2 |
76 |
| - add |
77 |
| - // _ (lhs_hi | rhs_hi) (rhs_lo | lhs_lo) |
78 |
| -
|
79 |
| - return |
80 |
| - " |
| 31 | +impl BasicSnippet for Or { |
| 32 | + fn inputs(&self) -> Vec<(DataType, String)> { |
| 33 | + ["right", "left"] |
| 34 | + .map(|s| (DataType::U64, s.to_string())) |
| 35 | + .to_vec() |
| 36 | + } |
| 37 | + |
| 38 | + fn outputs(&self) -> Vec<(DataType, String)> { |
| 39 | + vec![(DataType::U64, "left | right".to_string())] |
| 40 | + } |
| 41 | + |
| 42 | + fn entrypoint(&self) -> String { |
| 43 | + "tasmlib_arithmetic_u64_or".to_string() |
| 44 | + } |
| 45 | + |
| 46 | + fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> { |
| 47 | + let entrypoint = self.entrypoint(); |
| 48 | + triton_asm!( |
| 49 | + // BEFORE: _ r_hi r_lo l_hi l_lo |
| 50 | + // AFTER: _ (l | r)_hi (l | r)_lo |
| 51 | + {entrypoint}: |
| 52 | + dup 2 |
| 53 | + dup 1 |
| 54 | + xor // _ r_hi r_lo l_hi l_lo (r_lo ^ l_lo) |
| 55 | + swap 3 |
| 56 | + and // _ r_hi (r_lo ^ l_lo) l_hi (l_lo & r_lo) |
| 57 | + swap 3 // _ (l_lo & r_lo) (r_lo ^ l_lo) l_hi r_hi |
| 58 | + dup 1 |
| 59 | + dup 1 |
| 60 | + xor // _ (l_lo & r_lo) (r_lo ^ l_lo) l_hi r_hi (l_hi ^ r_hi) |
| 61 | + place 2 |
| 62 | + and // _ (l_lo & r_lo) (r_lo ^ l_lo) (l_hi ^ r_hi) (r_hi & l_hi) |
| 63 | + add // _ (l_lo & r_lo) (r_lo ^ l_lo) (l_hi | r_hi) |
| 64 | + place 2 |
| 65 | + add // _ (l_hi | r_hi) (r_lo | l_lo) |
| 66 | + return |
81 | 67 | )
|
82 | 68 | }
|
83 | 69 |
|
84 |
| - fn crash_conditions(&self) -> Vec<String> { |
85 |
| - vec!["Inputs are not u32".to_owned()] |
86 |
| - } |
87 |
| - |
88 |
| - fn gen_input_states(&self) -> Vec<InitVmState> { |
89 |
| - let mut ret: Vec<InitVmState> = vec![]; |
90 |
| - for _ in 0..100 { |
91 |
| - ret.push(prepare_state( |
92 |
| - thread_rng().next_u64(), |
93 |
| - thread_rng().next_u64(), |
94 |
| - )); |
95 |
| - } |
96 |
| - |
97 |
| - ret |
98 |
| - } |
99 |
| - |
100 |
| - fn common_case_input_state(&self) -> InitVmState { |
101 |
| - prepare_state(u32::MAX as u64, u32::MAX as u64) |
| 70 | + fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> { |
| 71 | + let mut sign_offs = HashMap::new(); |
| 72 | + sign_offs.insert(Reviewer("ferdinand"), 0x9304a37ae367ed6.into()); |
| 73 | + sign_offs |
102 | 74 | }
|
103 |
| - |
104 |
| - fn worst_case_input_state(&self) -> InitVmState { |
105 |
| - prepare_state(u64::MAX, u64::MAX) |
106 |
| - } |
107 |
| - |
108 |
| - fn rust_shadowing( |
109 |
| - &self, |
110 |
| - stack: &mut Vec<BFieldElement>, |
111 |
| - _std_in: Vec<BFieldElement>, |
112 |
| - _secret_in: Vec<BFieldElement>, |
113 |
| - _memory: &mut std::collections::HashMap<BFieldElement, BFieldElement>, |
114 |
| - ) { |
115 |
| - let lhs_lo: u32 = stack.pop().unwrap().try_into().unwrap(); |
116 |
| - let lhs_hi: u32 = stack.pop().unwrap().try_into().unwrap(); |
117 |
| - let rhs_lo: u32 = stack.pop().unwrap().try_into().unwrap(); |
118 |
| - let rhs_hi: u32 = stack.pop().unwrap().try_into().unwrap(); |
119 |
| - |
120 |
| - let lhs = ((lhs_hi as u64) << 32) + lhs_lo as u64; |
121 |
| - let rhs = ((rhs_hi as u64) << 32) + rhs_lo as u64; |
122 |
| - |
123 |
| - let or = lhs | rhs; |
124 |
| - stack.push(BFieldElement::new(or >> 32)); |
125 |
| - stack.push(BFieldElement::new(or & u32::MAX as u64)); |
126 |
| - } |
127 |
| -} |
128 |
| - |
129 |
| -fn prepare_state(a: u64, b: u64) -> InitVmState { |
130 |
| - let a = U32s::<2>::try_from(a).unwrap(); |
131 |
| - let b = U32s::<2>::try_from(b).unwrap(); |
132 |
| - let mut init_stack = empty_stack(); |
133 |
| - push_encodable(&mut init_stack, &a); |
134 |
| - push_encodable(&mut init_stack, &b); |
135 |
| - InitVmState::with_stack(init_stack) |
136 | 75 | }
|
137 | 76 |
|
138 | 77 | #[cfg(test)]
|
139 | 78 | mod tests {
|
140 |
| - use std::collections::HashMap; |
141 |
| - |
142 | 79 | use super::*;
|
143 |
| - use crate::test_helpers::test_rust_equivalence_given_input_values_deprecated; |
144 |
| - use crate::test_helpers::test_rust_equivalence_multiple_deprecated; |
| 80 | + use crate::arithmetic::u64::and::And; |
| 81 | + use crate::test_prelude::*; |
145 | 82 |
|
146 |
| - #[test] |
147 |
| - fn snippet_test() { |
148 |
| - test_rust_equivalence_multiple_deprecated(&Or, true); |
149 |
| - } |
| 83 | + impl Closure for Or { |
| 84 | + type Args = (u64, u64); |
150 | 85 |
|
151 |
| - #[test] |
152 |
| - fn or_simple_test() { |
153 |
| - prop_safe_or(10, 1, Some(11)); |
154 |
| - prop_safe_or(10, (1 << 36) + 1, Some(11 + (1 << 36))); |
155 |
| - prop_safe_or(256, 30, Some(286)); |
156 |
| - prop_safe_or(123, 0, Some(123)); |
157 |
| - prop_safe_or(0, 123, Some(123)); |
158 |
| - prop_safe_or(1 << 31, 1 << 30, Some((1 << 30) + (1 << 31))); |
159 |
| - prop_safe_or(0, 0, Some(0)); |
160 |
| - prop_safe_or(14, 0, Some(14)); |
161 |
| - prop_safe_or(u32::MAX as u64, 0, Some(u32::MAX as u64)); |
162 |
| - prop_safe_or(0, u32::MAX as u64, Some(u32::MAX as u64)); |
163 |
| - prop_safe_or(u32::MAX as u64, u32::MAX as u64, Some(u32::MAX as u64)); |
164 |
| - prop_safe_or(u64::MAX, u64::MAX, Some(u64::MAX)); |
165 |
| - prop_safe_or(u64::MAX, 0, Some(u64::MAX)); |
166 |
| - prop_safe_or(0, u64::MAX, Some(u64::MAX)); |
167 |
| - } |
| 86 | + fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) { |
| 87 | + let (right, left) = pop_encodable::<Self::Args>(stack); |
| 88 | + let or = left | right; |
| 89 | + push_encodable(stack, &or); |
| 90 | + } |
168 | 91 |
|
169 |
| - fn prop_safe_or(lhs: u64, rhs: u64, expected: Option<u64>) { |
170 |
| - let res = lhs | rhs; |
171 |
| - if let Some(exp) = expected { |
172 |
| - assert_eq!(exp, { res }); |
| 92 | + fn pseudorandom_args( |
| 93 | + &self, |
| 94 | + seed: [u8; 32], |
| 95 | + bench_case: Option<BenchmarkCase>, |
| 96 | + ) -> Self::Args { |
| 97 | + match bench_case { |
| 98 | + Some(BenchmarkCase::CommonCase) => (u32::MAX.into(), u32::MAX.into()), |
| 99 | + Some(BenchmarkCase::WorstCase) => (u64::MAX, u64::MAX), |
| 100 | + None => StdRng::from_seed(seed).gen(), |
| 101 | + } |
173 | 102 | }
|
174 | 103 |
|
175 |
| - let rhs = U32s::<2>::try_from(rhs).unwrap(); |
176 |
| - let lhs = U32s::<2>::try_from(lhs).unwrap(); |
177 |
| - let mut init_stack = empty_stack(); |
178 |
| - push_encodable(&mut init_stack, &rhs); |
179 |
| - push_encodable(&mut init_stack, &lhs); |
180 |
| - |
181 |
| - let mut expected = empty_stack(); |
182 |
| - expected.push(BFieldElement::new(res >> 32)); |
183 |
| - expected.push(BFieldElement::new(res & u32::MAX as u64)); |
184 |
| - |
185 |
| - test_rust_equivalence_given_input_values_deprecated( |
186 |
| - &Or, |
187 |
| - &init_stack, |
188 |
| - &[], |
189 |
| - HashMap::default(), |
190 |
| - Some(&expected), |
191 |
| - ); |
| 104 | + fn corner_case_args(&self) -> Vec<Self::Args> { |
| 105 | + And.corner_case_args() |
| 106 | + } |
| 107 | + } |
| 108 | + |
| 109 | + #[test] |
| 110 | + fn rust_shadow() { |
| 111 | + ShadowedClosure::new(Or).test(); |
192 | 112 | }
|
193 | 113 | }
|
194 | 114 |
|
195 | 115 | #[cfg(test)]
|
196 | 116 | mod benches {
|
197 | 117 | use super::*;
|
198 |
| - use crate::snippet_bencher::bench_and_write; |
| 118 | + use crate::test_prelude::*; |
199 | 119 |
|
200 | 120 | #[test]
|
201 |
| - fn u64_or_benchmark() { |
202 |
| - bench_and_write(Or); |
| 121 | + fn benchmark() { |
| 122 | + ShadowedClosure::new(Or).bench(); |
203 | 123 | }
|
204 | 124 | }
|
0 commit comments