tasm_lib/arithmetic/i128/
lt.rs1use triton_vm::prelude::*;
2
3use crate::arithmetic;
4use crate::prelude::*;
5
6#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
27pub struct Lt;
28
29impl BasicSnippet for Lt {
30 fn parameters(&self) -> Vec<(DataType, String)> {
31 ["rhs", "lhs"]
32 .map(|s| (DataType::I128, s.to_string()))
33 .to_vec()
34 }
35
36 fn return_values(&self) -> Vec<(DataType, String)> {
37 vec![(DataType::Bool, "result".to_string())]
38 }
39
40 fn entrypoint(&self) -> String {
41 "tasmlib_arithmetic_i128_lt".to_owned()
42 }
43
44 fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
45 let entrypoint = self.entrypoint();
46 let u128_lt = library.import(Box::new(arithmetic::u128::lt::Lt));
47
48 const TWO_POW_31: u32 = 1 << 31;
49 let flip_msbs = triton_asm!(
50 pick 3
52 push {TWO_POW_31}
53 xor
54 place 3
55
56 pick 7
57 push {TWO_POW_31}
58 xor
59 place 7
60 );
62
63 triton_asm!(
64 {entrypoint}:
65 {&flip_msbs}
70 call {u128_lt}
73 return
76 )
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use std::collections::HashSet;
83
84 use triton_vm::error::InstructionError;
85 use triton_vm::error::OpStackError;
86
87 use super::*;
88 use crate::test_helpers::negative_test;
89 use crate::test_prelude::*;
90
91 impl Closure for Lt {
92 type Args = (i128, i128);
93
94 fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) -> Result<(), RustShadowError> {
95 let (rhs, lhs) = pop_encodable::<Self::Args>(stack)?;
96 push_encodable(stack, &(lhs < rhs));
97 Ok(())
98 }
99
100 fn pseudorandom_args(&self, seed: [u8; 32], _: Option<BenchmarkCase>) -> Self::Args {
101 StdRng::from_seed(seed).random()
102 }
103
104 fn corner_case_args(&self) -> Vec<Self::Args> {
105 let points_with_plus_minus_one = [
106 i128::MIN,
107 -(1 << 96),
108 -(1 << 64),
109 -(1 << 32),
110 -1,
111 1,
112 1 << 32,
113 1 << 64,
114 1 << 96,
115 1 << 126,
116 i128::MAX,
117 ]
118 .into_iter()
119 .flat_map(|p| [p.checked_sub(1), Some(p), p.checked_add(1)])
120 .flatten()
121 .collect::<HashSet<_>>()
122 .into_iter()
123 .collect_vec();
124
125 points_with_plus_minus_one
126 .iter()
127 .cartesian_product(&points_with_plus_minus_one)
128 .map(|(&l, &r)| (l, r))
129 .collect()
130 }
131 }
132
133 #[macro_rules_attr::apply(test)]
134 fn i128_lt_proptest() {
135 ShadowedClosure::new(Lt).test();
136 }
137
138 #[macro_rules_attr::apply(proptest)]
139 fn input_not_u32_words_negative_test(
140 #[strategy(0usize..8)] stack_index_bad_word: usize,
141 #[strategy(arb())]
142 #[filter(#bad_word.value() > u32::MAX as u64)]
143 bad_word: BFieldElement,
144 ) {
145 fn init_state_not_u32_words(
146 stack_index_bad_word: usize,
147 bad_word: BFieldElement,
148 ) -> InitVmState {
149 let mut stack = Lt.set_up_test_stack(rand::random());
150 let last_elem_index = stack.len() - 1;
151 stack[last_elem_index - stack_index_bad_word] = bad_word;
152
153 InitVmState::with_stack(stack)
154 }
155
156 negative_test(
157 &ShadowedClosure::new(Lt),
158 init_state_not_u32_words(stack_index_bad_word, bad_word),
159 &[InstructionError::OpStackError(
160 OpStackError::FailedU32Conversion(bad_word),
161 )],
162 );
163 }
164
165 #[macro_rules_attr::apply(test)]
166 fn i128_lt_unit_test_min_max() {
167 let init_stack = Lt.set_up_test_stack((i128::MAX, i128::MIN));
168 let mut expected_end_stack = Lt.init_stack_for_isolated_run();
169 push_encodable(&mut expected_end_stack, &true);
170
171 let stdin = &[];
172 test_rust_equivalence_given_complete_state(
173 &ShadowedClosure::new(Lt),
174 &init_stack,
175 stdin,
176 &NonDeterminism::default(),
177 &None,
178 Some(&expected_end_stack),
179 );
180 }
181
182 #[macro_rules_attr::apply(test)]
183 fn i128_lt_unit_test_zero_zero() {
184 let init_stack = Lt.set_up_test_stack((0, 0));
185 let mut expected_end_stack = Lt.init_stack_for_isolated_run();
186 push_encodable(&mut expected_end_stack, &false);
187
188 let stdin = &[];
189 test_rust_equivalence_given_complete_state(
190 &ShadowedClosure::new(Lt),
191 &init_stack,
192 stdin,
193 &NonDeterminism::default(),
194 &None,
195 Some(&expected_end_stack),
196 );
197 }
198
199 #[macro_rules_attr::apply(proptest)]
200 fn equal_elements_are_not_lt_prop(value: i128) {
201 let init_stack = Lt.set_up_test_stack((value, value));
202 let mut expected_end_stack = Lt.init_stack_for_isolated_run();
203 push_encodable(&mut expected_end_stack, &false);
204
205 let stdin = &[];
206 test_rust_equivalence_given_complete_state(
207 &ShadowedClosure::new(Lt),
208 &init_stack,
209 stdin,
210 &NonDeterminism::default(),
211 &None,
212 Some(&expected_end_stack),
213 );
214 }
215}
216
217#[cfg(test)]
218mod benches {
219 use super::*;
220 use crate::test_prelude::*;
221
222 #[macro_rules_attr::apply(test)]
223 fn benchmark() {
224 ShadowedClosure::new(Lt).bench();
225 }
226}