Skip to content

Commit

Permalink
perf(precompile): use Bytes in precompile functions (bluealloy#1085)
Browse files Browse the repository at this point in the history
* perf(precompile): use `Bytes` in precompile functions

* fix: ecrecover

* chore: clippy
  • Loading branch information
DaniPopes authored Feb 13, 2024
1 parent ee62866 commit 0651044
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 80 deletions.
4 changes: 2 additions & 2 deletions crates/interpreter/src/instructions/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ macro_rules! as_u64_saturated {

macro_rules! as_usize_saturated {
($v:expr) => {
::core::convert::TryInto::<usize>::try_into(as_u64_saturated!($v)).unwrap_or(usize::MAX)
usize::try_from(as_u64_saturated!($v)).unwrap_or(usize::MAX)
};
}

Expand All @@ -234,7 +234,7 @@ macro_rules! as_usize_or_fail_ret {
$interp.instruction_result = $reason;
return $ret;
}
let Ok(val) = ::core::convert::TryInto::<usize>::try_into(x[0]) else {
let Ok(val) = usize::try_from(x[0]) else {
$interp.instruction_result = $reason;
return $ret;
};
Expand Down
8 changes: 5 additions & 3 deletions crates/precompile/src/blake2.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{Error, Precompile, PrecompileResult, PrecompileWithAddress};
use core::convert::TryInto;
use revm_primitives::Bytes;

const F_ROUND: u64 = 1;
const INPUT_LENGTH: usize = 213;
Expand All @@ -10,7 +10,9 @@ pub const FUN: PrecompileWithAddress =
/// reference: <https://eips.ethereum.org/EIPS/eip-152>
/// input format:
/// [4 bytes for rounds][64 bytes for h][128 bytes for m][8 bytes for t_0][8 bytes for t_1][1 byte for f]
fn run(input: &[u8], gas_limit: u64) -> PrecompileResult {
fn run(input: &Bytes, gas_limit: u64) -> PrecompileResult {
let input = &input[..];

if input.len() != INPUT_LENGTH {
return Err(Error::Blake2WrongLength);
}
Expand Down Expand Up @@ -49,7 +51,7 @@ fn run(input: &[u8], gas_limit: u64) -> PrecompileResult {
out[i..i + 8].copy_from_slice(&h.to_le_bytes());
}

Ok((gas_used, out.to_vec()))
Ok((gas_used, out.into()))
}

mod algo {
Expand Down
30 changes: 15 additions & 15 deletions crates/precompile/src/bn128.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{
utilities::right_pad, Address, Error, Precompile, PrecompileResult, PrecompileWithAddress,
};
use alloc::vec::Vec;
use bn::{AffineG1, AffineG2, Fq, Fq2, Group, Gt, G1, G2};
use revm_primitives::Bytes;

pub mod add {
use super::*;
Expand All @@ -11,8 +11,8 @@ pub mod add {

pub const ISTANBUL: PrecompileWithAddress = PrecompileWithAddress(
ADDRESS,
Precompile::Standard(|input: &[u8], target_gas: u64| -> PrecompileResult {
if 150 > target_gas {
Precompile::Standard(|input, gas_limit| {
if 150 > gas_limit {
return Err(Error::OutOfGas);
}
Ok((150, super::run_add(input)?))
Expand All @@ -21,8 +21,8 @@ pub mod add {

pub const BYZANTIUM: PrecompileWithAddress = PrecompileWithAddress(
ADDRESS,
Precompile::Standard(|input: &[u8], target_gas: u64| -> PrecompileResult {
if 500 > target_gas {
Precompile::Standard(|input, gas_limit| {
if 500 > gas_limit {
return Err(Error::OutOfGas);
}
Ok((500, super::run_add(input)?))
Expand All @@ -37,7 +37,7 @@ pub mod mul {

pub const ISTANBUL: PrecompileWithAddress = PrecompileWithAddress(
ADDRESS,
Precompile::Standard(|input: &[u8], gas_limit: u64| -> PrecompileResult {
Precompile::Standard(|input, gas_limit| {
if 6_000 > gas_limit {
return Err(Error::OutOfGas);
}
Expand All @@ -47,7 +47,7 @@ pub mod mul {

pub const BYZANTIUM: PrecompileWithAddress = PrecompileWithAddress(
ADDRESS,
Precompile::Standard(|input: &[u8], gas_limit: u64| -> PrecompileResult {
Precompile::Standard(|input, gas_limit| {
if 40_000 > gas_limit {
return Err(Error::OutOfGas);
}
Expand All @@ -65,12 +65,12 @@ pub mod pair {
const ISTANBUL_PAIR_BASE: u64 = 45_000;
pub const ISTANBUL: PrecompileWithAddress = PrecompileWithAddress(
ADDRESS,
Precompile::Standard(|input: &[u8], target_gas: u64| -> PrecompileResult {
Precompile::Standard(|input, gas_limit| {
super::run_pair(
input,
ISTANBUL_PAIR_PER_POINT,
ISTANBUL_PAIR_BASE,
target_gas,
gas_limit,
)
}),
);
Expand All @@ -79,12 +79,12 @@ pub mod pair {
const BYZANTIUM_PAIR_BASE: u64 = 100_000;
pub const BYZANTIUM: PrecompileWithAddress = PrecompileWithAddress(
ADDRESS,
Precompile::Standard(|input: &[u8], target_gas: u64| -> PrecompileResult {
Precompile::Standard(|input, gas_limit| {
super::run_pair(
input,
BYZANTIUM_PAIR_PER_POINT,
BYZANTIUM_PAIR_BASE,
target_gas,
gas_limit,
)
}),
);
Expand Down Expand Up @@ -132,7 +132,7 @@ fn new_g1_point(px: Fq, py: Fq) -> Result<G1, Error> {
}
}

fn run_add(input: &[u8]) -> Result<Vec<u8>, Error> {
fn run_add(input: &[u8]) -> Result<Bytes, Error> {
let input = right_pad::<ADD_INPUT_LEN>(input);

let p1 = read_point(&input[..64])?;
Expand All @@ -153,7 +153,7 @@ fn run_add(input: &[u8]) -> Result<Vec<u8>, Error> {
Ok(output.into())
}

fn run_mul(input: &[u8]) -> Result<Vec<u8>, Error> {
fn run_mul(input: &[u8]) -> Result<Bytes, Error> {
let input = right_pad::<MUL_INPUT_LEN>(input);

let p = read_point(&input[..64])?;
Expand All @@ -166,7 +166,7 @@ fn run_mul(input: &[u8]) -> Result<Vec<u8>, Error> {
mul.x().to_big_endian(&mut out[..32]).unwrap();
mul.y().to_big_endian(&mut out[32..]).unwrap();
}
Ok(out.to_vec())
Ok(out.into())
}

fn run_pair(
Expand Down Expand Up @@ -225,7 +225,7 @@ fn run_pair(

let mut out = [0u8; 32];
out[31] = success as u8;
Ok((gas_used, out.to_vec()))
Ok((gas_used, out.into()))
}

/*
Expand Down
11 changes: 6 additions & 5 deletions crates/precompile/src/hash.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::calc_linear_cost_u32;
use crate::{Error, Precompile, PrecompileResult, PrecompileWithAddress};
use revm_primitives::Bytes;
use sha2::Digest;

pub const SHA256: PrecompileWithAddress =
Expand All @@ -13,20 +14,20 @@ pub const RIPEMD160: PrecompileWithAddress = PrecompileWithAddress(
/// See: <https://ethereum.github.io/yellowpaper/paper.pdf>
/// See: <https://docs.soliditylang.org/en/develop/units-and-global-variables.html#mathematical-and-cryptographic-functions>
/// See: <https://etherscan.io/address/0000000000000000000000000000000000000002>
fn sha256_run(input: &[u8], gas_limit: u64) -> PrecompileResult {
fn sha256_run(input: &Bytes, gas_limit: u64) -> PrecompileResult {
let cost = calc_linear_cost_u32(input.len(), 60, 12);
if cost > gas_limit {
Err(Error::OutOfGas)
} else {
let output = sha2::Sha256::digest(input).to_vec();
Ok((cost, output))
let output = sha2::Sha256::digest(input);
Ok((cost, output.to_vec().into()))
}
}

/// See: <https://ethereum.github.io/yellowpaper/paper.pdf>
/// See: <https://docs.soliditylang.org/en/develop/units-and-global-variables.html#mathematical-and-cryptographic-functions>
/// See: <https://etherscan.io/address/0000000000000000000000000000000000000003>
fn ripemd160_run(input: &[u8], gas_limit: u64) -> PrecompileResult {
fn ripemd160_run(input: &Bytes, gas_limit: u64) -> PrecompileResult {
let gas_used = calc_linear_cost_u32(input.len(), 600, 120);
if gas_used > gas_limit {
Err(Error::OutOfGas)
Expand All @@ -36,6 +37,6 @@ fn ripemd160_run(input: &[u8], gas_limit: u64) -> PrecompileResult {

let mut output = [0u8; 32];
hasher.finalize_into((&mut output[12..]).into());
Ok((gas_used, output.to_vec()))
Ok((gas_used, output.to_vec().into()))
}
}
5 changes: 3 additions & 2 deletions crates/precompile/src/identity.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::calc_linear_cost_u32;
use crate::{Error, Precompile, PrecompileResult, PrecompileWithAddress};
use revm_primitives::Bytes;

pub const FUN: PrecompileWithAddress =
PrecompileWithAddress(crate::u64_to_address(4), Precompile::Standard(identity_run));
Expand All @@ -13,10 +14,10 @@ const IDENTITY_PER_WORD: u64 = 3;
///
/// See: <https://ethereum.github.io/yellowpaper/paper.pdf>
/// See: <https://etherscan.io/address/0000000000000000000000000000000000000004>
fn identity_run(input: &[u8], gas_limit: u64) -> PrecompileResult {
fn identity_run(input: &Bytes, gas_limit: u64) -> PrecompileResult {
let gas_used = calc_linear_cost_u32(input.len(), IDENTITY_BASE, IDENTITY_PER_WORD);
if gas_used > gas_limit {
return Err(Error::OutOfGas);
}
Ok((gas_used, input.to_vec()))
Ok((gas_used, input.clone()))
}
10 changes: 5 additions & 5 deletions crates/precompile/src/kzg_point_evaluation.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{Address, Error, Precompile, PrecompileResult, PrecompileWithAddress};
use c_kzg::{Bytes32, Bytes48, KzgProof, KzgSettings};
use revm_primitives::{hex_literal::hex, Env};
use revm_primitives::{hex_literal::hex, Bytes, Env};
use sha2::{Digest, Sha256};

// TODO: remove when we have `portable` feature in `c-kzg`
Expand All @@ -27,7 +27,7 @@ const RETURN_VALUE: &[u8; 64] = &hex!(
/// | versioned_hash | z | y | commitment | proof |
/// | 32 | 32 | 32 | 48 | 48 |
/// with z and y being padded 32 byte big endian values
fn run(input: &[u8], gas_limit: u64, env: &Env) -> PrecompileResult {
fn run(input: &Bytes, gas_limit: u64, env: &Env) -> PrecompileResult {
if gas_limit < GAS_COST {
return Err(Error::OutOfGas);
}
Expand All @@ -54,7 +54,7 @@ fn run(input: &[u8], gas_limit: u64, env: &Env) -> PrecompileResult {
}

// Return FIELD_ELEMENTS_PER_BLOB and BLS_MODULUS as padded 32 byte big endian values
Ok((GAS_COST, RETURN_VALUE.to_vec()))
Ok((GAS_COST, RETURN_VALUE.into()))
}

/// `VERSIONED_HASH_VERSION_KZG ++ sha256(commitment)[1..]`
Expand Down Expand Up @@ -116,8 +116,8 @@ mod tests {
let expected_output = hex!("000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001");
let gas = 50000;
let env = Env::default();
let (actual_gas, actual_output) = run(&input, gas, &env).unwrap();
let (actual_gas, actual_output) = run(&input.into(), gas, &env).unwrap();
assert_eq!(actual_gas, gas);
assert_eq!(actual_output, expected_output);
assert_eq!(actual_output[..], expected_output);
}
}
47 changes: 22 additions & 25 deletions crates/precompile/src/modexp.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::{
primitives::U256,
utilities::{left_pad, left_pad_vec, right_pad_with_offset, right_pad_with_offset_vec},
utilities::{left_pad, left_pad_vec, right_pad_vec, right_pad_with_offset},
Error, Precompile, PrecompileResult, PrecompileWithAddress,
};
use alloc::vec::Vec;
use aurora_engine_modexp::modexp;
use core::cmp::{max, min};
use revm_primitives::Bytes;

pub const BYZANTIUM: PrecompileWithAddress = PrecompileWithAddress(
crate::u64_to_address(5),
Expand All @@ -17,13 +17,13 @@ pub const BERLIN: PrecompileWithAddress =

/// See: <https://eips.ethereum.org/EIPS/eip-198>
/// See: <https://etherscan.io/address/0000000000000000000000000000000000000005>
fn byzantium_run(input: &[u8], gas_limit: u64) -> PrecompileResult {
fn byzantium_run(input: &Bytes, gas_limit: u64) -> PrecompileResult {
run_inner(input, gas_limit, 0, |a, b, c, d| {
byzantium_gas_calc(a, b, c, d)
})
}

pub fn berlin_run(input: &[u8], gas_limit: u64) -> PrecompileResult {
pub fn berlin_run(input: &Bytes, gas_limit: u64) -> PrecompileResult {
run_inner(input, gas_limit, 200, |a, b, c, d| {
berlin_gas_calc(a, b, c, d)
})
Expand Down Expand Up @@ -52,6 +52,7 @@ where
if min_gas > gas_limit {
return Err(Error::OutOfGas);
}

// The format of input is:
// <length_of_BASE> <length_of_EXPONENT> <length_of_MODULUS> <BASE> <EXPONENT> <MODULUS>
// Where every length is a 32-byte left-padded integer representing the number of bytes
Expand All @@ -71,26 +72,21 @@ where
return Err(Error::ModexpModOverflow);
};

// Handle a special case when both the base and mod length is zero
// Handle a special case when both the base and mod length are zero.
if base_len == 0 && mod_len == 0 {
return Ok((min_gas, Vec::new()));
return Ok((min_gas, Bytes::new()));
}

// cast exponent length to usize, it does not make sense to handle larger values.
// Cast exponent length to usize, since it does not make sense to handle larger values.
let Ok(exp_len) = usize::try_from(exp_len) else {
return Err(Error::ModexpModOverflow);
};

// Used to extract ADJUSTED_EXPONENT_LENGTH.
let exp_highp_len = min(exp_len, 32);

// throw away the header data as we already extracted lengths.
let input = if input.len() >= 96 {
&input[HEADER_LENGTH..]
} else {
// or set input to zero if there is no more data
&[]
};
// Throw away the header data as we already extracted lengths.
let input = input.get(HEADER_LENGTH..).unwrap_or_default();

let exp_highp = {
// get right padded bytes so if data.len is less then exp_len we will get right padded zeroes.
Expand All @@ -100,23 +96,24 @@ where
U256::from_be_bytes(out.into_owned())
};

// calculate gas spent.
// Check if we have enough gas.
let gas_cost = calc_gas(base_len as u64, exp_len as u64, mod_len as u64, &exp_highp);
// check if we have enough gas.
if gas_cost > gas_limit {
return Err(Error::OutOfGas);
}

// Padding is needed if the input does not contain all 3 values.
let base = right_pad_with_offset_vec(input, 0, base_len);
let exponent = right_pad_with_offset_vec(input, base_len, exp_len);
let modulus = right_pad_with_offset_vec(input, base_len.saturating_add(exp_len), mod_len);
let input_len = base_len.saturating_add(exp_len).saturating_add(mod_len);
let input = right_pad_vec(input, input_len);
let (base, input) = input.split_at(base_len);
let (exponent, modulus) = input.split_at(exp_len);
debug_assert_eq!(modulus.len(), mod_len);

// Call the modexp.
let output = modexp(&base, &exponent, &modulus);
let output = modexp(base, exponent, modulus);

// left pad the result to modulus length. bytes will always by less or equal to modulus length.
Ok((gas_cost, left_pad_vec(&output, mod_len).into_owned()))
Ok((gas_cost, left_pad_vec(&output, mod_len).into_owned().into()))
}

fn byzantium_gas_calc(base_len: u64, exp_len: u64, mod_len: u64, exp_highp: &U256) -> u64 {
Expand Down Expand Up @@ -163,6 +160,7 @@ fn berlin_gas_calc(base_length: u64, exp_length: u64, mod_length: u64, exp_highp
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec::Vec;
use revm_primitives::hex;

struct Test {
Expand Down Expand Up @@ -343,8 +341,7 @@ mod tests {
#[test]
fn test_byzantium_modexp_gas() {
for (test, &test_gas) in TESTS.iter().zip(BYZANTIUM_GAS.iter()) {
let input = hex::decode(test.input).unwrap();

let input = hex::decode(test.input).unwrap().into();
let res = byzantium_run(&input, 100_000_000).unwrap();
let expected = hex::decode(test.expected).unwrap();
assert_eq!(
Expand All @@ -359,7 +356,7 @@ mod tests {
#[test]
fn test_berlin_modexp_gas() {
for (test, &test_gas) in TESTS.iter().zip(BERLIN_GAS.iter()) {
let input = hex::decode(test.input).unwrap();
let input = hex::decode(test.input).unwrap().into();
let res = berlin_run(&input, 100_000_000).unwrap();
let expected = hex::decode(test.expected).unwrap();
assert_eq!(
Expand All @@ -373,7 +370,7 @@ mod tests {

#[test]
fn test_berlin_modexp_empty_input() {
let res = berlin_run(&[], 100_000).unwrap();
let res = berlin_run(&Bytes::new(), 100_000).unwrap();
let expected: Vec<u8> = Vec::new();
assert_eq!(res.1, expected)
}
Expand Down
Loading

0 comments on commit 0651044

Please sign in to comment.