1use super::ExecutionResult;
2use super::OpcodeHandler;
3use crate::context::Context;
4use crate::error::ExecError;
5use crate::error::RevertError;
6use crate::machine::CallInfo;
7use crate::machine::Machine;
8use crate::machine::Word;
9
10pub enum OpcodeBinaryOp {
11 Add,
12 Mul,
13 Sub,
14 Div,
15 Sdiv,
16 Mod,
17 Smod,
18 Exp,
19 Shl,
20 Shr,
21 Sar,
22 And,
23 Or,
24 Xor,
25 Byte,
26 Lt,
27 Gt,
28 Slt,
29 Sgt,
30 Eq,
31 SignExtend,
32}
33
34pub enum OpcodeUnaryOp {
35 IsZero,
36 Not,
37}
38
39pub enum OpcodeModularOp {
40 AddMod,
41 MulMod,
42}
43
44impl<W: Word, C: Context<W>> OpcodeHandler<W, C> for OpcodeModularOp {
45 fn call(
46 &self,
47 _ctx: &mut C,
48 machine: &mut Machine<W>,
49 _call_info: &CallInfo<W>,
50 ) -> Result<Option<ExecutionResult>, ExecError> {
51 let a = machine.pop_stack()?;
52 let b = machine.pop_stack()?;
53 let n = machine.pop_stack()?;
54 machine.stack.push(match self {
55 Self::AddMod => a.addmod(b, n),
56 Self::MulMod => a.mulmod(b, n),
57 });
58 machine.pc += 1;
59 Ok(None)
60 }
61}
62
63impl<W: Word, C: Context<W>> OpcodeHandler<W, C> for OpcodeUnaryOp {
64 fn call(
65 &self,
66 _ctx: &mut C,
67 machine: &mut Machine<W>,
68 _call_info: &CallInfo<W>,
69 ) -> Result<Option<ExecutionResult>, ExecError> {
70 let a = machine.pop_stack()?;
71 machine.stack.push(match self {
72 Self::IsZero => W::from_u64((a == W::ZERO) as u64),
73 Self::Not => a.not(),
74 });
75 machine.pc += 1;
76 Ok(None)
77 }
78}
79
80impl<W: Word, C: Context<W>> OpcodeHandler<W, C> for OpcodeBinaryOp {
81 fn call(
82 &self,
83 _ctx: &mut C,
84 machine: &mut Machine<W>,
85 _call_info: &CallInfo<W>,
86 ) -> Result<Option<ExecutionResult>, ExecError> {
87 let a = machine.pop_stack()?;
88 let b = machine.pop_stack()?;
89 machine.stack.push(match self {
90 Self::Add => a.add(b),
91 Self::Mul => a.mul(b),
92 Self::Sub => a.sub(b),
93 Self::Div => {
94 if b == W::ZERO {
95 W::ZERO
96 } else {
97 a.div(b)
98 }
99 }
100 Self::Sdiv => match (a.is_neg(), b.is_neg()) {
101 (false, false) => a.div(b),
102 (true, true) => a.neg().div(b.neg()),
103 (false, true) => if a.rem(b.neg()) == W::ZERO {
104 a.div(b.neg())
105 } else {
106 a.div(b.neg()).add(W::ONE)
107 }
108 .neg(),
109 (true, false) => if a.neg().rem(b) == W::ZERO {
110 a.neg().div(b)
111 } else {
112 a.neg().div(b).add(W::ONE)
113 }
114 .neg(),
115 },
116 Self::Mod => a.rem(b),
117 Self::Smod => match (a.is_neg(), b.is_neg()) {
118 (false, false) => a.rem(b),
119 (true, true) => a.neg().rem(b.neg()).neg(),
120 (false, true) => {
121 if a.rem(b.neg()) == W::ZERO {
122 W::ZERO
123 } else {
124 b.neg().sub(a.rem(b.neg())).neg()
125 }
126 }
127 (true, false) => {
128 if a.neg().rem(b) == W::ZERO {
129 W::ZERO
130 } else {
131 b.sub(a.neg().rem(b))
132 }
133 }
134 },
135 Self::Exp => a.pow(b),
136 Self::Shl => b.shl(a),
137 Self::Shr => b.shr(a),
138 Self::And => a.and(b),
139 Self::Or => a.or(b),
140 Self::Xor => a.xor(b),
141 Self::Lt => W::from_u64((a < b) as u64),
142 Self::Gt => W::from_u64((a > b) as u64),
143 Self::Slt => W::from_u64(match (a.is_neg(), b.is_neg()) {
144 (false, false) => a.lt(b),
145 (false, true) => false,
146 (true, false) => true,
147 (true, true) => a.neg().gt(b.neg()),
148 } as u64),
149 Self::Sgt => W::from_u64(match (a.is_neg(), b.is_neg()) {
150 (false, false) => a.gt(b),
151 (false, true) => true,
152 (true, false) => false,
153 (true, true) => a.neg().lt(b.neg()),
154 } as u64),
155 Self::Eq => W::from_u64((a == b) as u64),
156 Self::Byte => {
157 let i = a.to_usize()?;
158 let x = b.to_big_endian();
159 W::from_u64(if i < 32 { x[i] as u64 } else { 0 })
160 }
161 Self::Sar => {
162 let mut result = b.shr(a);
163 if b.is_neg() {
164 let addition = W::MAX.shl(W::from_u64(256).sub(a));
165 result = result.add(addition);
166 }
167 result
168 }
169 Self::SignExtend => {
170 let bytes_1 = a.to_usize()?;
171 if bytes_1 > 31 {
172 return Err(ExecError::Revert(RevertError::OutOfBounds));
173 }
174 let bytes = bytes_1 + 1;
175 let is_neg = b.bit(bytes_1 * 8 + 7);
176 let x = b
177 .shl(W::from_u64((256 - bytes * 8) as u64))
178 .shr(W::from_u64((256 - bytes * 8) as u64));
179 if is_neg {
180 x.add(W::MAX.shl(W::from_u64(((bytes_1 + 1) * 8) as u64)))
181 } else {
182 x
183 }
184 }
185 });
186 machine.pc += 1;
187 Ok(None)
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use crate::u256::U256;
194
195 use super::super::tests::test;
196 use super::*;
197
198 #[test]
199 fn test_opcode_sar() {
200 test(
201 OpcodeBinaryOp::Sar,
202 &[
203 (&[], None),
204 (&[U256::from(123)], None),
205 (&[U256::from(0), U256::from(123)], Some(&[U256::from(123)])),
206 (&[U256::from(1), U256::from(123)], Some(&[U256::from(61)])),
207 (&[U256::from(2), U256::from(123)], Some(&[U256::from(30)])),
208 (&[U256::from(3), U256::from(123)], Some(&[U256::from(15)])),
209 (&[U256::from(100), U256::from(123)], Some(&[U256::from(0)])),
210 (&[U256::from(1), -U256::from(123)], Some(&[-U256::from(62)])),
211 (&[U256::from(2), -U256::from(123)], Some(&[-U256::from(31)])),
212 (&[U256::from(3), -U256::from(123)], Some(&[-U256::from(16)])),
213 (
214 &[U256::from(100), -U256::from(123)],
215 Some(&[-U256::from(1)]),
216 ),
217 (
218 &[U256::from(128), U256::MAX >> U256::ONE],
219 Some(&[U256::MAX >> U256::from(129)]),
220 ),
221 (&[U256::from(128), U256::MAX], Some(&[U256::MAX])),
222 ],
223 );
224 }
225
226 #[test]
227 fn test_opcode_lt() {
228 test(
229 OpcodeBinaryOp::Lt,
230 &[
231 (&[], None),
232 (&[U256::from(123)], None),
233 (&[U256::from(123), U256::from(120)], Some(&[U256::ZERO])),
234 (&[U256::from(123), U256::from(123)], Some(&[U256::ZERO])),
235 (&[U256::from(123), U256::from(234)], Some(&[U256::ONE])),
236 (
237 &[U256::MAX, U256::MAX - U256::from(123)],
238 Some(&[U256::ZERO]),
239 ),
240 (&[U256::MAX, U256::MAX], Some(&[U256::ZERO])),
241 (
242 &[U256::MAX - U256::from(123), U256::MAX],
243 Some(&[U256::ONE]),
244 ),
245 ],
246 );
247 }
248
249 #[test]
250 fn test_opcode_gt() {
251 test(
252 OpcodeBinaryOp::Gt,
253 &[
254 (&[], None),
255 (&[U256::from(123)], None),
256 (&[U256::from(123), U256::from(120)], Some(&[U256::ONE])),
257 (&[U256::from(123), U256::from(123)], Some(&[U256::ZERO])),
258 (&[U256::from(123), U256::from(234)], Some(&[U256::ZERO])),
259 (
260 &[U256::MAX, U256::MAX - U256::from(123)],
261 Some(&[U256::ONE]),
262 ),
263 (&[U256::MAX, U256::MAX], Some(&[U256::ZERO])),
264 (
265 &[U256::MAX - U256::from(123), U256::MAX],
266 Some(&[U256::ZERO]),
267 ),
268 ],
269 );
270 }
271
272 #[test]
273 fn test_opcode_slt() {
274 test(
275 OpcodeBinaryOp::Slt,
276 &[
277 (&[], None),
278 (&[U256::from(123)], None),
279 (&[U256::from(123), U256::from(120)], Some(&[U256::ZERO])),
280 (&[U256::from(123), U256::from(123)], Some(&[U256::ZERO])),
281 (&[U256::from(123), U256::from(234)], Some(&[U256::ONE])),
282 (&[-U256::from(123), U256::from(123)], Some(&[U256::ONE])),
283 (&[U256::from(123), -U256::from(123)], Some(&[U256::ZERO])),
284 (&[-U256::from(123), -U256::from(123)], Some(&[U256::ZERO])),
285 (&[-U256::from(123), -U256::from(234)], Some(&[U256::ZERO])),
286 (&[-U256::from(234), -U256::from(123)], Some(&[U256::ONE])),
287 ],
288 );
289 }
290
291 #[test]
292 fn test_opcode_sgt() {
293 test(
294 OpcodeBinaryOp::Sgt,
295 &[
296 (&[], None),
297 (&[U256::from(123)], None),
298 (&[U256::from(123), U256::from(120)], Some(&[U256::ONE])),
299 (&[U256::from(123), U256::from(123)], Some(&[U256::ZERO])),
300 (&[U256::from(123), U256::from(234)], Some(&[U256::ZERO])),
301 (&[-U256::from(123), U256::from(123)], Some(&[U256::ZERO])),
302 (&[U256::from(123), -U256::from(123)], Some(&[U256::ONE])),
303 (&[-U256::from(123), -U256::from(123)], Some(&[U256::ZERO])),
304 (&[-U256::from(123), -U256::from(234)], Some(&[U256::ONE])),
305 (&[-U256::from(234), -U256::from(123)], Some(&[U256::ZERO])),
306 ],
307 );
308 }
309
310 #[test]
311 fn test_opcode_eq() {
312 test(
313 OpcodeBinaryOp::Eq,
314 &[
315 (&[], None),
316 (&[U256::from(123)], None),
317 (&[U256::from(0), U256::from(0)], Some(&[U256::ONE])),
318 (&[U256::from(123), U256::from(123)], Some(&[U256::ONE])),
319 (&[U256::from(123), U256::from(122)], Some(&[U256::ZERO])),
320 (&[U256::MAX, U256::MAX], Some(&[U256::ONE])),
321 (&[U256::MAX, U256::MAX - U256::ONE], Some(&[U256::ZERO])),
322 ],
323 );
324 }
325
326 #[test]
327 fn test_opcode_is_zero() {
328 test(
329 OpcodeUnaryOp::IsZero,
330 &[
331 (&[], None),
332 (&[U256::from(0)], Some(&[U256::ONE])),
333 (&[U256::from(123)], Some(&[U256::ZERO])),
334 (&[U256::MAX], Some(&[U256::ZERO])),
335 (&[U256::MAX - U256::ONE], Some(&[U256::ZERO])),
336 ],
337 );
338 }
339
340 #[test]
341 fn test_opcode_sdiv() {
342 test(
343 OpcodeBinaryOp::Sdiv,
344 &[
345 (&[U256::from(11), U256::from(2)], Some(&[U256::from(5)])),
346 (&[-U256::from(11), -U256::from(2)], Some(&[U256::from(5)])),
347 (&[-U256::from(11), U256::from(2)], Some(&[-U256::from(6)])),
348 (&[U256::from(11), -U256::from(2)], Some(&[-U256::from(6)])),
349 (&[U256::from(10), U256::from(2)], Some(&[U256::from(5)])),
350 (&[-U256::from(10), -U256::from(2)], Some(&[U256::from(5)])),
351 (&[U256::from(10), -U256::from(2)], Some(&[-U256::from(5)])),
352 (&[-U256::from(10), U256::from(2)], Some(&[-U256::from(5)])),
353 ],
354 );
355 }
356 #[test]
357 fn test_opcode_smod() {
358 test(
359 OpcodeBinaryOp::Smod,
360 &[
361 (&[U256::from(11), U256::from(3)], Some(&[U256::from(2)])),
362 (&[-U256::from(11), -U256::from(3)], Some(&[-U256::from(2)])),
363 (&[-U256::from(11), U256::from(3)], Some(&[U256::from(1)])),
364 (&[U256::from(11), -U256::from(3)], Some(&[-U256::from(1)])),
365 (&[U256::from(10), U256::from(3)], Some(&[U256::from(1)])),
366 (&[-U256::from(10), -U256::from(3)], Some(&[-U256::from(1)])),
367 (&[-U256::from(10), U256::from(3)], Some(&[U256::from(2)])),
368 (&[U256::from(10), -U256::from(3)], Some(&[-U256::from(2)])),
369 (&[U256::from(123), U256::from(100)], Some(&[U256::from(23)])),
370 (
371 &[-U256::from(123), -U256::from(100)],
372 Some(&[-U256::from(23)]),
373 ),
374 (
375 &[-U256::from(123), U256::from(100)],
376 Some(&[U256::from(77)]),
377 ),
378 (
379 &[U256::from(123), -U256::from(100)],
380 Some(&[-U256::from(77)]),
381 ),
382 ],
383 );
384 }
385 #[test]
386 fn test_sign_extend() {
387 test(
388 OpcodeBinaryOp::SignExtend,
389 &[
390 (&[U256::from(0), U256::from(0xff)], Some(&[U256::MAX])),
391 (
392 &[U256::from(0), U256::from(0x7f)],
393 Some(&[U256::from(0x7f)]),
394 ),
395 (&[U256::from(0), -U256::from(1)], Some(&[-U256::from(1)])),
396 (
397 &[U256::from(1), U256::from(0x1234)],
398 Some(&[U256::from(0x1234)]),
399 ),
400 (
401 &[U256::from(1), U256::from(0x8234)],
402 Some(&[-U256::from(32204)]),
403 ),
404 (
405 &[U256::from(2), U256::from(0x8234)],
406 Some(&[U256::from(0x8234)]),
407 ),
408 (
409 &[U256::from(31), U256::from(0x8234)],
410 Some(&[U256::from(0x8234)]),
411 ),
412 (&[U256::from(32), U256::from(0x8234)], None),
413 (&[U256::MAX, U256::from(0x8234)], None),
414 (&[U256::from(31), U256::MAX], Some(&[U256::MAX])),
415 ],
416 );
417 }
418}