revm_interpreter/instructions/
arithmetic.rs

1use super::i256::{i256_div, i256_mod};
2use crate::{
3    gas,
4    primitives::{Spec, U256},
5    Host, Interpreter,
6};
7
8pub fn add<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
9    gas!(interpreter, gas::VERYLOW);
10    pop_top!(interpreter, op1, op2);
11    *op2 = op1.wrapping_add(*op2);
12}
13
14pub fn mul<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
15    gas!(interpreter, gas::LOW);
16    pop_top!(interpreter, op1, op2);
17    *op2 = op1.wrapping_mul(*op2);
18}
19
20pub fn sub<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
21    gas!(interpreter, gas::VERYLOW);
22    pop_top!(interpreter, op1, op2);
23    *op2 = op1.wrapping_sub(*op2);
24}
25
26pub fn div<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
27    gas!(interpreter, gas::LOW);
28    pop_top!(interpreter, op1, op2);
29    if !op2.is_zero() {
30        *op2 = op1.wrapping_div(*op2);
31    }
32}
33
34pub fn sdiv<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
35    gas!(interpreter, gas::LOW);
36    pop_top!(interpreter, op1, op2);
37    *op2 = i256_div(op1, *op2);
38}
39
40pub fn rem<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
41    gas!(interpreter, gas::LOW);
42    pop_top!(interpreter, op1, op2);
43    if !op2.is_zero() {
44        *op2 = op1.wrapping_rem(*op2);
45    }
46}
47
48pub fn smod<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
49    gas!(interpreter, gas::LOW);
50    pop_top!(interpreter, op1, op2);
51    *op2 = i256_mod(op1, *op2)
52}
53
54pub fn addmod<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
55    gas!(interpreter, gas::MID);
56    pop_top!(interpreter, op1, op2, op3);
57    *op3 = op1.add_mod(op2, *op3)
58}
59
60pub fn mulmod<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
61    gas!(interpreter, gas::MID);
62    pop_top!(interpreter, op1, op2, op3);
63    *op3 = op1.mul_mod(op2, *op3)
64}
65
66pub fn exp<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H) {
67    pop_top!(interpreter, op1, op2);
68    gas_or_fail!(interpreter, gas::exp_cost(SPEC::SPEC_ID, *op2));
69    *op2 = op1.pow(*op2);
70}
71
72/// Implements the `SIGNEXTEND` opcode as defined in the Ethereum Yellow Paper.
73///
74/// In the yellow paper `SIGNEXTEND` is defined to take two inputs, we will call them
75/// `x` and `y`, and produce one output. The first `t` bits of the output (numbering from the
76/// left, starting from 0) are equal to the `t`-th bit of `y`, where `t` is equal to
77/// `256 - 8(x + 1)`. The remaining bits of the output are equal to the corresponding bits of `y`.
78/// Note: if `x >= 32` then the output is equal to `y` since `t <= 0`. To efficiently implement
79/// this algorithm in the case `x < 32` we do the following. Let `b` be equal to the `t`-th bit
80/// of `y` and let `s = 255 - t = 8x + 7` (this is effectively the same index as `t`, but
81/// numbering the bits from the right instead of the left). We can create a bit mask which is all
82/// zeros up to and including the `t`-th bit, and all ones afterwards by computing the quantity
83/// `2^s - 1`. We can use this mask to compute the output depending on the value of `b`.
84/// If `b == 1` then the yellow paper says the output should be all ones up to
85/// and including the `t`-th bit, followed by the remaining bits of `y`; this is equal to
86/// `y | !mask` where `|` is the bitwise `OR` and `!` is bitwise negation. Similarly, if
87/// `b == 0` then the yellow paper says the output should start with all zeros, then end with
88/// bits from `b`; this is equal to `y & mask` where `&` is bitwise `AND`.
89pub fn signextend<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
90    gas!(interpreter, gas::LOW);
91    pop_top!(interpreter, ext, x);
92    // For 31 we also don't need to do anything.
93    if ext < U256::from(31) {
94        let ext = ext.as_limbs()[0];
95        let bit_index = (8 * ext + 7) as usize;
96        let bit = x.bit(bit_index);
97        let mask = (U256::from(1) << bit_index) - U256::from(1);
98        *x = if bit { *x | !mask } else { *x & mask };
99    }
100}