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 authored Nov 27, 2024
1 parent cc5c84b commit 18e06a7
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 74 deletions.
46 changes: 6 additions & 40 deletions crates/blockifier/src/execution/native/syscall_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,47 +446,13 @@ 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(input, 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(err) => Err(self.handle_error(remaining_gas, err)),
}

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
45 changes: 11 additions & 34 deletions crates/blockifier/src/execution/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,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 @@ -606,45 +605,23 @@ 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(data_u64, 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
44 changes: 44 additions & 0 deletions crates/blockifier/src/execution/syscalls/syscall_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,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 @@ -250,6 +253,47 @@ impl<'state> SyscallHandlerBase<'state> {
Ok(raw_retdata)
}

pub fn keccak(
&mut self,
input: &[u64],
remaining_gas: &mut u64,
) -> SyscallResult<([u64; 4], usize)> {
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(SyscallExecutionError::SyscallError {
error_data: vec![
Felt::from_hex(INVALID_INPUT_LENGTH_ERROR)
.expect("Failed to parse INVALID_INPUT_LENGTH_ERROR hex string"),
],
});
}
// 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)
.expect("Failed to parse OUT_OF_GAS_ERROR hex string");

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))
}

pub fn finalize(&mut self) {
self.context
.revert_infos
Expand Down

0 comments on commit 18e06a7

Please sign in to comment.