Skip to content

Commit

Permalink
chore(blockifier): create func keccak_base to delete code duplication
Browse files Browse the repository at this point in the history
  • Loading branch information
avivg-starkware committed Nov 27, 2024
1 parent a44a243 commit b6f7a00
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 72 deletions.
44 changes: 6 additions & 38 deletions crates/blockifier/src/execution/native/syscall_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,47 +486,15 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> {
fn keccak(&mut self, input: &[u64], remaining_gas: &mut u64) -> SyscallResult<U256> {
self.pre_execute_syscall(remaining_gas, self.gas_costs().keccak_gas_cost)?;

const KECCAK_FULL_RATE_IN_WORDS: usize = 17;

let input_length = input.len();
let (n_rounds, remainder) = num_integer::div_rem(input_length, KECCAK_FULL_RATE_IN_WORDS);

if remainder != 0 {
return Err(self.handle_error(
remaining_gas,
SyscallExecutionError::SyscallError {
error_data: vec![Felt::from_hex(INVALID_INPUT_LENGTH_ERROR).unwrap()],
},
));
}

// TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion
// works.
let n_rounds = u64::try_from(n_rounds).expect("Failed to convert usize to u64.");
let gas_cost = n_rounds * self.gas_costs().keccak_round_cost_gas_cost;

if gas_cost > *remaining_gas {
return Err(self.handle_error(
remaining_gas,
SyscallExecutionError::SyscallError {
error_data: vec![Felt::from_hex(OUT_OF_GAS_ERROR).unwrap()],
},
));
}
*remaining_gas -= gas_cost;

let mut state = [0u64; 25];
for chunk in input.chunks(KECCAK_FULL_RATE_IN_WORDS) {
for (i, val) in chunk.iter().enumerate() {
state[i] ^= val;
}
keccak::f1600(&mut state)
match self.base.keccak_base(input, input_length, remaining_gas) {
Ok((state, _n_rounds)) => Ok(U256 {
hi: u128::from(state[2]) | (u128::from(state[3]) << 64),
lo: u128::from(state[0]) | (u128::from(state[1]) << 64),
}),
Err(e) => Err(self.handle_error(remaining_gas, e.into())),
}

Ok(U256 {
hi: u128::from(state[2]) | (u128::from(state[3]) << 64),
lo: u128::from(state[0]) | (u128::from(state[1]) << 64),
})
}

fn secp256k1_new(
Expand Down
46 changes: 12 additions & 34 deletions crates/blockifier/src/execution/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ use crate::execution::execution_utils::{
write_maybe_relocatable,
ReadOnlySegment,
};
use crate::execution::syscalls::hint_processor::{INVALID_INPUT_LENGTH_ERROR, OUT_OF_GAS_ERROR};
use crate::execution::syscalls::syscall_base::SyscallResult;
use crate::versioned_constants::{EventLimits, VersionedConstants};

Expand Down Expand Up @@ -639,45 +638,24 @@ pub fn keccak(
) -> SyscallResult<KeccakResponse> {
let input_length = (request.input_end - request.input_start)?;

const KECCAK_FULL_RATE_IN_WORDS: usize = 17;
let (n_rounds, remainder) = num_integer::div_rem(input_length, KECCAK_FULL_RATE_IN_WORDS);

if remainder != 0 {
return Err(SyscallExecutionError::SyscallError {
error_data: vec![
Felt::from_hex(INVALID_INPUT_LENGTH_ERROR).map_err(SyscallExecutionError::from)?,
],
});
}

// TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion works.
let n_rounds_as_u64 = u64::try_from(n_rounds).expect("Failed to convert usize to u64.");
let gas_cost = n_rounds_as_u64 * syscall_handler.gas_costs().keccak_round_cost_gas_cost;
if gas_cost > *remaining_gas {
let out_of_gas_error =
Felt::from_hex(OUT_OF_GAS_ERROR).map_err(SyscallExecutionError::from)?;
let data = vm.get_integer_range(request.input_start, input_length)?;
let data_u64: &[u64] = &data
.iter()
.map(|felt| {
felt.to_u64().ok_or_else(|| SyscallExecutionError::InvalidSyscallInput {
input: **felt,
info: "Invalid input for the keccak syscall.".to_string(),
})
})
.collect::<Result<Vec<u64>, _>>()?;

return Err(SyscallExecutionError::SyscallError { error_data: vec![out_of_gas_error] });
}
*remaining_gas -= gas_cost;
let (state, n_rounds) =
syscall_handler.base.keccak_base(data_u64, input_length, remaining_gas)?;

// For the keccak system call we want to count the number of rounds rather than the number of
// syscall invocations.
syscall_handler.increment_syscall_count_by(&SyscallSelector::Keccak, n_rounds);

let data = vm.get_integer_range(request.input_start, input_length)?;

let mut state = [0u64; 25];
for chunk in data.chunks(KECCAK_FULL_RATE_IN_WORDS) {
for (i, val) in chunk.iter().enumerate() {
state[i] ^= val.to_u64().ok_or_else(|| SyscallExecutionError::InvalidSyscallInput {
input: **val,
info: String::from("Invalid input for the keccak syscall."),
})?;
}
keccak::f1600(&mut state)
}

Ok(KeccakResponse {
result_low: (Felt::from(state[1]) * Felt::TWO.pow(64_u128)) + Felt::from(state[0]),
result_high: (Felt::from(state[3]) * Felt::TWO.pow(64_u128)) + Felt::from(state[2]),
Expand Down
43 changes: 43 additions & 0 deletions crates/blockifier/src/execution/syscalls/syscall_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ use crate::execution::syscalls::hint_processor::{
SyscallExecutionError,
BLOCK_NUMBER_OUT_OF_RANGE_ERROR,
ENTRYPOINT_FAILED_ERROR,
INVALID_INPUT_LENGTH_ERROR,
OUT_OF_GAS_ERROR,
};
use crate::state::state_api::State;
use crate::transaction::account_transaction::is_cairo1;

pub type SyscallResult<T> = Result<T, SyscallExecutionError>;
pub const KECCAK_FULL_RATE_IN_WORDS: usize = 17;

/// This file is for sharing common logic between Native and VM syscall implementations.
Expand Down Expand Up @@ -207,4 +210,44 @@ impl<'state> SyscallHandlerBase<'state> {
.expect("Missing contract revert info.")
.original_values = std::mem::take(&mut self.original_values);
}

pub fn keccak_base(
&mut self,
input: &[u64],
input_length: usize,
remaining_gas: &mut u64,
) -> SyscallResult<([u64; 4], usize)> {
let (n_rounds, remainder) = num_integer::div_rem(input_length, KECCAK_FULL_RATE_IN_WORDS);

if remainder != 0 {
return Err(SyscallExecutionError::SyscallError {
error_data: vec![
Felt::from_hex(INVALID_INPUT_LENGTH_ERROR)
.map_err(SyscallExecutionError::from)?,
],
});
}
// TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion
// works.
let n_rounds_as_u64 = u64::try_from(n_rounds).expect("Failed to convert usize to u64.");
let gas_cost = n_rounds_as_u64 * self.context.gas_costs().keccak_round_cost_gas_cost;

if gas_cost > *remaining_gas {
let out_of_gas_error =
Felt::from_hex(OUT_OF_GAS_ERROR).map_err(SyscallExecutionError::from)?;

return Err(SyscallExecutionError::SyscallError { error_data: vec![out_of_gas_error] });
}
*remaining_gas -= gas_cost;

let mut state = [0u64; 25];
for chunk in input.chunks(KECCAK_FULL_RATE_IN_WORDS) {
for (i, val) in chunk.iter().enumerate() {
state[i] ^= val;
}
keccak::f1600(&mut state)
}

Ok((state[..4].try_into().expect("Slice with incorrect length"), n_rounds))
}
}

0 comments on commit b6f7a00

Please sign in to comment.