tasm_lib/arithmetic/u160/
lt.rs1use triton_vm::prelude::*;
2
3use crate::prelude::*;
4
5#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
22pub struct Lt;
23
24impl BasicSnippet for Lt {
25 fn parameters(&self) -> Vec<(DataType, String)> {
26 ["rhs", "lhs"]
27 .map(|s| (DataType::U160, s.to_string()))
28 .to_vec()
29 }
30
31 fn return_values(&self) -> Vec<(DataType, String)> {
32 vec![(DataType::Bool, "cmp".to_string())]
33 }
34
35 fn entrypoint(&self) -> String {
36 "tasmlib_arithmetic_u160_lt".to_string()
37 }
38
39 fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
40 let entrypoint = self.entrypoint();
41
42 let lt_u128 = library.import(Box::new(crate::arithmetic::u128::lt::Lt));
43
44 triton_asm! {
45 {entrypoint}:
48
49 pick 4
57 place 8
58 call {lt_u128}
61 dup 2
64 dup 2
65 eq
66 mul
69 place 2
72 lt
73 add
74 return
78 }
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use num::BigUint;
85 use rand::rngs::StdRng;
86
87 use super::*;
88 use crate::arithmetic::u160::u128_to_u160;
89 use crate::test_helpers::test_rust_equivalence_given_execution_state;
90 use crate::test_prelude::*;
91
92 impl Closure for Lt {
93 type Args = ([u32; 5], [u32; 5]);
94
95 fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) {
96 let left: [u32; 5] = pop_encodable(stack);
97 let left: BigUint = BigUint::new(left.to_vec());
98
99 let right: [u32; 5] = pop_encodable(stack);
100 let right: BigUint = BigUint::new(right.to_vec());
101 push_encodable(stack, &(left < right));
102 }
103
104 fn pseudorandom_args(&self, seed: [u8; 32], _: Option<BenchmarkCase>) -> Self::Args {
105 StdRng::from_seed(seed).random()
106 }
107 }
108
109 fn test_rust_tasm_equivalence(left: [u32; 5], right: [u32; 5]) {
110 let initial_state = InitVmState::with_stack(Lt.set_up_test_stack((left, right)));
111 test_rust_equivalence_given_execution_state(&ShadowedClosure::new(Lt), initial_state);
112 }
113
114 #[test]
115 fn lt_u160_standard_test() {
116 ShadowedClosure::new(Lt).test()
117 }
118
119 #[test]
120 fn lt_u160_edge_cases_test() {
121 let mut boundary_points = [0, 1 << 32, 1 << 64, 1 << 96, u128::MAX]
122 .into_iter()
123 .flat_map(|p| [p.checked_sub(1), Some(p), p.checked_add(1)])
124 .flatten()
125 .map(u128_to_u160)
126 .collect_vec();
127 boundary_points.extend([
128 [u32::MAX; 5],
129 [1; 5],
130 [0, 0, 0, 0, 1],
131 [0, 0, 0, 0, u32::MAX],
132 [0x72581af6, 0, 0, 0, 0x72581af6],
133 [0x72581af6, 0, 0, 0, 0x72581af5],
134 [0x72581af5, 0, 0, 0, 0x72581af6],
135 [0x72581af5, 0, 0, 0, 0x72581af5],
136 ]);
137
138 for (&left, &right) in boundary_points.iter().cartesian_product(&boundary_points) {
139 test_rust_tasm_equivalence(left, right);
140 }
141 }
142
143 #[proptest]
144 fn lt_u160_randomized_test_identical_args(v: [u32; 5]) {
145 test_rust_tasm_equivalence(v, v);
146 }
147}
148
149#[cfg(test)]
150mod benches {
151 use super::*;
152 use crate::test_prelude::*;
153
154 #[test]
155 fn benchmark() {
156 ShadowedClosure::new(Lt).bench()
157 }
158}