evm_interpreter/
utils.rs

1//! Small utilities.
2
3use core::{
4	cmp::Ordering,
5	ops::{Div, Rem},
6};
7
8use crate::error::{ExitError, ExitFatal};
9#[allow(unused_imports)]
10use crate::uint::{H160, H256, U256, U256Ext};
11
12/// Convert [U256] into [H256].
13#[must_use]
14pub fn u256_to_h256(v: U256) -> H256 {
15	v.to_h256()
16}
17
18/// Convert [H256] to [U256].
19#[must_use]
20pub fn h256_to_u256(v: H256) -> U256 {
21	U256::from_h256(v)
22}
23
24/// Convert [U256] into [H160]
25#[must_use]
26pub fn u256_to_h160(v: U256) -> H160 {
27	v.to_h160()
28}
29
30/// Convert [U256] to [usize].
31pub fn u256_to_usize(v: U256) -> Result<usize, ExitError> {
32	if v > U256::USIZE_MAX {
33		return Err(ExitFatal::NotSupported.into());
34	}
35	Ok(v.low_usize())
36}
37
38/// Sign of [I256].
39#[derive(Copy, Clone, Eq, PartialEq, Debug)]
40pub enum Sign {
41	/// Plus
42	Plus,
43	/// Minus
44	Minus,
45	/// Zero
46	Zero,
47}
48
49/// Signed 256-bit integer.
50#[derive(Copy, Clone, Eq, PartialEq, Debug)]
51pub struct I256(pub Sign, pub U256);
52
53impl I256 {
54	/// Zero value of I256.
55	#[must_use]
56	pub const fn zero() -> I256 {
57		I256(Sign::Zero, U256::ZERO)
58	}
59	/// Minimum value of I256.
60	#[must_use]
61	pub fn min_value() -> I256 {
62		I256(
63			Sign::Minus,
64			(U256::MAX & U256::SIGN_BIT_MASK) + U256::from(1u64),
65		)
66	}
67}
68
69impl Ord for I256 {
70	fn cmp(&self, other: &I256) -> Ordering {
71		match (self.0, other.0) {
72			(Sign::Zero, Sign::Zero) => Ordering::Equal,
73			(Sign::Zero, Sign::Plus) => Ordering::Less,
74			(Sign::Zero, Sign::Minus) => Ordering::Greater,
75			(Sign::Minus, Sign::Zero) => Ordering::Less,
76			(Sign::Minus, Sign::Plus) => Ordering::Less,
77			(Sign::Minus, Sign::Minus) => self.1.cmp(&other.1).reverse(),
78			(Sign::Plus, Sign::Minus) => Ordering::Greater,
79			(Sign::Plus, Sign::Zero) => Ordering::Greater,
80			(Sign::Plus, Sign::Plus) => self.1.cmp(&other.1),
81		}
82	}
83}
84
85impl PartialOrd for I256 {
86	fn partial_cmp(&self, other: &I256) -> Option<Ordering> {
87		Some(self.cmp(other))
88	}
89}
90
91impl Default for I256 {
92	fn default() -> I256 {
93		I256::zero()
94	}
95}
96
97impl From<U256> for I256 {
98	fn from(val: U256) -> I256 {
99		if val == U256::ZERO {
100			I256::zero()
101		} else if val & U256::SIGN_BIT_MASK == val {
102			I256(Sign::Plus, val)
103		} else {
104			I256(Sign::Minus, !val + U256::from(1u64))
105		}
106	}
107}
108
109impl From<I256> for U256 {
110	fn from(value: I256) -> U256 {
111		let sign = value.0;
112		if sign == Sign::Zero {
113			U256::ZERO
114		} else if sign == Sign::Plus {
115			value.1
116		} else {
117			!value.1 + U256::from(1u64)
118		}
119	}
120}
121
122impl Div for I256 {
123	type Output = I256;
124
125	fn div(self, other: I256) -> I256 {
126		if other == I256::zero() {
127			return I256::zero();
128		}
129
130		if self == I256::min_value() && other.1 == U256::from(1u64) {
131			return I256::min_value();
132		}
133
134		let d = (self.1 / other.1) & U256::SIGN_BIT_MASK;
135
136		if d == U256::ZERO {
137			return I256::zero();
138		}
139
140		match (self.0, other.0) {
141			(Sign::Zero, Sign::Plus)
142			| (Sign::Plus, Sign::Zero)
143			| (Sign::Zero, Sign::Zero)
144			| (Sign::Plus, Sign::Plus)
145			| (Sign::Minus, Sign::Minus) => I256(Sign::Plus, d),
146			(Sign::Zero, Sign::Minus)
147			| (Sign::Plus, Sign::Minus)
148			| (Sign::Minus, Sign::Zero)
149			| (Sign::Minus, Sign::Plus) => I256(Sign::Minus, d),
150		}
151	}
152}
153
154impl Rem for I256 {
155	type Output = I256;
156
157	fn rem(self, other: I256) -> I256 {
158		let r = (self.1 % other.1) & U256::SIGN_BIT_MASK;
159
160		if r == U256::ZERO {
161			return I256::zero();
162		}
163
164		I256(self.0, r)
165	}
166}
167
168#[cfg(test)]
169mod tests {
170	use std::num::Wrapping;
171
172	use super::*;
173
174	#[test]
175	fn div_i256() {
176		// Sanity checks based on i8. Notice that we need to use `Wrapping` here because
177		// Rust will prevent the overflow by default whereas the EVM does not.
178		assert_eq!(Wrapping(i8::MIN) / Wrapping(-1), Wrapping(i8::MIN));
179
180		assert_eq!(100i8 / -1, -100i8);
181		assert_eq!(100i8 / 2, 50i8);
182
183		// Now the same calculations based on i256
184		let one = I256(Sign::Zero, U256::from_usize(1));
185		let one_hundred = I256(Sign::Zero, U256::from_usize(100));
186		let fifty = I256(Sign::Plus, U256::from_usize(50));
187		let two = I256(Sign::Zero, U256::from_usize(2));
188		let neg_one_hundred = I256(Sign::Minus, U256::from_usize(100));
189		let minus_one = I256(Sign::Minus, U256::from_usize(1));
190		let max_value = I256(
191			Sign::Plus,
192			U256::from_usize(2).pow(U256::from_usize(255)) - U256::ONE,
193		);
194		let neg_max_value = I256(
195			Sign::Minus,
196			U256::from_usize(2).pow(U256::from_usize(255)) - U256::ONE,
197		);
198
199		assert_eq!(I256::min_value() / minus_one, I256::min_value());
200		assert_eq!(I256::min_value() / one, I256::min_value());
201		assert_eq!(max_value / one, max_value);
202		assert_eq!(max_value / minus_one, neg_max_value);
203
204		assert_eq!(one_hundred / minus_one, neg_one_hundred);
205		assert_eq!(one_hundred / two, fifty);
206	}
207}