revm_interpreter/instructions/
bitwise.rs

1use super::i256::i256_cmp;
2use crate::{
3    interpreter_types::{InterpreterTypes, RuntimeFlag, StackTr},
4    InstructionContext,
5};
6use core::cmp::Ordering;
7use primitives::U256;
8
9/// Implements the LT instruction - less than comparison.
10pub fn lt<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
11    popn_top!([op1], op2, context.interpreter);
12    *op2 = U256::from(op1 < *op2);
13}
14
15/// Implements the GT instruction - greater than comparison.
16pub fn gt<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
17    popn_top!([op1], op2, context.interpreter);
18    *op2 = U256::from(op1 > *op2);
19}
20
21/// Implements the CLZ instruction - count leading zeros.
22pub fn clz<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
23    check!(context.interpreter, OSAKA);
24    popn_top!([], op1, context.interpreter);
25    let leading_zeros = op1.leading_zeros();
26    *op1 = U256::from(leading_zeros);
27}
28
29/// Implements the SLT instruction.
30///
31/// Signed less than comparison of two values from stack.
32pub fn slt<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
33    popn_top!([op1], op2, context.interpreter);
34    *op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Less);
35}
36
37/// Implements the SGT instruction.
38///
39/// Signed greater than comparison of two values from stack.
40pub fn sgt<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
41    popn_top!([op1], op2, context.interpreter);
42    *op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Greater);
43}
44
45/// Implements the EQ instruction.
46///
47/// Equality comparison of two values from stack.
48pub fn eq<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
49    popn_top!([op1], op2, context.interpreter);
50    *op2 = U256::from(op1 == *op2);
51}
52
53/// Implements the ISZERO instruction.
54///
55/// Checks if the top stack value is zero.
56pub fn iszero<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
57    popn_top!([], op1, context.interpreter);
58    *op1 = U256::from(op1.is_zero());
59}
60
61/// Implements the AND instruction.
62///
63/// Bitwise AND of two values from stack.
64pub fn bitand<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
65    popn_top!([op1], op2, context.interpreter);
66    *op2 = op1 & *op2;
67}
68
69/// Implements the OR instruction.
70///
71/// Bitwise OR of two values from stack.
72pub fn bitor<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
73    popn_top!([op1], op2, context.interpreter);
74    *op2 = op1 | *op2;
75}
76
77/// Implements the XOR instruction.
78///
79/// Bitwise XOR of two values from stack.
80pub fn bitxor<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
81    popn_top!([op1], op2, context.interpreter);
82    *op2 = op1 ^ *op2;
83}
84
85/// Implements the NOT instruction.
86///
87/// Bitwise NOT (negation) of the top stack value.
88pub fn not<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
89    popn_top!([], op1, context.interpreter);
90    *op1 = !*op1;
91}
92
93/// Implements the BYTE instruction.
94///
95/// Extracts a single byte from a word at a given index.
96pub fn byte<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
97    popn_top!([op1], op2, context.interpreter);
98    let o1 = as_usize_saturated!(op1);
99    *op2 = if o1 < 32 {
100        // `31 - o1` because `byte` returns LE, while we want BE
101        U256::from(op2.byte(31 - o1))
102    } else {
103        U256::ZERO
104    };
105}
106
107/// EIP-145: Bitwise shifting instructions in EVM
108pub fn shl<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
109    check!(context.interpreter, CONSTANTINOPLE);
110    popn_top!([op1], op2, context.interpreter);
111    let shift = as_usize_saturated!(op1);
112    *op2 = if shift < 256 {
113        *op2 << shift
114    } else {
115        U256::ZERO
116    }
117}
118
119/// EIP-145: Bitwise shifting instructions in EVM
120pub fn shr<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
121    check!(context.interpreter, CONSTANTINOPLE);
122    popn_top!([op1], op2, context.interpreter);
123    let shift = as_usize_saturated!(op1);
124    *op2 = if shift < 256 {
125        *op2 >> shift
126    } else {
127        U256::ZERO
128    }
129}
130
131/// EIP-145: Bitwise shifting instructions in EVM
132pub fn sar<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
133    check!(context.interpreter, CONSTANTINOPLE);
134    popn_top!([op1], op2, context.interpreter);
135    let shift = as_usize_saturated!(op1);
136    *op2 = if shift < 256 {
137        op2.arithmetic_shr(shift)
138    } else if op2.bit(255) {
139        U256::MAX
140    } else {
141        U256::ZERO
142    };
143}
144
145#[cfg(test)]
146mod tests {
147    use crate::{
148        host::DummyHost,
149        instructions::bitwise::{byte, clz, sar, shl, shr},
150        InstructionContext, Interpreter,
151    };
152    use primitives::{hardfork::SpecId, uint, U256};
153
154    #[test]
155    fn test_shift_left() {
156        let mut interpreter = Interpreter::default();
157
158        struct TestCase {
159            value: U256,
160            shift: U256,
161            expected: U256,
162        }
163
164        uint! {
165            let test_cases = [
166                TestCase {
167                    value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
168                    shift: 0x00_U256,
169                    expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
170                },
171                TestCase {
172                    value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
173                    shift: 0x01_U256,
174                    expected: 0x0000000000000000000000000000000000000000000000000000000000000002_U256,
175                },
176                TestCase {
177                    value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
178                    shift: 0xff_U256,
179                    expected: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
180                },
181                TestCase {
182                    value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
183                    shift: 0x0100_U256,
184                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
185                },
186                TestCase {
187                    value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
188                    shift: 0x0101_U256,
189                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
190                },
191                TestCase {
192                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
193                    shift: 0x00_U256,
194                    expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
195                },
196                TestCase {
197                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
198                    shift: 0x01_U256,
199                    expected: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe_U256,
200                },
201                TestCase {
202                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
203                    shift: 0xff_U256,
204                    expected: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
205                },
206                TestCase {
207                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
208                    shift: 0x0100_U256,
209                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
210                },
211                TestCase {
212                    value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
213                    shift: 0x01_U256,
214                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
215                },
216                TestCase {
217                    value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
218                    shift: 0x01_U256,
219                    expected: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe_U256,
220                },
221            ];
222        }
223
224        for test in test_cases {
225            push!(interpreter, test.value);
226            push!(interpreter, test.shift);
227            let context = InstructionContext {
228                host: &mut DummyHost::default(),
229                interpreter: &mut interpreter,
230            };
231            shl(context);
232            let res = interpreter.stack.pop().unwrap();
233            assert_eq!(res, test.expected);
234        }
235    }
236
237    #[test]
238    fn test_logical_shift_right() {
239        let mut interpreter = Interpreter::default();
240
241        struct TestCase {
242            value: U256,
243            shift: U256,
244            expected: U256,
245        }
246
247        uint! {
248            let test_cases = [
249                TestCase {
250                    value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
251                    shift: 0x00_U256,
252                    expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
253                },
254                TestCase {
255                    value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
256                    shift: 0x01_U256,
257                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
258                },
259                TestCase {
260                    value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
261                    shift: 0x01_U256,
262                    expected: 0x4000000000000000000000000000000000000000000000000000000000000000_U256,
263                },
264                TestCase {
265                    value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
266                    shift: 0xff_U256,
267                    expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
268                },
269                TestCase {
270                    value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
271                    shift: 0x0100_U256,
272                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
273                },
274                TestCase {
275                    value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
276                    shift: 0x0101_U256,
277                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
278                },
279                TestCase {
280                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
281                    shift: 0x00_U256,
282                    expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
283                },
284                TestCase {
285                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
286                    shift: 0x01_U256,
287                    expected: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
288                },
289                TestCase {
290                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
291                    shift: 0xff_U256,
292                    expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
293                },
294                TestCase {
295                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
296                    shift: 0x0100_U256,
297                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
298                },
299                TestCase {
300                    value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
301                    shift: 0x01_U256,
302                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
303                },
304            ];
305        }
306
307        for test in test_cases {
308            push!(interpreter, test.value);
309            push!(interpreter, test.shift);
310            let context = InstructionContext {
311                host: &mut DummyHost::default(),
312                interpreter: &mut interpreter,
313            };
314            shr(context);
315            let res = interpreter.stack.pop().unwrap();
316            assert_eq!(res, test.expected);
317        }
318    }
319
320    #[test]
321    fn test_arithmetic_shift_right() {
322        let mut interpreter = Interpreter::default();
323
324        struct TestCase {
325            value: U256,
326            shift: U256,
327            expected: U256,
328        }
329
330        uint! {
331        let test_cases = [
332            TestCase {
333                value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
334                shift: 0x00_U256,
335                expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
336            },
337            TestCase {
338                value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
339                shift: 0x01_U256,
340                expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
341            },
342            TestCase {
343                value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
344                shift: 0x01_U256,
345                expected: 0xc000000000000000000000000000000000000000000000000000000000000000_U256,
346            },
347            TestCase {
348                value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
349                shift: 0xff_U256,
350                expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
351            },
352            TestCase {
353                value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
354                shift: 0x0100_U256,
355                expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
356            },
357            TestCase {
358                value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
359                shift: 0x0101_U256,
360                expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
361            },
362            TestCase {
363                value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
364                shift: 0x00_U256,
365                expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
366            },
367            TestCase {
368                value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
369                shift: 0x01_U256,
370                expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
371            },
372            TestCase {
373                value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
374                shift: 0xff_U256,
375                expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
376            },
377            TestCase {
378                value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
379                shift: 0x0100_U256,
380                expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
381            },
382            TestCase {
383                value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
384                shift: 0x01_U256,
385                expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
386            },
387            TestCase {
388                value: 0x4000000000000000000000000000000000000000000000000000000000000000_U256,
389                shift: 0xfe_U256,
390                expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
391            },
392            TestCase {
393                value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
394                shift: 0xf8_U256,
395                expected: 0x000000000000000000000000000000000000000000000000000000000000007f_U256,
396            },
397            TestCase {
398                value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
399                shift: 0xfe_U256,
400                expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
401            },
402            TestCase {
403                value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
404                shift: 0xff_U256,
405                expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
406            },
407            TestCase {
408                value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
409                shift: 0x0100_U256,
410                expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
411            },
412        ];
413            }
414
415        for test in test_cases {
416            push!(interpreter, test.value);
417            push!(interpreter, test.shift);
418            let context = InstructionContext {
419                host: &mut DummyHost::default(),
420                interpreter: &mut interpreter,
421            };
422            sar(context);
423            let res = interpreter.stack.pop().unwrap();
424            assert_eq!(res, test.expected);
425        }
426    }
427
428    #[test]
429    fn test_byte() {
430        struct TestCase {
431            input: U256,
432            index: usize,
433            expected: U256,
434        }
435
436        let mut interpreter = Interpreter::default();
437
438        let input_value = U256::from(0x1234567890abcdef1234567890abcdef_u128);
439        let test_cases = (0..32)
440            .map(|i| {
441                let byte_pos = 31 - i;
442
443                let shift_amount = U256::from(byte_pos * 8);
444                let byte_value = (input_value >> shift_amount) & U256::from(0xFF);
445                TestCase {
446                    input: input_value,
447                    index: i,
448                    expected: byte_value,
449                }
450            })
451            .collect::<Vec<_>>();
452
453        for test in test_cases.iter() {
454            push!(interpreter, test.input);
455            push!(interpreter, U256::from(test.index));
456            let context = InstructionContext {
457                host: &mut DummyHost::default(),
458                interpreter: &mut interpreter,
459            };
460            byte(context);
461            let res = interpreter.stack.pop().unwrap();
462            assert_eq!(res, test.expected, "Failed at index: {}", test.index);
463        }
464    }
465
466    #[test]
467    fn test_clz() {
468        let mut interpreter = Interpreter::default();
469        interpreter.runtime_flag.spec_id = SpecId::OSAKA;
470        let mut host = DummyHost::new(SpecId::OSAKA);
471
472        struct TestCase {
473            value: U256,
474            expected: U256,
475        }
476
477        uint! {
478            let test_cases = [
479                TestCase { value: 0x0_U256, expected: 256_U256 },
480                TestCase { value: 0x1_U256, expected: 255_U256 },
481                TestCase { value: 0x2_U256, expected: 254_U256 },
482                TestCase { value: 0x3_U256, expected: 254_U256 },
483                TestCase { value: 0x4_U256, expected: 253_U256 },
484                TestCase { value: 0x7_U256, expected: 253_U256 },
485                TestCase { value: 0x8_U256, expected: 252_U256 },
486                TestCase { value: 0xff_U256, expected: 248_U256 },
487                TestCase { value: 0x100_U256, expected: 247_U256 },
488                TestCase { value: 0xffff_U256, expected: 240_U256 },
489                TestCase {
490                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, // U256::MAX
491                    expected: 0_U256,
492                },
493                TestCase {
494                    value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, // 1 << 255
495                    expected: 0_U256,
496                },
497                TestCase { // Smallest value with 1 leading zero
498                    value: 0x4000000000000000000000000000000000000000000000000000000000000000_U256, // 1 << 254
499                    expected: 1_U256,
500                },
501                TestCase { // Value just below 1 << 255
502                    value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
503                    expected: 1_U256,
504                },
505            ];
506        }
507
508        for test in test_cases {
509            push!(interpreter, test.value);
510            let context = InstructionContext {
511                host: &mut host,
512                interpreter: &mut interpreter,
513            };
514            clz(context);
515            let res = interpreter.stack.pop().unwrap();
516            assert_eq!(
517                res, test.expected,
518                "CLZ for value {:#x} failed. Expected: {}, Got: {}",
519                test.value, test.expected, res
520            );
521        }
522    }
523}