Skip to content

Commit

Permalink
fix(levm): mulmod implementation (#1337)
Browse files Browse the repository at this point in the history
- `mulmod` implementation is refactored to a less error-prone version.
- The modular arithmetic was not being done correctly.
  • Loading branch information
ilitteri authored Nov 28, 2024
1 parent 0303d4d commit c9f6694
Showing 1 changed file with 13 additions and 22 deletions.
35 changes: 13 additions & 22 deletions crates/vm/levm/src/opcode_handlers/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
opcode_handlers::bitwise_comparison::checked_shift_left,
vm::VM,
};
use ethrex_core::{U256, U512};
use ethrex_core::U256;

// Arithmetic Operations (11)
// Opcodes: ADD, SUB, MUL, DIV, SDIV, MOD, SMOD, ADDMOD, MULMOD, EXP, SIGNEXTEND
Expand Down Expand Up @@ -190,31 +190,22 @@ impl VM {
) -> Result<OpcodeSuccess, VMError> {
self.increase_consumed_gas(current_call_frame, gas_cost::MULMOD)?;

let multiplicand = U512::from(current_call_frame.stack.pop()?);
let multiplier = U512::from(current_call_frame.stack.pop()?);
let divisor = U512::from(current_call_frame.stack.pop()?);
if divisor.is_zero() {
let multiplicand = current_call_frame.stack.pop()?;
let multiplier = current_call_frame.stack.pop()?;
let modulus = current_call_frame.stack.pop()?;

if modulus.is_zero() {
current_call_frame.stack.push(U256::zero())?;
return Ok(OpcodeSuccess::Continue);
}

let (product, overflow) = multiplicand.overflowing_mul(multiplier);
let mut remainder = product.checked_rem(divisor).ok_or(VMError::Internal(
InternalError::ArithmeticOperationDividedByZero,
))?; // Cannot be zero bc if above
if overflow || remainder > divisor {
remainder = remainder.overflowing_sub(divisor).0;
}
let mut result = Vec::new();
for byte in remainder.0.iter().take(4) {
let bytes = byte.to_le_bytes();
result.extend_from_slice(&bytes);
}
// before reverse we have something like [120, 255, 0, 0....]
// after reverse we get the [0, 0, ...., 255, 120] which is the correct order for the little endian u256
result.reverse();
let remainder = U256::from(result.as_slice());
current_call_frame.stack.push(remainder)?;
let multiplicand = multiplicand.checked_rem(modulus).unwrap_or_default();
let multiplier = multiplier.checked_rem(modulus).unwrap_or_default();

let (product, _overflowed) = multiplicand.overflowing_mul(multiplier);
let product_mod = product.checked_rem(modulus).unwrap_or_default();

current_call_frame.stack.push(product_mod)?;

Ok(OpcodeSuccess::Continue)
}
Expand Down

0 comments on commit c9f6694

Please sign in to comment.