Skip to content

Commit b303c7f

Browse files
committed
signoff!: u32::or
BREAKING CHANGE: Remove the implementation of `DeprecatedSnippet` for `u32::or::Or`, implement `BasicSnippet` directly.
1 parent 647c279 commit b303c7f

File tree

2 files changed

+83
-139
lines changed

2 files changed

+83
-139
lines changed

tasm-lib/benchmarks/tasmlib_arithmetic_u32_or.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"benchmark_result": {
55
"clock_cycle_count": 9,
66
"hash_table_height": 12,
7-
"u32_table_height": 36,
7+
"u32_table_height": 18,
88
"op_stack_table_height": 5,
99
"ram_table_height": 0
1010
},

tasm-lib/src/arithmetic/u32/or.rs

Lines changed: 82 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1,172 +1,116 @@
1-
use rand::prelude::*;
1+
use std::collections::HashMap;
2+
23
use triton_vm::prelude::*;
34

4-
use crate::empty_stack;
55
use crate::prelude::*;
6-
use crate::traits::deprecated_snippet::DeprecatedSnippet;
7-
use crate::InitVmState;
8-
9-
#[derive(Clone, Debug)]
6+
use crate::traits::basic_snippet::Reviewer;
7+
use crate::traits::basic_snippet::SignOffFingerprint;
8+
9+
/// [Bitwise “or”][bitor] (“`|`”) for `u32`s.
10+
///
11+
/// ### Behavior
12+
///
13+
/// ```text
14+
/// BEFORE: _ [right: u32] [left: u32]
15+
/// AFTER: _ [left | right: u32]
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)]
1029
pub struct Or;
1130

12-
impl DeprecatedSnippet for Or {
13-
fn entrypoint_name(&self) -> String {
14-
"tasmlib_arithmetic_u32_or".to_string()
15-
}
16-
17-
fn input_field_names(&self) -> Vec<String> {
18-
vec!["rhs".to_string(), "lhs".to_string()]
19-
}
20-
21-
fn input_types(&self) -> Vec<DataType> {
22-
vec![DataType::U32, DataType::U32]
23-
}
24-
25-
fn output_field_names(&self) -> Vec<String> {
26-
vec!["lhs | rhs".to_string()]
31+
impl BasicSnippet for Or {
32+
fn inputs(&self) -> Vec<(DataType, String)> {
33+
["right", "left"]
34+
.map(|s| (DataType::U32, s.to_string()))
35+
.to_vec()
2736
}
2837

29-
fn output_types(&self) -> Vec<DataType> {
30-
vec![DataType::U32]
38+
fn outputs(&self) -> Vec<(DataType, String)> {
39+
vec![(DataType::U32, "left | right".to_string())]
3140
}
3241

33-
fn stack_diff(&self) -> isize {
34-
-1
35-
}
36-
37-
fn function_code(&self, _library: &mut crate::library::Library) -> String {
38-
let entrypoint = self.entrypoint_name();
39-
format!(
40-
"
41-
// BEFORE: _ rhs lhs
42-
// AFTER: _ (lhs | rhs)
43-
{entrypoint}:
44-
dup 1
45-
dup 1
46-
xor
47-
// _ rhs lhs (rhs ^ lhs)
48-
49-
swap 2
50-
and
51-
// _ (rhs ^ lhs) (lhs & rhs)
52-
53-
add
54-
55-
return
56-
"
57-
)
58-
}
59-
60-
fn crash_conditions(&self) -> Vec<String> {
61-
vec!["Inputs are not u32".to_owned()]
62-
}
63-
64-
fn gen_input_states(&self) -> Vec<InitVmState> {
65-
let mut ret: Vec<InitVmState> = vec![];
66-
for _ in 0..100 {
67-
let mut stack = empty_stack();
68-
let lhs = thread_rng().next_u32();
69-
let rhs = thread_rng().next_u32();
70-
let lhs = BFieldElement::new(lhs as u64);
71-
let rhs = BFieldElement::new(rhs as u64);
72-
stack.push(rhs);
73-
stack.push(lhs);
74-
ret.push(InitVmState::with_stack(stack));
75-
}
76-
77-
ret
78-
}
79-
80-
fn common_case_input_state(&self) -> InitVmState {
81-
InitVmState::with_stack(
82-
[
83-
empty_stack(),
84-
vec![BFieldElement::new(1 << 15), BFieldElement::new(1 << 16)],
85-
]
86-
.concat(),
87-
)
42+
fn entrypoint(&self) -> String {
43+
"tasmlib_arithmetic_u32_or".to_string()
8844
}
8945

90-
fn worst_case_input_state(&self) -> InitVmState {
91-
InitVmState::with_stack(
92-
[
93-
empty_stack(),
94-
vec![
95-
BFieldElement::new((1 << 32) - 1),
96-
BFieldElement::new((1 << 32) - 1),
97-
],
98-
]
99-
.concat(),
46+
fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
47+
triton_asm!(
48+
// BEFORE: _ right left
49+
// AFTER: _ (left | right)
50+
{self.entrypoint()}:
51+
dup 1
52+
dup 1 // _ right left right left
53+
xor // _ right left (right ^ left)
54+
place 2
55+
and // _ (right ^ left) (right & left)
56+
add
57+
return
10058
)
10159
}
10260

103-
fn rust_shadowing(
104-
&self,
105-
stack: &mut Vec<BFieldElement>,
106-
_std_in: Vec<BFieldElement>,
107-
_secret_in: Vec<BFieldElement>,
108-
_memory: &mut std::collections::HashMap<BFieldElement, BFieldElement>,
109-
) {
110-
let lhs: u32 = stack.pop().unwrap().try_into().unwrap();
111-
let rhs: u32 = stack.pop().unwrap().try_into().unwrap();
112-
113-
let or = lhs | rhs;
114-
stack.push(BFieldElement::new(or as u64));
61+
fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
62+
let mut sign_offs = HashMap::new();
63+
sign_offs.insert(Reviewer("ferdinand"), 0x78bc3071bcc44a84.into());
64+
sign_offs
11565
}
11666
}
11767

11868
#[cfg(test)]
11969
mod tests {
120-
use std::collections::HashMap;
121-
12270
use super::*;
123-
use crate::test_helpers::test_rust_equivalence_given_input_values_deprecated;
124-
use crate::test_helpers::test_rust_equivalence_multiple_deprecated;
71+
use crate::test_prelude::*;
12572

126-
#[test]
127-
fn snippet_test() {
128-
test_rust_equivalence_multiple_deprecated(&Or, true);
129-
}
73+
impl Closure for Or {
74+
type Args = (u32, u32);
13075

131-
#[test]
132-
fn or_simple_test() {
133-
prop_safe_or(10, 1, Some(11));
134-
prop_safe_or(256, 30, Some(286));
135-
prop_safe_or(123, 0, Some(123));
136-
prop_safe_or(0, 123, Some(123));
137-
prop_safe_or(1 << 31, 1 << 30, Some((1 << 30) + (1 << 31)));
138-
prop_safe_or(0, 0, Some(0));
139-
prop_safe_or(14, 0, Some(14));
140-
prop_safe_or(u32::MAX, 0, Some(u32::MAX));
141-
prop_safe_or(0, u32::MAX, Some(u32::MAX));
142-
prop_safe_or(u32::MAX, u32::MAX, Some(u32::MAX));
76+
fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) {
77+
let (right, left) = pop_encodable::<Self::Args>(stack);
78+
let or = left | right;
79+
push_encodable(stack, &or);
80+
}
81+
82+
fn pseudorandom_args(
83+
&self,
84+
seed: [u8; 32],
85+
bench_case: Option<BenchmarkCase>,
86+
) -> Self::Args {
87+
match bench_case {
88+
Some(BenchmarkCase::CommonCase) => (1 << 15, 1 << 16),
89+
Some(BenchmarkCase::WorstCase) => (u32::MAX, u32::MAX),
90+
None => StdRng::from_seed(seed).gen(),
91+
}
92+
}
93+
94+
fn corner_case_args(&self) -> Vec<Self::Args> {
95+
let edges = [0, 1, 2, 0b1110, 0b11110, 1 << 30, 1 << 31, u32::MAX];
96+
97+
edges.into_iter().cartesian_product(edges).collect()
98+
}
14399
}
144100

145-
fn prop_safe_or(lhs: u32, rhs: u32, _expected: Option<u32>) {
146-
let mut init_stack = empty_stack();
147-
init_stack.push(BFieldElement::new(rhs as u64));
148-
init_stack.push(BFieldElement::new(lhs as u64));
149-
150-
let expected = lhs | rhs;
151-
let expected = [empty_stack(), vec![BFieldElement::new(expected as u64)]].concat();
152-
153-
test_rust_equivalence_given_input_values_deprecated(
154-
&Or,
155-
&init_stack,
156-
&[],
157-
HashMap::default(),
158-
Some(&expected),
159-
);
101+
#[test]
102+
fn rust_shadow() {
103+
ShadowedClosure::new(Or).test();
160104
}
161105
}
162106

163107
#[cfg(test)]
164108
mod benches {
165109
use super::*;
166-
use crate::snippet_bencher::bench_and_write;
110+
use crate::test_prelude::*;
167111

168112
#[test]
169-
fn u32_or_benchmark() {
170-
bench_and_write(Or);
113+
fn benchmark() {
114+
ShadowedClosure::new(Or).bench();
171115
}
172116
}

0 commit comments

Comments
 (0)