ethrex_levm/opcode_handlers/
arithmetic.rs1use crate::{
18 errors::{OpcodeResult, VMError},
19 gas_cost,
20 opcode_handlers::OpcodeHandler,
21 vm::VM,
22};
23use ethrex_common::{U256, U512};
24
25pub struct OpAddHandler;
27impl OpcodeHandler for OpAddHandler {
28 #[inline(always)]
29 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
30 vm.current_call_frame.increase_consumed_gas(gas_cost::ADD)?;
31
32 let (lhs, rhs) = vm.current_call_frame.stack.pop1_and_top_mut()?;
33 *rhs = lhs.overflowing_add(*rhs).0;
34
35 Ok(OpcodeResult::Continue)
36 }
37}
38
39pub struct OpSubHandler;
41impl OpcodeHandler for OpSubHandler {
42 #[inline(always)]
43 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
44 vm.current_call_frame.increase_consumed_gas(gas_cost::SUB)?;
45
46 let (lhs, rhs) = vm.current_call_frame.stack.pop1_and_top_mut()?;
47 *rhs = lhs.overflowing_sub(*rhs).0;
48
49 Ok(OpcodeResult::Continue)
50 }
51}
52
53pub struct OpMulHandler;
55impl OpcodeHandler for OpMulHandler {
56 #[inline(always)]
57 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
58 vm.current_call_frame.increase_consumed_gas(gas_cost::MUL)?;
59
60 let (lhs, rhs) = vm.current_call_frame.stack.pop1_and_top_mut()?;
61 *rhs = lhs.overflowing_mul(*rhs).0;
62
63 Ok(OpcodeResult::Continue)
64 }
65}
66
67pub struct OpDivHandler;
69impl OpcodeHandler for OpDivHandler {
70 #[inline(always)]
71 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
72 vm.current_call_frame.increase_consumed_gas(gas_cost::DIV)?;
73
74 let (lhs, rhs) = vm.current_call_frame.stack.pop1_and_top_mut()?;
75 *rhs = lhs.checked_div(*rhs).unwrap_or(U256::zero());
76
77 Ok(OpcodeResult::Continue)
78 }
79}
80
81pub struct OpSDivHandler;
83impl OpcodeHandler for OpSDivHandler {
84 #[inline(always)]
85 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
86 vm.current_call_frame
87 .increase_consumed_gas(gas_cost::SDIV)?;
88
89 let (top, slot) = vm.current_call_frame.stack.pop1_and_top_mut()?;
90 let mut lhs = top;
91 let mut rhs = *slot;
92
93 let mut sign = false;
94 if lhs.bit(255) {
95 lhs = U256::zero().overflowing_sub(lhs).0;
96 sign = !sign;
97 }
98 if rhs.bit(255) {
99 rhs = U256::zero().overflowing_sub(rhs).0;
100 sign = !sign;
101 }
102
103 *slot = match lhs.checked_div(rhs) {
104 Some(mut res) => {
105 if sign {
106 res = U256::zero().overflowing_sub(res).0;
107 }
108 res
109 }
110 None => U256::zero(),
111 };
112
113 Ok(OpcodeResult::Continue)
114 }
115}
116
117pub struct OpModHandler;
119impl OpcodeHandler for OpModHandler {
120 #[inline(always)]
121 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
122 vm.current_call_frame.increase_consumed_gas(gas_cost::MOD)?;
123
124 let (lhs, rhs) = vm.current_call_frame.stack.pop1_and_top_mut()?;
125 *rhs = lhs.checked_rem(*rhs).unwrap_or(U256::zero());
126
127 Ok(OpcodeResult::Continue)
128 }
129}
130
131pub struct OpSModHandler;
133impl OpcodeHandler for OpSModHandler {
134 #[inline(always)]
135 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
136 vm.current_call_frame
137 .increase_consumed_gas(gas_cost::SMOD)?;
138
139 let (top, slot) = vm.current_call_frame.stack.pop1_and_top_mut()?;
140 let mut lhs = top;
141 let mut rhs = *slot;
142
143 let sign = lhs.bit(255);
144 if sign {
145 (lhs, _) = (!lhs).overflowing_add(U256::one());
146 }
147 if rhs.bit(255) {
148 (rhs, _) = (!rhs).overflowing_add(U256::one());
149 }
150
151 *slot = match lhs.checked_rem(rhs) {
152 Some(mut res) => {
153 if sign {
154 (res, _) = (!res).overflowing_add(U256::one());
155 }
156 res
157 }
158 None => U256::zero(),
159 };
160
161 Ok(OpcodeResult::Continue)
162 }
163}
164
165pub struct OpAddModHandler;
167impl OpcodeHandler for OpAddModHandler {
168 #[inline(always)]
169 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
170 vm.current_call_frame
171 .increase_consumed_gas(gas_cost::ADDMOD)?;
172
173 let [lhs, rhs, r#mod] = *vm.current_call_frame.stack.pop()?;
174 if r#mod.is_zero() || r#mod == U256::one() {
175 vm.current_call_frame.stack.push_zero()?;
176 } else {
177 #[expect(
178 clippy::arithmetic_side_effects,
179 reason = "mod is checked non-zero above"
180 )]
181 let res = U512::from(lhs).overflowing_add(rhs.into()).0 % r#mod;
182 vm.current_call_frame
183 .stack
184 .push(U256([res.0[0], res.0[1], res.0[2], res.0[3]]))?;
185 }
186
187 Ok(OpcodeResult::Continue)
188 }
189}
190
191pub struct OpMulModHandler;
193impl OpcodeHandler for OpMulModHandler {
194 #[inline(always)]
195 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
196 vm.current_call_frame
197 .increase_consumed_gas(gas_cost::MULMOD)?;
198
199 let [multiplicand, multiplier, modulus] = *vm.current_call_frame.stack.pop()?;
200 if modulus.is_zero() || multiplicand.is_zero() || multiplier.is_zero() {
201 vm.current_call_frame.stack.push_zero()?;
202 } else {
203 let a_bytes = multiplicand.to_big_endian();
204 let b_bytes = multiplier.to_big_endian();
205 let m_bytes = modulus.to_big_endian();
206 let result_bytes = vm.crypto.mulmod256(&a_bytes, &b_bytes, &m_bytes);
207 let product_mod = U256::from_big_endian(&result_bytes);
208 vm.current_call_frame.stack.push(product_mod)?;
209 }
210
211 Ok(OpcodeResult::Continue)
212 }
213}
214
215pub struct OpExpHandler;
217impl OpcodeHandler for OpExpHandler {
218 #[inline(always)]
219 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
220 let [base, exp] = *vm.current_call_frame.stack.pop()?;
221 vm.current_call_frame
222 .increase_consumed_gas(gas_cost::exp(exp)?)?;
223
224 let (res, _) = base.overflowing_pow(exp);
225 vm.current_call_frame.stack.push(res)?;
226
227 Ok(OpcodeResult::Continue)
228 }
229}
230
231pub struct OpSignExtendHandler;
233impl OpcodeHandler for OpSignExtendHandler {
234 #[inline(always)]
235 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
236 vm.current_call_frame
237 .increase_consumed_gas(gas_cost::SIGNEXTEND)?;
238
239 let (index, slot) = vm.current_call_frame.stack.pop1_and_top_mut()?;
240 let mut value = *slot;
241 *slot = match usize::try_from(index) {
242 #[expect(
243 clippy::arithmetic_side_effects,
244 reason = "x < 32 guard prevents overflow"
245 )]
246 Ok(x) if x < 32 => {
247 if value.bit(8 * x + 7) {
248 value |= U256::MAX << (8 * (x + 1));
249 } else if x != 31 {
250 value &= (U256::one() << (8 * (x + 1))) - 1;
251 }
252
253 value
254 }
255 _ => value,
256 };
257
258 Ok(OpcodeResult::Continue)
259 }
260}
261
262pub struct OpClzHandler;
264impl OpcodeHandler for OpClzHandler {
265 #[inline(always)]
266 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
267 vm.current_call_frame.increase_consumed_gas(gas_cost::CLZ)?;
268
269 let slot = vm.current_call_frame.stack.top_mut()?;
270 let lz = slot.leading_zeros();
271 *slot = lz.into();
272
273 Ok(OpcodeResult::Continue)
274 }
275}