referrerpolicy=no-referrer-when-downgrade

pallet_revive/vm/evm/instructions/
arithmetic.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use super::{
19	i256::{i256_div, i256_mod},
20	Context,
21};
22use crate::vm::Ext;
23use revm::{
24	interpreter::{
25		gas as revm_gas,
26		interpreter_types::{RuntimeFlag, StackTr},
27	},
28	primitives::U256,
29};
30
31/// Implements the ADD instruction - adds two values from stack.
32pub fn add<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
33	gas_legacy!(context.interpreter, revm_gas::VERYLOW);
34	popn_top!([op1], op2, context.interpreter);
35	*op2 = op1.wrapping_add(*op2);
36}
37
38/// Implements the MUL instruction - multiplies two values from stack.
39pub fn mul<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
40	gas_legacy!(context.interpreter, revm_gas::LOW);
41	popn_top!([op1], op2, context.interpreter);
42	*op2 = op1.wrapping_mul(*op2);
43}
44
45/// Implements the SUB instruction - subtracts two values from stack.
46pub fn sub<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
47	gas_legacy!(context.interpreter, revm_gas::VERYLOW);
48	popn_top!([op1], op2, context.interpreter);
49	*op2 = op1.wrapping_sub(*op2);
50}
51
52/// Implements the DIV instruction - divides two values from stack.
53pub fn div<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
54	gas_legacy!(context.interpreter, revm_gas::LOW);
55	popn_top!([op1], op2, context.interpreter);
56	if !op2.is_zero() {
57		*op2 = op1.wrapping_div(*op2);
58	}
59}
60
61/// Implements the SDIV instruction.
62///
63/// Performs signed division of two values from stack.
64pub fn sdiv<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
65	gas_legacy!(context.interpreter, revm_gas::LOW);
66	popn_top!([op1], op2, context.interpreter);
67	*op2 = i256_div(op1, *op2);
68}
69
70/// Implements the MOD instruction.
71///
72/// Pops two values from stack and pushes the remainder of their division.
73pub fn rem<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
74	gas_legacy!(context.interpreter, revm_gas::LOW);
75	popn_top!([op1], op2, context.interpreter);
76	if !op2.is_zero() {
77		*op2 = op1.wrapping_rem(*op2);
78	}
79}
80
81/// Implements the SMOD instruction.
82///
83/// Performs signed modulo of two values from stack.
84pub fn smod<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
85	gas_legacy!(context.interpreter, revm_gas::LOW);
86	popn_top!([op1], op2, context.interpreter);
87	*op2 = i256_mod(op1, *op2)
88}
89
90/// Implements the ADDMOD instruction.
91///
92/// Pops three values from stack and pushes (a + b) % n.
93pub fn addmod<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
94	gas_legacy!(context.interpreter, revm_gas::MID);
95	popn_top!([op1, op2], op3, context.interpreter);
96	*op3 = op1.add_mod(op2, *op3)
97}
98
99/// Implements the MULMOD instruction.
100///
101/// Pops three values from stack and pushes (a * b) % n.
102pub fn mulmod<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
103	gas_legacy!(context.interpreter, revm_gas::MID);
104	popn_top!([op1, op2], op3, context.interpreter);
105	*op3 = op1.mul_mod(op2, *op3)
106}
107
108/// Implements the EXP instruction - exponentiates two values from stack.
109pub fn exp<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
110	let spec_id = context.interpreter.runtime_flag.spec_id();
111	popn_top!([op1], op2, context.interpreter);
112	gas_or_fail_legacy!(context.interpreter, revm_gas::exp_cost(spec_id, *op2));
113	*op2 = op1.pow(*op2);
114}
115
116/// Implements the `SIGNEXTEND` opcode as defined in the Ethereum Yellow Paper.
117///
118/// In the yellow paper `SIGNEXTEND` is defined to take two inputs, we will call them
119/// `x` and `y`, and produce one output.
120///
121/// The first `t` bits of the output (numbering from the left, starting from 0) are
122/// equal to the `t`-th bit of `y`, where `t` is equal to `256 - 8(x + 1)`.
123///
124/// The remaining bits of the output are equal to the corresponding bits of `y`.
125///
126/// **Note**: If `x >= 32` then the output is equal to `y` since `t <= 0`.
127///
128/// To efficiently implement this algorithm in the case `x < 32` we do the following.
129///
130/// Let `b` be equal to the `t`-th bit of `y` and let `s = 255 - t = 8x + 7`
131/// (this is effectively the same index as `t`, but numbering the bits from the
132/// right instead of the left).
133///
134/// We can create a bit mask which is all zeros up to and including the `t`-th bit,
135/// and all ones afterwards by computing the quantity `2^s - 1`.
136///
137/// We can use this mask to compute the output depending on the value of `b`.
138///
139/// If `b == 1` then the yellow paper says the output should be all ones up to
140/// and including the `t`-th bit, followed by the remaining bits of `y`; this is equal to
141/// `y | !mask` where `|` is the bitwise `OR` and `!` is bitwise negation.
142///
143/// Similarly, if `b == 0` then the yellow paper says the output should start with all zeros,
144/// then end with bits from `b`; this is equal to `y & mask` where `&` is bitwise `AND`.
145pub fn signextend<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
146	gas_legacy!(context.interpreter, revm_gas::LOW);
147	popn_top!([ext], x, context.interpreter);
148	// For 31 we also don't need to do anything.
149	if ext < U256::from(31) {
150		let ext = ext.as_limbs()[0];
151		let bit_index = (8 * ext + 7) as usize;
152		let bit = x.bit(bit_index);
153		let mask = (U256::from(1) << bit_index) - U256::from(1);
154		*x = if bit { *x | !mask } else { *x & mask };
155	}
156}