Skip to main content

revm_interpreter/instructions/
bitwise.rs

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