Skip to main content

revm_interpreter/instructions/
arithmetic.rs

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