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 inputs(&self) -> Vec<(DataType, String)> {
31 ["rhs", "lhs"]
32 .map(|s| (DataType::I128, s.to_string()))
33 .to_vec()
34 }
35
36 fn outputs(&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>) {
95 let (rhs, lhs) = pop_encodable::<Self::Args>(stack);
96 push_encodable(stack, &(lhs < rhs));
97 }
98
99 fn pseudorandom_args(&self, seed: [u8; 32], _: Option<BenchmarkCase>) -> Self::Args {
100 StdRng::from_seed(seed).random()
101 }
102
103 fn corner_case_args(&self) -> Vec<Self::Args> {
104 let points_with_plus_minus_one = [
105 i128::MIN,
106 -(1 << 96),
107 -(1 << 64),
108 -(1 << 32),
109 -1,
110 1,
111 1 << 32,
112 1 << 64,
113 1 << 96,
114 1 << 126,
115 i128::MAX,
116 ]
117 .into_iter()
118 .flat_map(|p| [p.checked_sub(1), Some(p), p.checked_add(1)])
119 .flatten()
120 .collect::<HashSet<_>>()
121 .into_iter()
122 .collect_vec();
123
124 points_with_plus_minus_one
125 .iter()
126 .cartesian_product(&points_with_plus_minus_one)
127 .map(|(&l, &r)| (l, r))
128 .collect()
129 }
130 }
131
132 #[test]
133 fn i128_lt_proptest() {
134 ShadowedClosure::new(Lt).test();
135 }
136
137 #[proptest]
138 fn input_not_u32_words_negative_test(
139 #[strategy(0usize..8)] stack_index_bad_word: usize,
140 #[strategy(arb())]
141 #[filter(#bad_word.value() > u32::MAX as u64)]
142 bad_word: BFieldElement,
143 ) {
144 fn init_state_not_u32_words(
145 stack_index_bad_word: usize,
146 bad_word: BFieldElement,
147 ) -> InitVmState {
148 let mut stack = Lt.set_up_test_stack(rand::random());
149 let last_elem_index = stack.len() - 1;
150 stack[last_elem_index - stack_index_bad_word] = bad_word;
151
152 InitVmState::with_stack(stack)
153 }
154
155 negative_test(
156 &ShadowedClosure::new(Lt),
157 init_state_not_u32_words(stack_index_bad_word, bad_word),
158 &[InstructionError::OpStackError(
159 OpStackError::FailedU32Conversion(bad_word),
160 )],
161 );
162 }
163
164 #[test]
165 fn i128_lt_unit_test_min_max() {
166 let init_stack = Lt.set_up_test_stack((i128::MAX, i128::MIN));
167 let mut expected_end_stack = Lt.init_stack_for_isolated_run();
168 push_encodable(&mut expected_end_stack, &true);
169
170 let stdin = &[];
171 test_rust_equivalence_given_complete_state(
172 &ShadowedClosure::new(Lt),
173 &init_stack,
174 stdin,
175 &NonDeterminism::default(),
176 &None,
177 Some(&expected_end_stack),
178 );
179 }
180
181 #[test]
182 fn i128_lt_unit_test_zero_zero() {
183 let init_stack = Lt.set_up_test_stack((0, 0));
184 let mut expected_end_stack = Lt.init_stack_for_isolated_run();
185 push_encodable(&mut expected_end_stack, &false);
186
187 let stdin = &[];
188 test_rust_equivalence_given_complete_state(
189 &ShadowedClosure::new(Lt),
190 &init_stack,
191 stdin,
192 &NonDeterminism::default(),
193 &None,
194 Some(&expected_end_stack),
195 );
196 }
197
198 #[proptest]
199 fn equal_elements_are_not_lt_prop(value: i128) {
200 let init_stack = Lt.set_up_test_stack((value, value));
201 let mut expected_end_stack = Lt.init_stack_for_isolated_run();
202 push_encodable(&mut expected_end_stack, &false);
203
204 let stdin = &[];
205 test_rust_equivalence_given_complete_state(
206 &ShadowedClosure::new(Lt),
207 &init_stack,
208 stdin,
209 &NonDeterminism::default(),
210 &None,
211 Some(&expected_end_stack),
212 );
213 }
214}
215
216#[cfg(test)]
217mod benches {
218 use super::*;
219 use crate::test_prelude::*;
220
221 #[test]
222 fn benchmark() {
223 ShadowedClosure::new(Lt).bench();
224 }
225}