rtvm_interpreter/instructions/
bitwise.rs

1use super::i256::{i256_cmp, i256_sign_compl, two_compl, Sign};
2use crate::{
3    gas,
4    primitives::{Spec, U256},
5    Host, Interpreter,
6};
7use core::cmp::Ordering;
8use rtvm_primitives::uint;
9
10pub fn lt<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
11    gas!(interpreter, gas::VERYLOW);
12    pop_top!(interpreter, op1, op2);
13    *op2 = U256::from(op1 < *op2);
14}
15
16pub fn gt<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
17    gas!(interpreter, gas::VERYLOW);
18    pop_top!(interpreter, op1, op2);
19    *op2 = U256::from(op1 > *op2);
20}
21
22pub fn slt<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
23    gas!(interpreter, gas::VERYLOW);
24    pop_top!(interpreter, op1, op2);
25    *op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Less);
26}
27
28pub fn sgt<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
29    gas!(interpreter, gas::VERYLOW);
30    pop_top!(interpreter, op1, op2);
31    *op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Greater);
32}
33
34pub fn eq<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
35    gas!(interpreter, gas::VERYLOW);
36    pop_top!(interpreter, op1, op2);
37    *op2 = U256::from(op1 == *op2);
38}
39
40pub fn iszero<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
41    gas!(interpreter, gas::VERYLOW);
42    pop_top!(interpreter, op1);
43    *op1 = U256::from(*op1 == U256::ZERO);
44}
45
46pub fn bitand<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
47    gas!(interpreter, gas::VERYLOW);
48    pop_top!(interpreter, op1, op2);
49    *op2 = op1 & *op2;
50}
51
52pub fn bitor<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
53    gas!(interpreter, gas::VERYLOW);
54    pop_top!(interpreter, op1, op2);
55    *op2 = op1 | *op2;
56}
57
58pub fn bitxor<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
59    gas!(interpreter, gas::VERYLOW);
60    pop_top!(interpreter, op1, op2);
61    *op2 = op1 ^ *op2;
62}
63
64pub fn not<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
65    gas!(interpreter, gas::VERYLOW);
66    pop_top!(interpreter, op1);
67    *op1 = !*op1;
68}
69
70pub fn byte<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
71    gas!(interpreter, gas::VERYLOW);
72    pop_top!(interpreter, op1, op2);
73
74    let o1 = as_usize_saturated!(op1);
75    *op2 = if o1 < 32 {
76        // `31 - o1` because `byte` returns LE, while we want BE
77        U256::from(op2.byte(31 - o1))
78    } else {
79        U256::ZERO
80    };
81}
82
83/// EIP-145: Bitwise shifting instructions in EVM
84pub fn shl<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H) {
85    check!(interpreter, CONSTANTINOPLE);
86    gas!(interpreter, gas::VERYLOW);
87    pop_top!(interpreter, op1, op2);
88    *op2 <<= as_usize_saturated!(op1);
89}
90
91/// EIP-145: Bitwise shifting instructions in EVM
92pub fn shr<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H) {
93    check!(interpreter, CONSTANTINOPLE);
94    gas!(interpreter, gas::VERYLOW);
95    pop_top!(interpreter, op1, op2);
96    *op2 >>= as_usize_saturated!(op1);
97}
98
99/// EIP-145: Bitwise shifting instructions in EVM
100pub fn sar<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H) {
101    check!(interpreter, CONSTANTINOPLE);
102    gas!(interpreter, gas::VERYLOW);
103    pop_top!(interpreter, op1, op2);
104
105    let value_sign = i256_sign_compl(op2);
106
107    // If the shift count is 255+, we can short-circuit. This is because shifting by 255 bits is the
108    // maximum shift that still leaves 1 bit in the original 256-bit number. Shifting by 256 bits or
109    // more would mean that no original bits remain. The result depends on what the highest bit of
110    // the value is.
111    *op2 = if value_sign == Sign::Zero || op1 >= U256::from(255) {
112        match value_sign {
113            // value is 0 or >=1, pushing 0
114            Sign::Plus | Sign::Zero => U256::ZERO,
115            // value is <0, pushing -1
116            Sign::Minus => U256::MAX,
117        }
118    } else {
119        const ONE: U256 = uint!(1_U256);
120        // SAFETY: shift count is checked above; it's less than 255.
121        let shift = usize::try_from(op1).unwrap();
122        match value_sign {
123            Sign::Plus | Sign::Zero => op2.wrapping_shr(shift),
124            Sign::Minus => two_compl(op2.wrapping_sub(ONE).wrapping_shr(shift).wrapping_add(ONE)),
125        }
126    };
127}
128
129#[cfg(test)]
130mod tests {
131    use crate::instructions::bitwise::{sar, shl, shr};
132    use crate::{Contract, DummyHost, Interpreter};
133    use rtvm_primitives::{uint, Env, LatestSpec, U256};
134
135    #[test]
136    fn test_shift_left() {
137        let mut host = DummyHost::new(Env::default());
138        let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false);
139
140        struct TestCase {
141            value: U256,
142            shift: U256,
143            expected: U256,
144        }
145
146        uint! {
147            let test_cases = [
148                TestCase {
149                    value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
150                    shift: 0x00_U256,
151                    expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
152                },
153                TestCase {
154                    value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
155                    shift: 0x01_U256,
156                    expected: 0x0000000000000000000000000000000000000000000000000000000000000002_U256,
157                },
158                TestCase {
159                    value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
160                    shift: 0xff_U256,
161                    expected: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
162                },
163                TestCase {
164                    value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
165                    shift: 0x0100_U256,
166                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
167                },
168                TestCase {
169                    value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
170                    shift: 0x0101_U256,
171                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
172                },
173                TestCase {
174                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
175                    shift: 0x00_U256,
176                    expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
177                },
178                TestCase {
179                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
180                    shift: 0x01_U256,
181                    expected: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe_U256,
182                },
183                TestCase {
184                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
185                    shift: 0xff_U256,
186                    expected: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
187                },
188                TestCase {
189                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
190                    shift: 0x0100_U256,
191                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
192                },
193                TestCase {
194                    value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
195                    shift: 0x01_U256,
196                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
197                },
198                TestCase {
199                    value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
200                    shift: 0x01_U256,
201                    expected: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe_U256,
202                },
203            ];
204        }
205
206        for test in test_cases {
207            host.clear();
208            push!(interpreter, test.value);
209            push!(interpreter, test.shift);
210            shl::<DummyHost, LatestSpec>(&mut interpreter, &mut host);
211            pop!(interpreter, res);
212            assert_eq!(res, test.expected);
213        }
214    }
215
216    #[test]
217    fn test_logical_shift_right() {
218        let mut host = DummyHost::new(Env::default());
219        let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false);
220
221        struct TestCase {
222            value: U256,
223            shift: U256,
224            expected: U256,
225        }
226
227        uint! {
228            let test_cases = [
229                TestCase {
230                    value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
231                    shift: 0x00_U256,
232                    expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
233                },
234                TestCase {
235                    value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
236                    shift: 0x01_U256,
237                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
238                },
239                TestCase {
240                    value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
241                    shift: 0x01_U256,
242                    expected: 0x4000000000000000000000000000000000000000000000000000000000000000_U256,
243                },
244                TestCase {
245                    value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
246                    shift: 0xff_U256,
247                    expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
248                },
249                TestCase {
250                    value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
251                    shift: 0x0100_U256,
252                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
253                },
254                TestCase {
255                    value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
256                    shift: 0x0101_U256,
257                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
258                },
259                TestCase {
260                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
261                    shift: 0x00_U256,
262                    expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
263                },
264                TestCase {
265                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
266                    shift: 0x01_U256,
267                    expected: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
268                },
269                TestCase {
270                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
271                    shift: 0xff_U256,
272                    expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
273                },
274                TestCase {
275                    value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
276                    shift: 0x0100_U256,
277                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
278                },
279                TestCase {
280                    value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
281                    shift: 0x01_U256,
282                    expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
283                },
284            ];
285        }
286
287        for test in test_cases {
288            host.clear();
289            push!(interpreter, test.value);
290            push!(interpreter, test.shift);
291            shr::<DummyHost, LatestSpec>(&mut interpreter, &mut host);
292            pop!(interpreter, res);
293            assert_eq!(res, test.expected);
294        }
295    }
296
297    #[test]
298    fn test_arithmetic_shift_right() {
299        let mut host = DummyHost::new(Env::default());
300        let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false);
301
302        struct TestCase {
303            value: U256,
304            shift: U256,
305            expected: U256,
306        }
307
308        uint! {
309        let test_cases = [
310            TestCase {
311                value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
312                shift: 0x00_U256,
313                expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
314            },
315            TestCase {
316                value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
317                shift: 0x01_U256,
318                expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
319            },
320            TestCase {
321                value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
322                shift: 0x01_U256,
323                expected: 0xc000000000000000000000000000000000000000000000000000000000000000_U256,
324            },
325            TestCase {
326                value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
327                shift: 0xff_U256,
328                expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
329            },
330            TestCase {
331                value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
332                shift: 0x0100_U256,
333                expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
334            },
335            TestCase {
336                value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
337                shift: 0x0101_U256,
338                expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
339            },
340            TestCase {
341                value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
342                shift: 0x00_U256,
343                expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
344            },
345            TestCase {
346                value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
347                shift: 0x01_U256,
348                expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
349            },
350            TestCase {
351                value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
352                shift: 0xff_U256,
353                expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
354            },
355            TestCase {
356                value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
357                shift: 0x0100_U256,
358                expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
359            },
360            TestCase {
361                value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
362                shift: 0x01_U256,
363                expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
364            },
365            TestCase {
366                value: 0x4000000000000000000000000000000000000000000000000000000000000000_U256,
367                shift: 0xfe_U256,
368                expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
369            },
370            TestCase {
371                value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
372                shift: 0xf8_U256,
373                expected: 0x000000000000000000000000000000000000000000000000000000000000007f_U256,
374            },
375            TestCase {
376                value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
377                shift: 0xfe_U256,
378                expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
379            },
380            TestCase {
381                value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
382                shift: 0xff_U256,
383                expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
384            },
385            TestCase {
386                value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
387                shift: 0x0100_U256,
388                expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
389            },
390        ];
391            }
392
393        for test in test_cases {
394            host.clear();
395            push!(interpreter, test.value);
396            push!(interpreter, test.shift);
397            sar::<DummyHost, LatestSpec>(&mut interpreter, &mut host);
398            pop!(interpreter, res);
399            assert_eq!(res, test.expected);
400        }
401    }
402}