|
1 |
| -use std::collections::HashMap; |
2 |
| - |
3 |
| -use num::One; |
4 |
| -use num::Zero; |
5 |
| -use rand::prelude::*; |
6 | 1 | use triton_vm::prelude::*;
|
7 | 2 |
|
8 |
| -use crate::empty_stack; |
9 | 3 | use crate::prelude::*;
|
10 |
| -use crate::push_encodable; |
11 |
| -use crate::traits::deprecated_snippet::DeprecatedSnippet; |
12 |
| -use crate::InitVmState; |
13 | 4 |
|
14 |
| -#[derive(Clone, Debug)] |
| 5 | +/// Is the top of the stack a u32? |
| 6 | +/// |
| 7 | +/// ### Behavior |
| 8 | +/// |
| 9 | +/// ```text |
| 10 | +/// BEFORE: _ value |
| 11 | +/// AFTER: _ [is_u32: bool] |
| 12 | +/// ``` |
| 13 | +/// |
| 14 | +/// ### Preconditions |
| 15 | +/// |
| 16 | +/// None. |
| 17 | +/// |
| 18 | +/// ### Postconditions |
| 19 | +/// |
| 20 | +/// - the output is properly [`BFieldCodec`] encoded |
| 21 | +#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)] |
15 | 22 | pub struct IsU32;
|
16 | 23 |
|
17 |
| -impl DeprecatedSnippet for IsU32 { |
18 |
| - fn entrypoint_name(&self) -> String { |
19 |
| - "tasmlib_arithmetic_u32_is_u32".to_string() |
20 |
| - } |
21 |
| - |
22 |
| - fn input_field_names(&self) -> Vec<String> { |
23 |
| - vec!["value".to_string()] |
24 |
| - } |
25 |
| - |
26 |
| - fn input_types(&self) -> Vec<DataType> { |
27 |
| - vec![DataType::U32] |
28 |
| - } |
29 |
| - |
30 |
| - fn output_field_names(&self) -> Vec<String> { |
31 |
| - vec!["value < 2^32".to_string()] |
| 24 | +impl BasicSnippet for IsU32 { |
| 25 | + fn inputs(&self) -> Vec<(DataType, String)> { |
| 26 | + vec![(DataType::U32, "value".to_string())] |
32 | 27 | }
|
33 | 28 |
|
34 |
| - fn output_types(&self) -> Vec<DataType> { |
35 |
| - vec![DataType::Bool] |
| 29 | + fn outputs(&self) -> Vec<(DataType, String)> { |
| 30 | + vec![(DataType::Bool, "value < 2^32".to_string())] |
36 | 31 | }
|
37 | 32 |
|
38 |
| - fn stack_diff(&self) -> isize { |
39 |
| - 0 |
| 33 | + fn entrypoint(&self) -> String { |
| 34 | + "tasmlib_arithmetic_u32_is_u32".to_string() |
40 | 35 | }
|
41 | 36 |
|
42 |
| - /// Place 1 on stack iff top element is less than $2^32$. Otherwise |
43 |
| - /// place 0 on stack. Consumes top element of stack, leaves a boolean |
44 |
| - /// on top of stack. So this subroutine does not change the height |
45 |
| - /// of the stack |
46 |
| - fn function_code(&self, _library: &mut Library) -> String { |
47 |
| - let entrypoint = self.entrypoint_name(); |
48 |
| - format!( |
49 |
| - " |
50 |
| - {entrypoint}: |
| 37 | + fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> { |
| 38 | + triton_asm!( |
| 39 | + {self.entrypoint()}: |
51 | 40 | // _ a
|
52 | 41 | split // _ hi lo
|
53 | 42 | pop 1 // _ hi
|
54 | 43 | push 0 // _ hi 0
|
55 | 44 | eq // _ (hi == 0)
|
56 | 45 | return
|
57 |
| - " |
58 | 46 | )
|
59 | 47 | }
|
60 |
| - |
61 |
| - fn crash_conditions(&self) -> Vec<String> { |
62 |
| - vec![] |
63 |
| - } |
64 |
| - |
65 |
| - fn gen_input_states(&self) -> Vec<InitVmState> { |
66 |
| - let n: u32 = rand::thread_rng().next_u32(); |
67 |
| - |
68 |
| - let mut true_stack = empty_stack(); |
69 |
| - push_encodable(&mut true_stack, &n); |
70 |
| - |
71 |
| - let mut false_stack = empty_stack(); |
72 |
| - push_encodable(&mut false_stack, &(u32::MAX)); |
73 |
| - |
74 |
| - vec![ |
75 |
| - InitVmState::with_stack(true_stack), |
76 |
| - InitVmState::with_stack(false_stack), |
77 |
| - ] |
78 |
| - } |
79 |
| - |
80 |
| - fn common_case_input_state(&self) -> InitVmState { |
81 |
| - InitVmState::with_stack([empty_stack(), vec![BFieldElement::new(1 << 16)]].concat()) |
82 |
| - } |
83 |
| - |
84 |
| - fn worst_case_input_state(&self) -> InitVmState { |
85 |
| - InitVmState::with_stack([empty_stack(), vec![BFieldElement::new((1 << 32) - 1)]].concat()) |
86 |
| - } |
87 |
| - |
88 |
| - fn rust_shadowing( |
89 |
| - &self, |
90 |
| - stack: &mut Vec<BFieldElement>, |
91 |
| - _std_in: Vec<BFieldElement>, |
92 |
| - _secret_in: Vec<BFieldElement>, |
93 |
| - _memory: &mut HashMap<BFieldElement, BFieldElement>, |
94 |
| - ) { |
95 |
| - let top = stack.pop().unwrap(); |
96 |
| - stack.push(if top.value() < (1 << 32) { |
97 |
| - BFieldElement::one() |
98 |
| - } else { |
99 |
| - BFieldElement::zero() |
100 |
| - }); |
101 |
| - } |
102 | 48 | }
|
103 | 49 |
|
104 | 50 | #[cfg(test)]
|
105 | 51 | mod tests {
|
106 | 52 | use super::*;
|
107 |
| - use crate::empty_stack; |
108 |
| - use crate::test_helpers::test_rust_equivalence_given_input_values_deprecated; |
109 |
| - use crate::test_helpers::test_rust_equivalence_multiple_deprecated; |
110 |
| - |
111 |
| - #[test] |
112 |
| - fn is_u32_test() { |
113 |
| - test_rust_equivalence_multiple_deprecated(&IsU32, true); |
114 |
| - } |
| 53 | + use crate::test_prelude::*; |
115 | 54 |
|
116 |
| - #[test] |
117 |
| - fn is_u32_simple() { |
118 |
| - let stack_true: Vec<BFieldElement> = [empty_stack(), vec![BFieldElement::one()]].concat(); |
119 |
| - let stack_false: Vec<BFieldElement> = [empty_stack(), vec![BFieldElement::zero()]].concat(); |
| 55 | + impl Closure for IsU32 { |
| 56 | + type Args = BFieldElement; |
120 | 57 |
|
121 |
| - prop_is_u32(BFieldElement::zero(), Some(&stack_true)); |
122 |
| - prop_is_u32(BFieldElement::one(), Some(&stack_true)); |
123 |
| - prop_is_u32(BFieldElement::new(1 << 10), Some(&stack_true)); |
124 |
| - prop_is_u32(BFieldElement::new(1 << 20), Some(&stack_true)); |
125 |
| - prop_is_u32(BFieldElement::new(1 << 30), Some(&stack_true)); |
126 |
| - prop_is_u32(BFieldElement::new(1 << 40), Some(&stack_false)); |
127 |
| - prop_is_u32(BFieldElement::new(1 << 50), Some(&stack_false)); |
128 |
| - prop_is_u32(BFieldElement::new(1 << 60), Some(&stack_false)); |
129 |
| - prop_is_u32( |
130 |
| - BFieldElement::new((1 << 63) + (1 << 42)), |
131 |
| - Some(&stack_false), |
132 |
| - ); |
133 |
| - } |
| 58 | + fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) { |
| 59 | + let value = stack.pop().unwrap(); |
| 60 | + let is_u32 = u32::try_from(value).is_ok(); |
| 61 | + push_encodable(stack, &is_u32); |
| 62 | + } |
134 | 63 |
|
135 |
| - #[test] |
136 |
| - fn is_u32_pbt() { |
137 |
| - let stack_true: Vec<BFieldElement> = [empty_stack(), vec![BFieldElement::one()]].concat(); |
138 |
| - let stack_false: Vec<BFieldElement> = [empty_stack(), vec![BFieldElement::zero()]].concat(); |
| 64 | + fn pseudorandom_args( |
| 65 | + &self, |
| 66 | + seed: [u8; 32], |
| 67 | + bench_case: Option<BenchmarkCase>, |
| 68 | + ) -> Self::Args { |
| 69 | + match bench_case { |
| 70 | + Some(BenchmarkCase::CommonCase) => bfe!(1 << 16), |
| 71 | + Some(BenchmarkCase::WorstCase) => bfe!(u32::MAX), |
| 72 | + None => StdRng::from_seed(seed).gen(), |
| 73 | + } |
| 74 | + } |
139 | 75 |
|
140 |
| - let mut rng = rand::thread_rng(); |
141 |
| - for _ in 0..10 { |
142 |
| - prop_is_u32(BFieldElement::new(rng.next_u32() as u64), Some(&stack_true)); |
143 |
| - prop_is_u32( |
144 |
| - BFieldElement::new((rng.next_u32() as u64) + (1u64 << 32)), |
145 |
| - Some(&stack_false), |
146 |
| - ); |
| 76 | + fn corner_case_args(&self) -> Vec<Self::Args> { |
| 77 | + bfe_vec![0, u32::MAX, u64::from(u32::MAX) + 1, BFieldElement::MAX] |
147 | 78 | }
|
148 | 79 | }
|
149 | 80 |
|
150 |
| - fn prop_is_u32(some_value: BFieldElement, expected: Option<&[BFieldElement]>) { |
151 |
| - let mut init_stack = empty_stack(); |
152 |
| - init_stack.push(some_value); |
153 |
| - |
154 |
| - test_rust_equivalence_given_input_values_deprecated::<IsU32>( |
155 |
| - &IsU32, |
156 |
| - &init_stack, |
157 |
| - &[], |
158 |
| - HashMap::default(), |
159 |
| - expected, |
160 |
| - ); |
| 81 | + #[test] |
| 82 | + fn rust_shadow() { |
| 83 | + ShadowedClosure::new(IsU32).test(); |
161 | 84 | }
|
162 | 85 | }
|
163 | 86 |
|
164 | 87 | #[cfg(test)]
|
165 | 88 | mod benches {
|
166 | 89 | use super::*;
|
167 |
| - use crate::snippet_bencher::bench_and_write; |
| 90 | + use crate::test_prelude::*; |
168 | 91 |
|
169 | 92 | #[test]
|
170 | 93 | fn is_u32_benchmark() {
|
171 |
| - bench_and_write(IsU32); |
| 94 | + ShadowedClosure::new(IsU32).bench(); |
172 | 95 | }
|
173 | 96 | }
|
0 commit comments