Skip to content

Commit

Permalink
refactor(precompile): make use of padding utilities, simplify secp256k1
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes committed Feb 10, 2024
1 parent 1b8704f commit 08ae23f
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 82 deletions.
8 changes: 3 additions & 5 deletions crates/precompile/src/blake2.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
use crate::{Error, Precompile, PrecompileResult, PrecompileWithAddress, StandardPrecompileFn};
use crate::{Error, Precompile, PrecompileResult, PrecompileWithAddress};
use core::convert::TryInto;

const F_ROUND: u64 = 1;
const INPUT_LENGTH: usize = 213;

pub const FUN: PrecompileWithAddress = PrecompileWithAddress(
crate::u64_to_address(9),
Precompile::Standard(run as StandardPrecompileFn),
);
pub const FUN: PrecompileWithAddress =
PrecompileWithAddress(crate::u64_to_address(9), Precompile::Standard(run));

/// reference: <https://eips.ethereum.org/EIPS/eip-152>
/// input format:
Expand Down
22 changes: 12 additions & 10 deletions crates/precompile/src/hash.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use super::calc_linear_cost_u32;
use crate::{Error, Precompile, PrecompileResult, PrecompileWithAddress, StandardPrecompileFn};
use sha2::*;
use crate::{Error, Precompile, PrecompileResult, PrecompileWithAddress};
use sha2::Digest;

pub const SHA256: PrecompileWithAddress =
PrecompileWithAddress(crate::u64_to_address(2), Precompile::Standard(sha256_run));

pub const SHA256: PrecompileWithAddress = PrecompileWithAddress(
crate::u64_to_address(2),
Precompile::Standard(sha256_run as StandardPrecompileFn),
);
pub const RIPEMD160: PrecompileWithAddress = PrecompileWithAddress(
crate::u64_to_address(3),
Precompile::Standard(ripemd160_run as StandardPrecompileFn),
Precompile::Standard(ripemd160_run),
);

/// See: <https://ethereum.github.io/yellowpaper/paper.pdf>
Expand All @@ -32,8 +31,11 @@ fn ripemd160_run(input: &[u8], gas_limit: u64) -> PrecompileResult {
if gas_used > gas_limit {
Err(Error::OutOfGas)
} else {
let mut ret = [0u8; 32];
ret[12..32].copy_from_slice(&ripemd::Ripemd160::digest(input));
Ok((gas_used, ret.to_vec()))
let mut hasher = ripemd::Ripemd160::new();
hasher.update(input);

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

pub const FUN: PrecompileWithAddress = PrecompileWithAddress(
crate::u64_to_address(4),
Precompile::Standard(identity_run as StandardPrecompileFn),
);
pub const FUN: PrecompileWithAddress =
PrecompileWithAddress(crate::u64_to_address(4), Precompile::Standard(identity_run));

/// The base cost of the operation.
const IDENTITY_BASE: u64 = 15;
Expand Down
4 changes: 2 additions & 2 deletions crates/precompile/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ impl Precompiles {

/// Returns the precompile for the given address.
#[inline]
pub fn get(&self, address: &Address) -> Option<Precompile> {
self.inner.get(address).cloned()
pub fn get(&self, address: &Address) -> Option<&Precompile> {
self.inner.get(address)
}

/// Is the precompiles list empty.
Expand Down
24 changes: 6 additions & 18 deletions crates/precompile/src/modexp.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
use crate::{
primitives::U256,
utilities::{get_right_padded, get_right_padded_vec, left_padding, left_padding_vec},
Error, Precompile, PrecompileResult, PrecompileWithAddress, StandardPrecompileFn,
Error, Precompile, PrecompileResult, PrecompileWithAddress,
};
use alloc::vec::Vec;
use aurora_engine_modexp::modexp;
use core::cmp::{max, min};

pub const BYZANTIUM: PrecompileWithAddress = PrecompileWithAddress(
crate::u64_to_address(5),
Precompile::Standard(byzantium_run as StandardPrecompileFn),
Precompile::Standard(byzantium_run),
);

pub const BERLIN: PrecompileWithAddress = PrecompileWithAddress(
crate::u64_to_address(5),
Precompile::Standard(berlin_run as StandardPrecompileFn),
);
pub const BERLIN: PrecompileWithAddress =
PrecompileWithAddress(crate::u64_to_address(5), Precompile::Standard(berlin_run));

/// See: <https://eips.ethereum.org/EIPS/eip-198>
/// See: <https://etherscan.io/address/0000000000000000000000000000000000000005>
Expand Down Expand Up @@ -139,12 +137,7 @@ fn byzantium_gas_calc(base_len: u64, exp_len: u64, mod_len: u64, exp_highp: &U25
let iter_count = U256::from(calculate_iteration_count(exp_len, exp_highp));
// mul * iter_count bounded by 2^195 < 2^256 (no overflow)
let gas = (mul * iter_count) / U256::from(20);

if gas.as_limbs()[1] != 0 || gas.as_limbs()[2] != 0 || gas.as_limbs()[3] != 0 {
u64::MAX
} else {
gas.as_limbs()[0]
}
gas.saturating_to()
}

// Calculate gas cost according to EIP 2565:
Expand All @@ -163,12 +156,7 @@ fn berlin_gas_calc(base_length: u64, exp_length: u64, mod_length: u64, exp_highp
let multiplication_complexity = calculate_multiplication_complexity(base_length, mod_length);
let iteration_count = calculate_iteration_count(exp_length, exp_highp);
let gas = (multiplication_complexity * U256::from(iteration_count)) / U256::from(3);

if gas.as_limbs()[1] != 0 || gas.as_limbs()[2] != 0 || gas.as_limbs()[3] != 0 {
u64::MAX
} else {
max(200, gas.as_limbs()[0])
}
max(200, gas.saturating_to())
}

#[cfg(test)]
Expand Down
51 changes: 24 additions & 27 deletions crates/precompile/src/secp256k1.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
use crate::{Error, Precompile, PrecompileResult, PrecompileWithAddress, StandardPrecompileFn};
use crate::{
utilities::get_right_padded, Error, Precompile, PrecompileResult, PrecompileWithAddress,
};
use alloc::vec::Vec;
use core::cmp::min;
use revm_primitives::B256;
use revm_primitives::{alloy_primitives::B512, B256};

pub const ECRECOVER: PrecompileWithAddress = PrecompileWithAddress(
crate::u64_to_address(1),
Precompile::Standard(ec_recover_run as StandardPrecompileFn),
Precompile::Standard(ec_recover_run),
);

#[cfg(not(feature = "secp256k1"))]
#[allow(clippy::module_inception)]
mod secp256k1 {
use crate::B256;
use k256::ecdsa::{Error, RecoveryId, Signature, VerifyingKey};
use revm_primitives::keccak256;
use revm_primitives::{alloy_primitives::B512, keccak256, B256};

pub fn ecrecover(sig: &[u8; 65], msg: &B256) -> Result<B256, Error> {
pub fn ecrecover(sig: &B512, mut recid: u8, msg: &B256) -> Result<B256, Error> {
// parse signature
let mut recid = sig[64];
let mut sig = Signature::from_slice(&sig[..64])?;
let mut sig = Signature::from_slice(sig.as_slice())?;

// normalize signature and flip recovery id if needed.
if let Some(sig_normalized) = sig.normalize_s() {
sig = sig_normalized;
recid = recid ^ 1;
};
let recid = RecoveryId::from_byte(recid).expect("Recovery id is valid");
}
let recid = RecoveryId::from_byte(recid).expect("recovery ID is valid");

// recover key
let recovered_key = VerifyingKey::recover_from_prehash(&msg[..], &sig, recid)?;
Expand All @@ -45,8 +44,7 @@ mod secp256k1 {
#[cfg(feature = "secp256k1")]
#[allow(clippy::module_inception)]
mod secp256k1 {
use crate::B256;
use revm_primitives::keccak256;
use revm_primitives::{alloy_primitives::B512, keccak256, B256};
use secp256k1::{
ecdsa::{RecoverableSignature, RecoveryId},
Message, Secp256k1,
Expand All @@ -55,40 +53,39 @@ mod secp256k1 {
// Silence the unused crate dependency warning.
use k256 as _;

pub fn ecrecover(sig: &[u8; 65], msg: &B256) -> Result<B256, secp256k1::Error> {
let sig =
RecoverableSignature::from_compact(&sig[0..64], RecoveryId::from_i32(sig[64] as i32)?)?;
pub fn ecrecover(sig: &B512, recid: u8, msg: &B256) -> Result<B256, secp256k1::Error> {
let recid = RecoveryId::from_i32(recid as i32).expect("recovery ID is valid");
let sig = RecoverableSignature::from_compact(sig.as_slice(), recid)?;

let secp = Secp256k1::new();
let public = secp.recover_ecdsa(&Message::from_digest_slice(&msg[..])?, &sig)?;
let msg = Message::from_digest_slice(msg.as_slice())?;
let public = secp.recover_ecdsa(&msg, &sig)?;

let mut hash = keccak256(&public.serialize_uncompressed()[1..]);
hash[..12].fill(0);
Ok(hash)
}
}

fn ec_recover_run(i: &[u8], target_gas: u64) -> PrecompileResult {
fn ec_recover_run(input: &[u8], target_gas: u64) -> PrecompileResult {
const ECRECOVER_BASE: u64 = 3_000;

if ECRECOVER_BASE > target_gas {
return Err(Error::OutOfGas);
}
let mut input = [0u8; 128];
input[..min(i.len(), 128)].copy_from_slice(&i[..min(i.len(), 128)]);

let msg = B256::from_slice(&input[0..32]);
let input = get_right_padded::<128>(input, 0);

let mut sig = [0u8; 65];
sig[0..64].copy_from_slice(&input[64..128]);

if input[32..63] != [0u8; 31] || !matches!(input[63], 27 | 28) {
// `v` must be a 32-byte big-endian integer equal to 27 or 28.
if !(input[32..63].iter().all(|&b| b == 0) && matches!(input[63], 27 | 28)) {
return Ok((ECRECOVER_BASE, Vec::new()));
}

sig[64] = input[63] - 27;
let msg = <&B256>::try_from(&input[0..32]).unwrap();
let recid = input[63] - 27;
let sig = <&B512>::try_from(&input[64..128]).unwrap();

let out = secp256k1::ecrecover(&sig, &msg)
let out = secp256k1::ecrecover(sig, recid, msg)
.map(|o| o.to_vec())
.unwrap_or_default();

Expand Down
25 changes: 12 additions & 13 deletions crates/precompile/src/utilities.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
use core::cmp::min;

use alloc::vec::Vec;
use core::cmp::min;

/// Get an array from the data, if data does not contain `start` to `len` bytes, add right padding with
/// zeroes
/// Get an array from the data, if data does not contain `start` to `len` bytes,
/// add right padding with zeroes.
#[inline(always)]
pub fn get_right_padded<const S: usize>(data: &[u8], offset: usize) -> [u8; S] {
let mut padded = [0; S];
pub fn get_right_padded<const LEN: usize>(data: &[u8], offset: usize) -> [u8; LEN] {
let mut padded = [0; LEN];
let start = min(offset, data.len());
let end = min(start.saturating_add(S), data.len());
let end = min(start.saturating_add(LEN), data.len());
padded[..end - start].copy_from_slice(&data[start..end]);
padded
}

/// Get a vector of the data, if data does not contain the slice of `start` to `len`, right pad missing
/// part with zeroes
/// Get a vector of the data, if data does not contain the slice of `start` to `len`,
/// right pad missing part with zeroes.
#[inline(always)]
pub fn get_right_padded_vec(data: &[u8], offset: usize, len: usize) -> Vec<u8> {
let mut padded = vec![0; len];
Expand All @@ -26,10 +25,10 @@ pub fn get_right_padded_vec(data: &[u8], offset: usize, len: usize) -> Vec<u8> {

/// Left padding until `len`. If data is more then len, truncate the right most bytes.
#[inline(always)]
pub fn left_padding<const S: usize>(data: &[u8]) -> [u8; S] {
let mut padded = [0; S];
let end = min(S, data.len());
padded[S - end..].copy_from_slice(&data[..end]);
pub fn left_padding<const LEN: usize>(data: &[u8]) -> [u8; LEN] {
let mut padded = [0; LEN];
let end = min(LEN, data.len());
padded[LEN - end..].copy_from_slice(&data[..end]);
padded
}

Expand Down
4 changes: 2 additions & 2 deletions crates/revm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ impl<DB: Database> EvmContext<DB> {
/// Sets precompiles
pub fn set_precompiles(&mut self, precompiles: Precompiles) {
self.journaled_state.warm_preloaded_addresses =
precompiles.addresses().cloned().collect::<HashSet<_>>();
precompiles.addresses().copied().collect::<HashSet<_>>();
self.precompiles = precompiles;
}

Expand Down Expand Up @@ -415,7 +415,7 @@ impl<DB: Database> EvmContext<DB> {
}

if let Some(precompile) = self.precompiles.get(&inputs.contract) {
let result = self.call_precompile(precompile, inputs, gas);
let result = self.call_precompile(precompile.clone(), inputs, gas);
if matches!(result.result, return_ok!()) {
self.journaled_state.checkpoint_commit();
} else {
Expand Down

0 comments on commit 08ae23f

Please sign in to comment.