Skip to content

Commit 8d272de

Browse files
committed
signoff!: u64::xor
BREAKING CHANGE: Remove the implementation of `DeprecatedSnippet` for `u64::xor::Xor`, implement `BasicSnippet` directly.
1 parent ea54a09 commit 8d272de

File tree

1 file changed

+67
-157
lines changed
  • tasm-lib/src/arithmetic/u64

1 file changed

+67
-157
lines changed

tasm-lib/src/arithmetic/u64/xor.rs

Lines changed: 67 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -1,202 +1,112 @@
11
use std::collections::HashMap;
22

3-
use num::Zero;
4-
use rand::prelude::*;
53
use triton_vm::prelude::*;
6-
use twenty_first::prelude::U32s;
74

8-
use crate::empty_stack;
95
use crate::prelude::*;
10-
use crate::push_encodable;
11-
use crate::traits::deprecated_snippet::DeprecatedSnippet;
12-
use crate::InitVmState;
13-
14-
#[derive(Clone, Debug)]
6+
use crate::traits::basic_snippet::Reviewer;
7+
use crate::traits::basic_snippet::SignOffFingerprint;
8+
9+
/// [Bitwise xor][bitxor] of two `u64`s.
10+
///
11+
/// ### Behavior
12+
///
13+
/// ```text
14+
/// BEFORE: _ [right: u64] [left: u64]
15+
/// AFTER: _ [xor: u64]
16+
/// ```
17+
///
18+
/// ### Preconditions
19+
///
20+
/// - all input arguments are properly [`BFieldCodec`] encoded
21+
///
22+
/// ### Postconditions
23+
///
24+
/// - the output is the bitwise “xor” of the input
25+
/// - the output is properly [`BFieldCodec`] encoded
26+
///
27+
/// [bitxor]: core::ops::BitXor
28+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1529
pub struct Xor;
1630

17-
impl DeprecatedSnippet for Xor {
18-
fn entrypoint_name(&self) -> String {
19-
"tasmlib_arithmetic_u64_xor".to_string()
31+
impl BasicSnippet for Xor {
32+
fn inputs(&self) -> Vec<(DataType, String)> {
33+
["right", "left"]
34+
.map(|side| (DataType::U64, side.to_string()))
35+
.to_vec()
2036
}
2137

22-
fn input_field_names(&self) -> Vec<String> {
23-
vec![
24-
"rhs_hi".to_string(),
25-
"rhs_lo".to_string(),
26-
"lhs_hi".to_string(),
27-
"lhs_lo".to_string(),
28-
]
38+
fn outputs(&self) -> Vec<(DataType, String)> {
39+
vec![(DataType::U64, "xor".to_string())]
2940
}
3041

31-
fn input_types(&self) -> Vec<DataType> {
32-
vec![DataType::U64, DataType::U64]
33-
}
34-
35-
fn output_field_names(&self) -> Vec<String> {
36-
vec!["(lhs ^ rhs)_hi".to_string(), "(lhs ^ rhs)_lo".to_string()]
37-
}
38-
39-
fn output_types(&self) -> Vec<DataType> {
40-
vec![DataType::U64]
41-
}
42-
43-
fn stack_diff(&self) -> isize {
44-
-2
42+
fn entrypoint(&self) -> String {
43+
"tasmlib_arithmetic_u64_xor".to_string()
4544
}
4645

47-
fn function_code(&self, _library: &mut Library) -> String {
48-
let entrypoint = self.entrypoint_name();
49-
format!(
50-
"
51-
// BEFORE: rhs_hi rhs_lo lhs_hi lhs_lo
52-
// AFTER: (rhs ^ lhs)_hi (rhs ^ lhs)_lo
53-
{entrypoint}:
46+
fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
47+
triton_asm!(
48+
// BEFORE: _ rhs_hi rhs_lo lhs_hi lhs_lo
49+
// AFTER: _ (rhs ^ lhs)_hi (rhs ^ lhs)_lo
50+
{self.entrypoint()}:
5451
swap 3
5552
xor
56-
// stack: _ lhs_lo rhs_lo (lhs_hi ^ rhs_hi)
53+
// _ lhs_lo rhs_lo (lhs_hi ^ rhs_hi)
5754

5855
swap 2
5956
xor
60-
// stack: _ (lhs_hi ^ rhs_hi) (rhs_lo ^ lhs_lo)
57+
// _ (lhs_hi ^ rhs_hi) (lhs_lo ^ rhs_lo)
58+
// _ (lhs ^ rhs)_hi (lhs ^ rhs)_lo
6159

6260
return
63-
"
6461
)
6562
}
6663

67-
fn crash_conditions(&self) -> Vec<String> {
68-
vec!["any input is not u32".to_string()]
69-
}
70-
71-
fn gen_input_states(&self) -> Vec<InitVmState> {
72-
let mut rng = rand::thread_rng();
73-
let lhs = U32s::<2>::try_from(rng.next_u64()).unwrap();
74-
let rhs = U32s::<2>::try_from(rng.next_u64()).unwrap();
75-
let mut stack = empty_stack();
76-
push_encodable(&mut stack, &lhs);
77-
push_encodable(&mut stack, &rhs);
78-
vec![InitVmState::with_stack(stack)]
79-
}
80-
81-
fn common_case_input_state(&self) -> InitVmState {
82-
InitVmState::with_stack(
83-
[
84-
empty_stack(),
85-
vec![BFieldElement::zero(), BFieldElement::new((1 << 31) - 1)],
86-
vec![BFieldElement::zero(), BFieldElement::new((1 << 10) - 1)],
87-
]
88-
.concat(),
89-
)
90-
}
91-
92-
fn worst_case_input_state(&self) -> InitVmState {
93-
InitVmState::with_stack(
94-
[
95-
empty_stack(),
96-
vec![BFieldElement::new(1 << 31), BFieldElement::new(1 << 31)],
97-
vec![
98-
BFieldElement::new(1 << 30),
99-
BFieldElement::new((1 << 31) + 10),
100-
],
101-
]
102-
.concat(),
103-
)
104-
}
105-
106-
fn rust_shadowing(
107-
&self,
108-
stack: &mut Vec<BFieldElement>,
109-
_std_in: Vec<BFieldElement>,
110-
_secret_in: Vec<BFieldElement>,
111-
_memory: &mut HashMap<BFieldElement, BFieldElement>,
112-
) {
113-
// top element on stack
114-
let a_lo: u32 = stack.pop().unwrap().try_into().unwrap();
115-
let a_hi: u32 = stack.pop().unwrap().try_into().unwrap();
116-
117-
// second element on stack
118-
let b_lo: u32 = stack.pop().unwrap().try_into().unwrap();
119-
let b_hi: u32 = stack.pop().unwrap().try_into().unwrap();
120-
121-
// Perform calculation and write the result back to the stack
122-
let xor_res = U32s::<2>::new([a_lo ^ b_lo, a_hi ^ b_hi]);
123-
let mut res = xor_res.encode();
124-
for _ in 0..res.len() {
125-
stack.push(res.pop().unwrap());
126-
}
64+
fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
65+
let mut sign_offs = HashMap::new();
66+
sign_offs.insert(Reviewer("ferdinand"), 0x7ed1b73a89177516.into());
67+
sign_offs
12768
}
12869
}
12970

13071
#[cfg(test)]
13172
mod tests {
132-
use num::BigUint;
133-
13473
use super::*;
135-
use crate::empty_stack;
136-
use crate::test_helpers::test_rust_equivalence_given_input_values_deprecated;
137-
use crate::test_helpers::test_rust_equivalence_multiple_deprecated;
74+
use crate::test_prelude::*;
13875

139-
#[test]
140-
fn xor_u64_test() {
141-
test_rust_equivalence_multiple_deprecated(&Xor, true);
142-
}
76+
impl Closure for Xor {
77+
type Args = (u64, u64);
14378

144-
#[test]
145-
fn xor_test_simple() {
146-
prop_xor(4, 3);
147-
prop_xor(4, 4);
148-
prop_xor(u64::MAX, u64::MAX);
149-
prop_xor(0, u64::MAX);
150-
prop_xor(u64::MAX, 0);
151-
}
152-
153-
#[test]
154-
fn xor_test_pbt() {
155-
let mut rng = thread_rng();
156-
for _ in 0..100 {
157-
let lhs = rng.next_u64();
158-
let rhs = rng.next_u64();
159-
prop_xor(lhs, rhs);
160-
}
161-
}
162-
163-
fn prop_xor(lhs: u64, rhs: u64) {
164-
let mut init_stack = empty_stack();
165-
166-
let rhs_u32_2 = U32s::<2>::new([(rhs & u32::MAX as u64) as u32, (rhs >> 32) as u32]);
167-
for elem in rhs_u32_2.encode().into_iter().rev() {
168-
init_stack.push(elem);
79+
fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) {
80+
let (right, left) = pop_encodable::<Self::Args>(stack);
81+
push_encodable(stack, &(left ^ right));
16982
}
17083

171-
let lhs_u32_2 = U32s::<2>::new([(lhs & u32::MAX as u64) as u32, (lhs >> 32) as u32]);
172-
for elem in lhs_u32_2.encode().into_iter().rev() {
173-
init_stack.push(elem);
174-
}
175-
176-
let expected_res: BigUint = (lhs ^ rhs).into();
177-
let expected_u32_2: U32s<2> = expected_res.into();
178-
let mut expected_end_stack = empty_stack();
179-
for elem in expected_u32_2.encode().into_iter().rev() {
180-
expected_end_stack.push(elem);
84+
fn pseudorandom_args(
85+
&self,
86+
seed: [u8; 32],
87+
bench_case: Option<BenchmarkCase>,
88+
) -> Self::Args {
89+
match bench_case {
90+
Some(BenchmarkCase::CommonCase) => (0x7fff_ffff, 0x3ff),
91+
Some(BenchmarkCase::WorstCase) => (0x8000_0000_8000_0000, 0x4000_0000_8000_000a),
92+
None => StdRng::from_seed(seed).gen(),
93+
}
18194
}
95+
}
18296

183-
test_rust_equivalence_given_input_values_deprecated(
184-
&Xor,
185-
&init_stack,
186-
&[],
187-
HashMap::default(),
188-
Some(&expected_end_stack),
189-
);
97+
#[test]
98+
fn rust_shadow() {
99+
ShadowedClosure::new(Xor).test();
190100
}
191101
}
192102

193103
#[cfg(test)]
194104
mod benches {
195105
use super::*;
196-
use crate::snippet_bencher::bench_and_write;
106+
use crate::test_prelude::*;
197107

198108
#[test]
199-
fn xor_u64_benchmark() {
200-
bench_and_write(Xor);
109+
fn benchmark() {
110+
ShadowedClosure::new(Xor).bench();
201111
}
202112
}

0 commit comments

Comments
 (0)