pub mod i256;
use i256::{i256_div, i256_mod};
mod modular;
use modular::Modular;
use crate::{
vm::{
evm::{interpreter::Halt, EVMGas, Interpreter},
Ext,
},
Error, U256,
};
use core::ops::ControlFlow;
use revm::interpreter::gas::{EXP, LOW, MID, VERYLOW};
pub fn add<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(VERYLOW))?;
let ([op1], op2) = interpreter.stack.popn_top()?;
*op2 = op1.overflowing_add(*op2).0;
ControlFlow::Continue(())
}
pub fn mul<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(LOW))?;
let ([op1], op2) = interpreter.stack.popn_top()?;
*op2 = op1.overflowing_mul(*op2).0;
ControlFlow::Continue(())
}
pub fn sub<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(VERYLOW))?;
let ([op1], op2) = interpreter.stack.popn_top()?;
*op2 = op1.overflowing_sub(*op2).0;
ControlFlow::Continue(())
}
pub fn div<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(LOW))?;
let ([op1], op2) = interpreter.stack.popn_top()?;
if !op2.is_zero() {
*op2 = op1 / *op2;
}
ControlFlow::Continue(())
}
pub fn sdiv<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(LOW))?;
let ([op1], op2) = interpreter.stack.popn_top()?;
*op2 = i256_div(op1, *op2);
ControlFlow::Continue(())
}
pub fn rem<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(LOW))?;
let ([op1], op2) = interpreter.stack.popn_top()?;
if !op2.is_zero() {
*op2 = op1 % *op2;
}
ControlFlow::Continue(())
}
pub fn smod<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(LOW))?;
let ([op1], op2) = interpreter.stack.popn_top()?;
*op2 = i256_mod(op1, *op2);
ControlFlow::Continue(())
}
pub fn addmod<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(MID))?;
let ([op1, op2], op3) = interpreter.stack.popn_top()?;
*op3 = op1.add_mod(op2, *op3);
ControlFlow::Continue(())
}
pub fn mulmod<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(MID))?;
let ([op1, op2], op3) = interpreter.stack.popn_top()?;
*op3 = op1.mul_mod(op2, *op3);
ControlFlow::Continue(())
}
pub fn exp<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
let ([op1], op2) = interpreter.stack.popn_top()?;
let Some(gas_cost) = exp_cost(*op2) else {
return ControlFlow::Break(Error::<E::T>::OutOfGas.into());
};
interpreter.ext.charge_or_halt(EVMGas(gas_cost))?;
*op2 = op1.overflowing_pow(*op2).0;
ControlFlow::Continue(())
}
pub fn signextend<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt> {
interpreter.ext.charge_or_halt(EVMGas(LOW))?;
let ([ext], x) = interpreter.stack.popn_top()?;
if ext < U256::from(31) {
let ext = &ext.0[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 };
}
ControlFlow::Continue(())
}
fn exp_cost(power: U256) -> Option<u64> {
if power.is_zero() {
Some(EXP)
} else {
let gas_byte = U256::from(50);
let gas = U256::from(EXP)
.checked_add(gas_byte.checked_mul(U256::from(log2floor(power) / 8 + 1))?)?;
u64::try_from(gas).ok()
}
}
const fn log2floor(value: U256) -> u64 {
let mut l: u64 = 256;
let mut i = 3;
loop {
if value.0[i] == 0u64 {
l -= 64;
} else {
l -= value.0[i].leading_zeros() as u64;
if l == 0 {
return l;
} else {
return l - 1;
}
}
if i == 0 {
break;
}
i -= 1;
}
l
}