revm_interpreter/instructions/
arithmetic.rs

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