|
1 | 1 | use std::collections::HashMap;
|
2 |
| - |
3 |
| -use num::One; |
4 |
| -use num::Zero; |
5 |
| -use rand::prelude::*; |
6 | 2 | use triton_vm::prelude::*;
|
7 | 3 |
|
8 |
| -use crate::empty_stack; |
9 | 4 | use crate::prelude::*;
|
10 |
| -use crate::push_encodable; |
11 |
| -use crate::traits::deprecated_snippet::DeprecatedSnippet; |
12 |
| -use crate::InitVmState; |
13 |
| - |
14 |
| -#[derive(Clone, Debug)] |
| 5 | +use crate::traits::basic_snippet::{Reviewer, SignOffFingerprint}; |
| 6 | + |
| 7 | +/// Is the top of the stack a u32? |
| 8 | +/// |
| 9 | +/// ### Behavior |
| 10 | +/// |
| 11 | +/// ```text |
| 12 | +/// BEFORE: _ value |
| 13 | +/// AFTER: _ [is_u32: bool] |
| 14 | +/// ``` |
| 15 | +/// |
| 16 | +/// ### Preconditions |
| 17 | +/// |
| 18 | +/// None. |
| 19 | +/// |
| 20 | +/// ### Postconditions |
| 21 | +/// |
| 22 | +/// - the output is properly [`BFieldCodec`] encoded |
| 23 | +#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)] |
15 | 24 | pub struct IsU32;
|
16 | 25 |
|
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()] |
| 26 | +impl BasicSnippet for IsU32 { |
| 27 | + fn inputs(&self) -> Vec<(DataType, String)> { |
| 28 | + vec![(DataType::U32, "value".to_string())] |
32 | 29 | }
|
33 | 30 |
|
34 |
| - fn output_types(&self) -> Vec<DataType> { |
35 |
| - vec![DataType::Bool] |
| 31 | + fn outputs(&self) -> Vec<(DataType, String)> { |
| 32 | + vec![(DataType::Bool, "value < 2^32".to_string())] |
36 | 33 | }
|
37 | 34 |
|
38 |
| - fn stack_diff(&self) -> isize { |
39 |
| - 0 |
| 35 | + fn entrypoint(&self) -> String { |
| 36 | + "tasmlib_arithmetic_u32_is_u32".to_string() |
40 | 37 | }
|
41 | 38 |
|
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}: |
| 39 | + fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> { |
| 40 | + triton_asm!( |
| 41 | + {self.entrypoint()}: |
51 | 42 | // _ a
|
52 | 43 | split // _ hi lo
|
53 | 44 | pop 1 // _ hi
|
54 | 45 | push 0 // _ hi 0
|
55 | 46 | eq // _ (hi == 0)
|
56 | 47 | return
|
57 |
| - " |
58 | 48 | )
|
59 | 49 | }
|
60 | 50 |
|
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 |
| - }); |
| 51 | + fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> { |
| 52 | + let mut sign_offs = HashMap::new(); |
| 53 | + sign_offs.insert(Reviewer("ferdinand"), 0x95dae6d2fe11abda.into()); |
| 54 | + sign_offs |
101 | 55 | }
|
102 | 56 | }
|
103 | 57 |
|
104 | 58 | #[cfg(test)]
|
105 | 59 | mod tests {
|
106 | 60 | 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; |
| 61 | + use crate::test_prelude::*; |
110 | 62 |
|
111 |
| - #[test] |
112 |
| - fn is_u32_test() { |
113 |
| - test_rust_equivalence_multiple_deprecated(&IsU32, true); |
114 |
| - } |
| 63 | + impl Closure for IsU32 { |
| 64 | + type Args = BFieldElement; |
115 | 65 |
|
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(); |
120 |
| - |
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 |
| - } |
| 66 | + fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) { |
| 67 | + let value = stack.pop().unwrap(); |
| 68 | + let is_u32 = u32::try_from(value).is_ok(); |
| 69 | + push_encodable(stack, &is_u32); |
| 70 | + } |
134 | 71 |
|
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(); |
| 72 | + fn pseudorandom_args( |
| 73 | + &self, |
| 74 | + seed: [u8; 32], |
| 75 | + bench_case: Option<BenchmarkCase>, |
| 76 | + ) -> Self::Args { |
| 77 | + match bench_case { |
| 78 | + Some(BenchmarkCase::CommonCase) => bfe!(1 << 16), |
| 79 | + Some(BenchmarkCase::WorstCase) => bfe!(u32::MAX), |
| 80 | + None => StdRng::from_seed(seed).gen(), |
| 81 | + } |
| 82 | + } |
139 | 83 |
|
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 |
| - ); |
| 84 | + fn corner_case_args(&self) -> Vec<Self::Args> { |
| 85 | + bfe_vec![0, u32::MAX, u64::from(u32::MAX) + 1, BFieldElement::MAX] |
147 | 86 | }
|
148 | 87 | }
|
149 | 88 |
|
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 |
| - ); |
| 89 | + #[test] |
| 90 | + fn rust_shadow() { |
| 91 | + ShadowedClosure::new(IsU32).test(); |
161 | 92 | }
|
162 | 93 | }
|
163 | 94 |
|
164 | 95 | #[cfg(test)]
|
165 | 96 | mod benches {
|
166 | 97 | use super::*;
|
167 |
| - use crate::snippet_bencher::bench_and_write; |
| 98 | + use crate::test_prelude::*; |
168 | 99 |
|
169 | 100 | #[test]
|
170 | 101 | fn is_u32_benchmark() {
|
171 |
| - bench_and_write(IsU32); |
| 102 | + ShadowedClosure::new(IsU32).bench(); |
172 | 103 | }
|
173 | 104 | }
|
0 commit comments