@@ -18,6 +18,7 @@ use cairo_vm::vm::vm_core::VirtualMachine;
1818use num_bigint:: BigUint ;
1919use starknet_api:: core:: ClassHash ;
2020use starknet_api:: deprecated_contract_class:: Program as DeprecatedProgram ;
21+ use starknet_api:: execution_resources:: GasAmount ;
2122use starknet_api:: transaction:: fields:: Calldata ;
2223use starknet_types_core:: felt:: Felt ;
2324
@@ -44,6 +45,7 @@ use crate::execution::syscalls::hint_processor::{ENTRYPOINT_NOT_FOUND_ERROR, OUT
4445use crate :: execution:: { deprecated_entry_point_execution, entry_point_execution} ;
4546use crate :: state:: errors:: StateError ;
4647use crate :: state:: state_api:: State ;
48+ use crate :: utils:: { add_gas, u64_from_usize} ;
4749
4850pub 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+ blake_cost:: BASE_STEPS_PARTIAL_MSG + blake_cost:: STEPS_PER_2_U32_REMINDER * ( rem_u32s / 2 )
398+ } ;
399+
400+ n_big_felts * blake_cost:: STEPS_BIG_FELT
401+ + n_small_felts * blake_cost:: STEPS_SMALL_FELT
402+ + base_steps
403+ }
404+
405+ /// Returns the number of BLAKE opcodes needed to hash the given felts.
406+ /// Each BLAKE opcode processes 16 u32s (partial messages are padded).
407+ fn count_blake_opcode ( n_big_felts : usize , n_small_felts : usize ) -> usize {
408+ // Count the total number of u32s to be hashed.
409+ let total_u32s =
410+ n_big_felts * blake_cost:: N_U32S_BIG_FELT + n_small_felts * blake_cost:: N_U32S_SMALL_FELT ;
411+
412+ let full_msgs = total_u32s / blake_cost:: N_U32S_MESSAGE ;
413+ let has_partial = total_u32s % blake_cost:: N_U32S_MESSAGE != 0 ;
414+
415+ if has_partial { full_msgs + 1 } else { full_msgs }
416+ }
417+
418+ /// Estimates the VM resources for `encode_felt252_data_and_calc_blake_hash` in the Starknet OS.
419+ /// Assumes small felts unpack into 2 u32s and big felts into 8 u32s.
420+ pub fn cost_of_encode_felt252_data_and_calc_blake_hash < F > (
421+ n_big_felts : usize ,
422+ n_small_felts : usize ,
423+ resources_to_gas_fn : F ,
424+ ) -> GasAmount
425+ where
426+ F : Fn ( & ExecutionResources ) -> GasAmount ,
427+ {
428+ let n_steps = compute_blake_hash_steps ( n_big_felts, n_small_felts) ;
429+ let n_felts = n_big_felts + n_small_felts;
430+ // One `range_check` per input felt to validate its size.
431+ let builtins = HashMap :: from ( [ ( BuiltinName :: range_check, n_felts) ] ) ;
432+ let resources =
433+ ExecutionResources { n_steps, n_memory_holes : 0 , builtin_instance_counter : builtins } ;
434+ let mut gas = resources_to_gas_fn ( & resources) ;
435+
436+ let blake_op_count = count_blake_opcode ( n_big_felts, n_small_felts) ;
437+ let blake_op_gas = blake_op_count
438+ . checked_mul ( blake_cost:: BLAKE_OPCODE_GAS )
439+ . map ( u64_from_usize)
440+ . map ( GasAmount )
441+ . expect ( "Overflow computing Blake opcode gas." ) ;
442+
443+ add_gas ( & mut gas, blake_op_gas) ;
444+
445+ gas
446+ }
0 commit comments