Skip to main content

yevm_core/ops/
basic.rs

1use yevm_base::{
2    Int,
3    math::{ONE, ZERO, lift},
4};
5use yevm_misc::keccak256;
6
7use crate::evm::{self, Evm, EvmResult, EvmYield};
8use crate::state::State;
9use crate::trace::Event;
10
11pub fn stop(_: &mut Evm) -> EvmResult<()> {
12    Err(EvmYield::Return(vec![]))
13}
14
15#[inline]
16pub fn add(evm: &mut Evm) -> EvmResult<()> {
17    evm.gas_charge(3)?;
18    let [a, b] = evm.peek()?;
19    let f = lift(|[a, b]| a + b);
20    let r = f([a, b]);
21    evm.push(r)?;
22    Ok(())
23}
24
25pub fn mul(evm: &mut Evm) -> EvmResult<()> {
26    evm.gas_charge(5)?;
27    let [a, b] = evm.peek()?;
28    let f = lift(|[a, b]| a * b);
29    let r = f([a, b]);
30    evm.push(r)?;
31    Ok(())
32}
33
34pub fn sub(evm: &mut Evm) -> EvmResult<()> {
35    evm.gas_charge(3)?;
36    let [a, b] = evm.peek()?;
37    let f = lift(|[a, b]| a - b);
38    let r = f([a, b]);
39    evm.push(r)?;
40    Ok(())
41}
42
43pub fn div(evm: &mut Evm) -> EvmResult<()> {
44    evm.gas_charge(5)?;
45    let [a, b] = evm.peek()?;
46    if b.is_zero() {
47        evm.push(Int::ZERO)?;
48        return Ok(());
49    }
50    let f = lift(|[a, b]| a / b);
51    let r = f([a, b]);
52    evm.push(r)?;
53    Ok(())
54}
55
56pub fn sdiv(evm: &mut Evm) -> EvmResult<()> {
57    use yevm_base::math::U256;
58    evm.gas_charge(5)?;
59    let [a, b] = evm.peek()?;
60    if b.is_zero() {
61        evm.push(Int::ZERO)?;
62        return Ok(());
63    }
64    let f = lift(|[a, b]| {
65        let neg = |x: U256| (!x) + U256::ONE;
66        let sign_a = a.bit(255);
67        let sign_b = b.bit(255);
68        let abs_a = if sign_a { neg(a) } else { a };
69        let abs_b = if sign_b { neg(b) } else { b };
70        let result = abs_a / abs_b;
71        if sign_a != sign_b {
72            neg(result)
73        } else {
74            result
75        }
76    });
77    let r = f([a, b]);
78    evm.push(r)?;
79    Ok(())
80}
81
82pub fn r#mod(evm: &mut Evm) -> EvmResult<()> {
83    evm.gas_charge(5)?;
84    let [a, b] = evm.peek()?;
85    if b.is_zero() {
86        evm.push(Int::ZERO)?;
87        return Ok(());
88    }
89    let f = lift(|[a, b]| a % b);
90    let r = f([a, b]);
91    evm.push(r)?;
92    Ok(())
93}
94
95pub fn smod(evm: &mut Evm) -> EvmResult<()> {
96    use yevm_base::math::U256;
97    evm.gas_charge(5)?;
98    let [a, b] = evm.peek()?;
99    let f = lift(|[a, b]| {
100        if b.is_zero() {
101            return U256::ZERO;
102        }
103        let neg = |x: U256| (!x) + U256::ONE;
104        let sign_a = a.bit(255);
105        let abs_a = if sign_a { neg(a) } else { a };
106        let abs_b = if b.bit(255) { neg(b) } else { b };
107        let result = abs_a % abs_b;
108        if sign_a && !result.is_zero() {
109            neg(result)
110        } else {
111            result
112        }
113    });
114    let r = f([a, b]);
115    evm.push(r)?;
116    Ok(())
117}
118
119pub fn addmod(evm: &mut Evm) -> EvmResult<()> {
120    evm.gas_charge(8)?;
121    let [a, b, m] = evm.peek()?;
122    let f = lift(|[a, b, m]| a.add_mod(b, m));
123    let r = f([a, b, m]);
124    evm.push(r)?;
125    Ok(())
126}
127
128pub fn mulmod(evm: &mut Evm) -> EvmResult<()> {
129    evm.gas_charge(8)?;
130    let [a, b, m] = evm.peek()?;
131    let f = lift(|[a, b, m]| a.mul_mod(b, m));
132    let r = f([a, b, m]);
133    evm.push(r)?;
134    Ok(())
135}
136
137pub fn exp(evm: &mut Evm) -> EvmResult<()> {
138    let [a, b] = evm.peek()?;
139    // EIP-160: 10 + 50 * exponent_byte_size
140    let exp_cost = if b.is_zero() {
141        10
142    } else {
143        use yevm_base::math::U256;
144        let b_u = U256::from_be_slice(b.as_ref());
145        let bit_len = 256 - b_u.leading_zeros();
146        10 + 50 * bit_len.div_ceil(8) as i64
147    };
148    evm.gas_charge(exp_cost)?;
149    let f = lift(|[a, b]| a.pow(b));
150    let r = f([a, b]);
151    evm.push(r)?;
152    Ok(())
153}
154
155pub fn signextend(evm: &mut Evm) -> EvmResult<()> {
156    use yevm_base::math::U256;
157    evm.gas_charge(5)?;
158    let [b, x] = evm.peek()?;
159    let f = lift(|[b, x]| {
160        if b >= U256::from(32u32) {
161            return x;
162        }
163        let b = b.saturating_to::<usize>();
164        let sign_bit = b * 8 + 7;
165        let low_bits = b * 8 + 8; // == (b+1)*8
166        let mask = if low_bits == 256 {
167            U256::MAX
168        } else {
169            (U256::ONE << low_bits) - U256::ONE
170        };
171        if x.bit(sign_bit) { x | !mask } else { x & mask }
172    });
173    let r = f([b, x]);
174    evm.push(r)?;
175    Ok(())
176}
177
178pub fn lt(evm: &mut Evm) -> EvmResult<()> {
179    evm.gas_charge(3)?;
180    let [a, b] = evm.peek()?;
181    let f = lift(|[a, b]| if a < b { ONE } else { ZERO });
182    let r = f([a, b]);
183    evm.push(r)?;
184    Ok(())
185}
186
187pub fn gt(evm: &mut Evm) -> EvmResult<()> {
188    evm.gas_charge(3)?;
189    let [a, b] = evm.peek()?;
190    let f = lift(|[a, b]| if a > b { ONE } else { ZERO });
191    let r = f([a, b]);
192    evm.push(r)?;
193    Ok(())
194}
195
196pub fn slt(evm: &mut Evm) -> EvmResult<()> {
197    evm.gas_charge(3)?;
198    let [a, b] = evm.peek()?;
199    let f = lift(|[a, b]| {
200        // Signed: flip the sign bit so the unsigned order matches signed order
201        let key = |x| x ^ (ONE << 255);
202        if key(a) < key(b) { ONE } else { ZERO }
203    });
204    let r = f([a, b]);
205    evm.push(r)?;
206    Ok(())
207}
208
209pub fn sgt(evm: &mut Evm) -> EvmResult<()> {
210    evm.gas_charge(3)?;
211    let [a, b] = evm.peek()?;
212    let f = lift(|[a, b]| {
213        let key = |x| x ^ (ONE << 255);
214        if key(a) > key(b) { ONE } else { ZERO }
215    });
216    let r = f([a, b]);
217    evm.push(r)?;
218    Ok(())
219}
220
221pub fn eq(evm: &mut Evm) -> EvmResult<()> {
222    evm.gas_charge(3)?;
223    let [a, b] = evm.peek()?;
224    let f = lift(|[a, b]| if a == b { ONE } else { ZERO });
225    let r = f([a, b]);
226    evm.push(r)?;
227    Ok(())
228}
229
230pub fn iszero(evm: &mut Evm) -> EvmResult<()> {
231    evm.gas_charge(3)?;
232    let [x] = evm.peek()?;
233    let f = lift(|[x]| if x.is_zero() { ONE } else { ZERO });
234    let r = f([x]);
235    evm.push(r)?;
236    Ok(())
237}
238
239pub fn and(evm: &mut Evm) -> EvmResult<()> {
240    evm.gas_charge(3)?;
241    let [a, b] = evm.peek()?;
242    let f = lift(|[a, b]| a & b);
243    let r = f([a, b]);
244    evm.push(r)?;
245    Ok(())
246}
247
248pub fn or(evm: &mut Evm) -> EvmResult<()> {
249    evm.gas_charge(3)?;
250    let [a, b] = evm.peek()?;
251    let f = lift(|[a, b]| a | b);
252    let r = f([a, b]);
253    evm.push(r)?;
254    Ok(())
255}
256
257pub fn xor(evm: &mut Evm) -> EvmResult<()> {
258    evm.gas_charge(3)?;
259    let [a, b] = evm.peek()?;
260    let f = lift(|[a, b]| a ^ b);
261    let r = f([a, b]);
262    evm.push(r)?;
263    Ok(())
264}
265
266pub fn not(evm: &mut Evm) -> EvmResult<()> {
267    evm.gas_charge(3)?;
268    let [x] = evm.peek()?;
269    let f = lift(|[x]| !x);
270    let r = f([x]);
271    evm.push(r)?;
272    Ok(())
273}
274
275pub fn byte(evm: &mut Evm) -> EvmResult<()> {
276    evm.gas_charge(3)?;
277    let [idx, int] = evm.peek()?;
278    let byte = int
279        .as_ref()
280        .get(idx.as_usize())
281        .copied()
282        .unwrap_or_default();
283    evm.push(Int::from(byte))?;
284    Ok(())
285}
286
287pub fn shl(evm: &mut Evm) -> EvmResult<()> {
288    evm.gas_charge(3)?;
289    let [shift, val] = evm.peek()?;
290    let f = lift(|[shift, val]| val << shift);
291    let r = f([shift, val]);
292    evm.push(r)?;
293    Ok(())
294}
295
296pub fn shr(evm: &mut Evm) -> EvmResult<()> {
297    evm.gas_charge(3)?;
298    let [shift, val] = evm.peek()?;
299    let f = lift(|[shift, val]| val >> shift);
300    let r = f([shift, val]);
301    evm.push(r)?;
302    Ok(())
303}
304
305pub fn sar(evm: &mut Evm) -> EvmResult<()> {
306    evm.gas_charge(3)?;
307    let [shift, val] = evm.peek()?;
308    let f = lift(|[shift, val]| val.arithmetic_shr(shift.saturating_to::<usize>()));
309    let r = f([shift, val]);
310    evm.push(r)?;
311    Ok(())
312}
313
314pub fn clz(evm: &mut Evm) -> EvmResult<()> {
315    use yevm_base::math::U256;
316    evm.gas_charge(5)?;
317    let [x] = evm.peek()?;
318    let f = lift(|[x]| U256::from(x.leading_zeros()));
319    let r = f([x]);
320    evm.push(r)?;
321    Ok(())
322}
323
324pub fn hash(evm: &mut Evm, state: &mut dyn State) -> EvmResult<()> {
325    evm.gas_charge(30)?;
326    let [offset, size] = evm.peek()?;
327    evm::mem_check_int(offset, size)?;
328    let (offset, size) = (offset.as_usize(), size.as_usize());
329    evm.gas_charge(6 * size.div_ceil(32) as i64)?;
330    let data = evm.mem_get(offset, size)?;
331    let hash = keccak256(&data);
332    let hash_int = Int::from(hash.as_ref());
333    state.emit(Event::Hash(data.into(), hash_int));
334    evm.push(hash_int)?;
335    Ok(())
336}