use super::i256::i256_cmp;
use crate::{gas, Host, Interpreter};
use core::cmp::Ordering;
use primitives::U256;
use specification::hardfork::Spec;
pub fn lt<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = U256::from(op1 < *op2);
}
pub fn gt<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = U256::from(op1 > *op2);
}
pub fn slt<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Less);
}
pub fn sgt<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Greater);
}
pub fn eq<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = U256::from(op1 == *op2);
}
pub fn iszero<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1);
*op1 = U256::from(op1.is_zero());
}
pub fn bitand<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = op1 & *op2;
}
pub fn bitor<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = op1 | *op2;
}
pub fn bitxor<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = op1 ^ *op2;
}
pub fn not<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1);
*op1 = !*op1;
}
pub fn byte<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
let o1 = as_usize_saturated!(op1);
*op2 = if o1 < 32 {
U256::from(op2.byte(31 - o1))
} else {
U256::ZERO
};
}
pub fn shl<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H) {
check!(interpreter, CONSTANTINOPLE);
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
let shift = as_usize_saturated!(op1);
*op2 = if shift < 256 {
*op2 << shift
} else {
U256::ZERO
}
}
pub fn shr<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H) {
check!(interpreter, CONSTANTINOPLE);
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
let shift = as_usize_saturated!(op1);
*op2 = if shift < 256 {
*op2 >> shift
} else {
U256::ZERO
}
}
pub fn sar<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H) {
check!(interpreter, CONSTANTINOPLE);
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
let shift = as_usize_saturated!(op1);
*op2 = if shift < 256 {
op2.arithmetic_shr(shift)
} else if op2.bit(255) {
U256::MAX
} else {
U256::ZERO
};
}
#[cfg(test)]
mod tests {
use crate::instructions::bitwise::{byte, sar, shl, shr};
use crate::{Contract, DummyHost, Interpreter};
use primitives::{uint, U256};
use specification::hardfork::LatestSpec;
use wiring::{default::Env, DefaultEthereumWiring};
#[test]
fn test_shift_left() {
let mut host = DummyHost::new(Env::default());
let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false);
struct TestCase {
value: U256,
shift: U256,
expected: U256,
}
uint! {
let test_cases = [
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x00_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x01_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000002_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0xff_U256,
expected: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x0100_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x0101_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x00_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x01_U256,
expected: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0xff_U256,
expected: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x0100_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x01_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x01_U256,
expected: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe_U256,
},
];
}
for test in test_cases {
host.clear();
push!(interpreter, test.value);
push!(interpreter, test.shift);
shl::<DummyHost<DefaultEthereumWiring>, LatestSpec>(&mut interpreter, &mut host);
pop!(interpreter, res);
assert_eq!(res, test.expected);
}
}
#[test]
fn test_logical_shift_right() {
let mut host = DummyHost::new(Env::default());
let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false);
struct TestCase {
value: U256,
shift: U256,
expected: U256,
}
uint! {
let test_cases = [
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x00_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x01_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x01_U256,
expected: 0x4000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0xff_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x0100_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x0101_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x00_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x01_U256,
expected: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0xff_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x0100_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x01_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
];
}
for test in test_cases {
host.clear();
push!(interpreter, test.value);
push!(interpreter, test.shift);
shr::<DummyHost<DefaultEthereumWiring>, LatestSpec>(&mut interpreter, &mut host);
pop!(interpreter, res);
assert_eq!(res, test.expected);
}
}
#[test]
fn test_arithmetic_shift_right() {
let mut host = DummyHost::new(Env::default());
let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false);
struct TestCase {
value: U256,
shift: U256,
expected: U256,
}
uint! {
let test_cases = [
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x00_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x01_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x01_U256,
expected: 0xc000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0xff_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x0100_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x0101_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x00_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x01_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0xff_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x0100_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x01_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x4000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0xfe_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
},
TestCase {
value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0xf8_U256,
expected: 0x000000000000000000000000000000000000000000000000000000000000007f_U256,
},
TestCase {
value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0xfe_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
},
TestCase {
value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0xff_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x0100_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
];
}
for test in test_cases {
host.clear();
push!(interpreter, test.value);
push!(interpreter, test.shift);
sar::<DummyHost<DefaultEthereumWiring>, LatestSpec>(&mut interpreter, &mut host);
pop!(interpreter, res);
assert_eq!(res, test.expected);
}
}
#[test]
fn test_byte() {
struct TestCase {
input: U256,
index: usize,
expected: U256,
}
let mut host = DummyHost::<DefaultEthereumWiring>::new(Env::default());
let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false);
let input_value = U256::from(0x1234567890abcdef1234567890abcdef_u128);
let test_cases = (0..32)
.map(|i| {
let byte_pos = 31 - i;
let shift_amount = U256::from(byte_pos * 8);
let byte_value = (input_value >> shift_amount) & U256::from(0xFF);
TestCase {
input: input_value,
index: i,
expected: byte_value,
}
})
.collect::<Vec<_>>();
for test in test_cases.iter() {
push!(interpreter, test.input);
push!(interpreter, U256::from(test.index));
byte(&mut interpreter, &mut host);
pop!(interpreter, res);
assert_eq!(res, test.expected, "Failed at index: {}", test.index);
}
}
}