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