Skip to content

Commit 5cd1cc9

Browse files
blockifier: add fn encode_felt252_data_and_calc_blake_hash_cost
1 parent 73e88e4 commit 5cd1cc9

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

crates/blockifier/src/execution/execution_utils.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use cairo_vm::vm::vm_core::VirtualMachine;
1818
use num_bigint::BigUint;
1919
use starknet_api::core::ClassHash;
2020
use starknet_api::deprecated_contract_class::Program as DeprecatedProgram;
21+
use starknet_api::execution_resources::GasAmount;
2122
use starknet_api::transaction::fields::Calldata;
2223
use starknet_types_core::felt::Felt;
2324

@@ -44,6 +45,7 @@ use crate::execution::syscalls::hint_processor::{ENTRYPOINT_NOT_FOUND_ERROR, OUT
4445
use crate::execution::{deprecated_entry_point_execution, entry_point_execution};
4546
use crate::state::errors::StateError;
4647
use crate::state::state_api::State;
48+
use crate::utils::u64_from_usize;
4749

4850
pub type Args = Vec<CairoArg>;
4951

@@ -361,3 +363,84 @@ pub fn poseidon_hash_many_cost(data_length: usize) -> ExecutionResources {
361363
builtin_instance_counter: HashMap::from([(BuiltinName::poseidon, data_length / 2 + 1)]),
362364
}
363365
}
366+
367+
mod blake_cost {
368+
// U-32 counts
369+
pub const N_U32S_MESSAGE: usize = 16;
370+
pub const N_U32S_BIG_FELT: usize = 8;
371+
pub const N_U32S_SMALL_FELT: usize = 2;
372+
373+
// Steps counts
374+
pub const STEPS_BIG_FELT: usize = 45;
375+
pub const STEPS_SMALL_FELT: usize = 15;
376+
377+
// One-time segment setup cost (full vs partial)
378+
pub const BASE_STEPS_FULL_MSG: usize = 217;
379+
pub const BASE_STEPS_PARTIAL_MSG: usize = 195;
380+
pub const STEPS_PER_2_U32_REMINDER: usize = 3;
381+
382+
// TODO(AvivG): This is a placeholder, add the actual gas cost for the BLAKE opcode
383+
pub const BLAKE_OPCODE_GAS: usize = 0;
384+
}
385+
386+
/// Estimates the number of VM steps needed to hash the given felts with Blake in Starknet OS.
387+
/// Each small felt unpacks into 2 u32s, and each big felt into 8 u32s.
388+
/// Adds a base cost depending on whether the total fits exactly into full 16-u32 messages.
389+
fn compute_blake_hash_steps(n_big_felts: usize, n_small_felts: usize) -> usize {
390+
let total_u32s =
391+
n_big_felts * blake_cost::N_U32S_BIG_FELT + n_small_felts * blake_cost::N_U32S_SMALL_FELT;
392+
let rem_u32s = total_u32s % blake_cost::N_U32S_MESSAGE;
393+
394+
let base_steps = if rem_u32s == 0 {
395+
blake_cost::BASE_STEPS_FULL_MSG
396+
} else {
397+
// This computation is based on manual calculations of running blake2s with different
398+
// inputs.
399+
blake_cost::BASE_STEPS_PARTIAL_MSG + blake_cost::STEPS_PER_2_U32_REMINDER * (rem_u32s / 2)
400+
};
401+
402+
n_big_felts * blake_cost::STEPS_BIG_FELT
403+
+ n_small_felts * blake_cost::STEPS_SMALL_FELT
404+
+ base_steps
405+
}
406+
407+
/// Returns the number of BLAKE opcodes needed to hash the given felts.
408+
/// Each BLAKE opcode processes 16 u32s (partial messages are padded).
409+
fn count_blake_opcode(n_big_felts: usize, n_small_felts: usize) -> usize {
410+
// Count the total number of u32s to be hashed.
411+
let total_u32s =
412+
n_big_felts * blake_cost::N_U32S_BIG_FELT + n_small_felts * blake_cost::N_U32S_SMALL_FELT;
413+
414+
let full_msgs = total_u32s / blake_cost::N_U32S_MESSAGE;
415+
let has_partial = total_u32s % blake_cost::N_U32S_MESSAGE != 0;
416+
417+
if has_partial { full_msgs + 1 } else { full_msgs }
418+
}
419+
420+
/// Estimates the VM resources for `encode_felt252_data_and_calc_blake_hash` in the Starknet OS.
421+
/// Assumes small felts unpack into 2 u32s and big felts into 8 u32s.
422+
pub fn cost_of_encode_felt252_data_and_calc_blake_hash<F>(
423+
n_big_felts: usize,
424+
n_small_felts: usize,
425+
resources_to_gas_fn: F,
426+
) -> GasAmount
427+
where
428+
F: Fn(&ExecutionResources) -> GasAmount,
429+
{
430+
let n_steps = compute_blake_hash_steps(n_big_felts, n_small_felts);
431+
let n_felts = n_big_felts + n_small_felts;
432+
// One `range_check` per input felt to validate its size.
433+
let builtins = HashMap::from([(BuiltinName::range_check, n_felts)]);
434+
let resources =
435+
ExecutionResources { n_steps, n_memory_holes: 0, builtin_instance_counter: builtins };
436+
let gas = resources_to_gas_fn(&resources);
437+
438+
let blake_op_count = count_blake_opcode(n_big_felts, n_small_felts);
439+
let blake_op_gas = blake_op_count
440+
.checked_mul(blake_cost::BLAKE_OPCODE_GAS)
441+
.map(u64_from_usize)
442+
.map(GasAmount)
443+
.expect("Overflow computing Blake opcode gas.");
444+
445+
gas.checked_add_panic_on_overflow(blake_op_gas)
446+
}

crates/blockifier/src/utils.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::collections::HashMap;
22

33
use cairo_vm::vm::runners::cairo_runner::ExecutionResources;
4+
use starknet_api::execution_resources::GasAmount;
45

56
use crate::blockifier_versioned_constants::{BaseGasCosts, BuiltinGasCosts};
67
use crate::transaction::errors::NumericConversionError;

0 commit comments

Comments
 (0)