Skip to content

Commit a9f3f88

Browse files
committed
signoff!: u32::is_odd
BREAKING CHANGE: Remove the implementation of `DeprecatedSnippet` for `u32::is_odd::IsOdd`, implement `BasicSnippet` directly.
1 parent 5a006ad commit a9f3f88

File tree

1 file changed

+69
-119
lines changed

1 file changed

+69
-119
lines changed
Lines changed: 69 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,156 +1,106 @@
11
use std::collections::HashMap;
2-
3-
use rand::prelude::*;
42
use triton_vm::prelude::*;
53

6-
use crate::empty_stack;
74
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)]
1324
pub struct IsOdd;
1425

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())]
2629
}
2730

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())]
3033
}
3134

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()
3937
}
4038

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
5550
)
5651
}
5752

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
9657
}
9758
}
9859

9960
#[cfg(test)]
10061
mod tests {
10162
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::*;
10564

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;
11067

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+
}
12373

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+
}
12884
}
129-
}
13085

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+
}
13690

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();
14494
}
14595
}
14696

14797
#[cfg(test)]
14898
mod benches {
14999
use super::*;
150-
use crate::snippet_bencher::bench_and_write;
100+
use crate::test_prelude::*;
151101

152102
#[test]
153-
fn is_odd_u32_benchmark() {
154-
bench_and_write(IsOdd);
103+
fn benchmark() {
104+
ShadowedClosure::new(IsOdd).bench();
155105
}
156106
}

0 commit comments

Comments
 (0)