|
1 | 1 | use std::collections::HashMap;
|
2 |
| - |
3 |
| -use rand::prelude::*; |
4 | 2 | use triton_vm::prelude::*;
|
5 | 3 |
|
6 |
| -use crate::empty_stack; |
7 | 4 | use crate::prelude::*;
|
8 |
| -use crate::push_encodable; |
9 |
| -use crate::traits::deprecated_snippet::DeprecatedSnippet; |
10 |
| -use crate::InitVmState; |
11 |
| - |
12 |
| -#[derive(Clone, Debug)] |
| 5 | +use 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)] |
13 | 24 | pub struct IsOdd;
|
14 | 25 |
|
15 |
| -impl DeprecatedSnippet for IsOdd { |
16 |
| - fn entrypoint_name(&self) -> String { |
17 |
| - "tasmlib_arithmetic_u32_is_odd".to_string() |
18 |
| - } |
19 |
| - |
20 |
| - fn input_field_names(&self) -> Vec<String> { |
21 |
| - vec!["value".to_string()] |
22 |
| - } |
23 |
| - |
24 |
| - fn input_types(&self) -> Vec<DataType> { |
25 |
| - vec![DataType::U32] |
| 26 | +impl BasicSnippet for IsOdd { |
| 27 | + fn inputs(&self) -> Vec<(DataType, String)> { |
| 28 | + vec![(DataType::U32, "value".to_string())] |
26 | 29 | }
|
27 | 30 |
|
28 |
| - fn output_field_names(&self) -> Vec<String> { |
29 |
| - vec!["value % 2".to_string()] |
| 31 | + fn outputs(&self) -> Vec<(DataType, String)> { |
| 32 | + vec![(DataType::Bool, "value % 2".to_string())] |
30 | 33 | }
|
31 | 34 |
|
32 |
| - fn output_types(&self) -> Vec<DataType> { |
33 |
| - vec![DataType::Bool] |
34 |
| - } |
35 |
| - |
36 |
| - fn stack_diff(&self) -> isize { |
37 |
| - // pops a u32 from the stack and pushes a bool |
38 |
| - 0 |
| 35 | + fn entrypoint(&self) -> String { |
| 36 | + "tasmlib_arithmetic_u32_is_odd".to_string() |
39 | 37 | }
|
40 | 38 |
|
41 |
| - fn function_code(&self, _library: &mut Library) -> String { |
42 |
| - let entrypoint = self.entrypoint_name(); |
43 |
| - format!( |
44 |
| - " |
45 |
| - // BEFORE: _ value |
46 |
| - // AFTER: _ (value % 2) |
47 |
| - {entrypoint}: |
48 |
| - push 2 |
49 |
| - swap 1 |
50 |
| - div_mod |
51 |
| - swap 1 |
52 |
| - pop 1 |
53 |
| - return |
54 |
| - " |
| 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 |
55 | 50 | )
|
56 | 51 | }
|
57 | 52 |
|
58 |
| - fn crash_conditions(&self) -> Vec<String> { |
59 |
| - vec!["if `value` is not a u32".to_string()] |
60 |
| - } |
61 |
| - |
62 |
| - fn gen_input_states(&self) -> Vec<InitVmState> { |
63 |
| - let n: u32 = rand::thread_rng().next_u32(); |
64 |
| - |
65 |
| - let mut even_stack = empty_stack(); |
66 |
| - let even_value = n - (n & 1); |
67 |
| - push_encodable(&mut even_stack, &even_value); |
68 |
| - |
69 |
| - let mut odd_stack = empty_stack(); |
70 |
| - let odd_value = n | 1; |
71 |
| - push_encodable(&mut odd_stack, &odd_value); |
72 |
| - |
73 |
| - vec![ |
74 |
| - InitVmState::with_stack(even_stack), |
75 |
| - InitVmState::with_stack(odd_stack), |
76 |
| - ] |
77 |
| - } |
78 |
| - |
79 |
| - fn common_case_input_state(&self) -> InitVmState { |
80 |
| - InitVmState::with_stack([empty_stack(), vec![BFieldElement::new(1 << 16)]].concat()) |
81 |
| - } |
82 |
| - |
83 |
| - fn worst_case_input_state(&self) -> InitVmState { |
84 |
| - InitVmState::with_stack([empty_stack(), vec![BFieldElement::new((1 << 32) - 1)]].concat()) |
85 |
| - } |
86 |
| - |
87 |
| - fn rust_shadowing( |
88 |
| - &self, |
89 |
| - stack: &mut Vec<BFieldElement>, |
90 |
| - _std_in: Vec<BFieldElement>, |
91 |
| - _secret_in: Vec<BFieldElement>, |
92 |
| - _memory: &mut HashMap<BFieldElement, BFieldElement>, |
93 |
| - ) { |
94 |
| - let value: u64 = stack.pop().unwrap().value(); |
95 |
| - stack.push(BFieldElement::new(value % 2)); |
| 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 |
96 | 57 | }
|
97 | 58 | }
|
98 | 59 |
|
99 | 60 | #[cfg(test)]
|
100 | 61 | mod tests {
|
101 | 62 | use super::*;
|
102 |
| - use crate::empty_stack; |
103 |
| - use crate::test_helpers::test_rust_equivalence_given_input_values_deprecated; |
104 |
| - use crate::test_helpers::test_rust_equivalence_multiple_deprecated; |
| 63 | + use crate::test_prelude::*; |
105 | 64 |
|
106 |
| - #[test] |
107 |
| - fn is_odd_u32_test() { |
108 |
| - test_rust_equivalence_multiple_deprecated(&IsOdd, true); |
109 |
| - } |
| 65 | + impl Closure for IsOdd { |
| 66 | + type Args = u32; |
110 | 67 |
|
111 |
| - #[test] |
112 |
| - fn u32_is_odd_test() { |
113 |
| - prop_is_odd(0); |
114 |
| - prop_is_odd(1); |
115 |
| - prop_is_odd(2); |
116 |
| - prop_is_odd(3); |
117 |
| - prop_is_odd(4); |
118 |
| - prop_is_odd(5); |
119 |
| - prop_is_odd(6); |
120 |
| - prop_is_odd(7); |
121 |
| - prop_is_odd(8); |
122 |
| - prop_is_odd(u32::MAX); |
| 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 | + } |
123 | 73 |
|
124 |
| - let mut rng = thread_rng(); |
125 |
| - for _ in 0..100 { |
126 |
| - let value = rng.next_u32(); |
127 |
| - prop_is_odd(value); |
| 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).gen(), |
| 83 | + } |
128 | 84 | }
|
129 |
| - } |
130 | 85 |
|
131 |
| - fn prop_is_odd(value: u32) { |
132 |
| - let mut init_stack = empty_stack(); |
133 |
| - init_stack.push(BFieldElement::new(value as u64)); |
134 |
| - let mut expected_stack = empty_stack(); |
135 |
| - expected_stack.push(BFieldElement::new((value % 2) as u64)); |
| 86 | + fn corner_case_args(&self) -> Vec<Self::Args> { |
| 87 | + (0..32).chain(u32::MAX - 32..=u32::MAX).collect_vec() |
| 88 | + } |
| 89 | + } |
136 | 90 |
|
137 |
| - test_rust_equivalence_given_input_values_deprecated( |
138 |
| - &IsOdd, |
139 |
| - &init_stack, |
140 |
| - &[], |
141 |
| - HashMap::default(), |
142 |
| - Some(&expected_stack), |
143 |
| - ); |
| 91 | + #[test] |
| 92 | + fn rust_shadow() { |
| 93 | + ShadowedClosure::new(IsOdd).test(); |
144 | 94 | }
|
145 | 95 | }
|
146 | 96 |
|
147 | 97 | #[cfg(test)]
|
148 | 98 | mod benches {
|
149 | 99 | use super::*;
|
150 |
| - use crate::snippet_bencher::bench_and_write; |
| 100 | + use crate::test_prelude::*; |
151 | 101 |
|
152 | 102 | #[test]
|
153 |
| - fn is_odd_u32_benchmark() { |
154 |
| - bench_and_write(IsOdd); |
| 103 | + fn benchmark() { |
| 104 | + ShadowedClosure::new(IsOdd).bench(); |
155 | 105 | }
|
156 | 106 | }
|
0 commit comments