@@ -18,9 +18,12 @@ 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
25+ use crate :: blockifier_versioned_constants:: VersionedConstants ;
26+ use crate :: bouncer:: vm_resources_to_sierra_gas;
2427use crate :: execution:: call_info:: { CallExecution , CallInfo , Retdata } ;
2528use crate :: execution:: contract_class:: { RunnableCompiledClass , TrackedResource } ;
2629use crate :: execution:: entry_point:: {
@@ -42,8 +45,10 @@ use crate::execution::native::entry_point_execution as native_entry_point_execut
4245use crate :: execution:: stack_trace:: { extract_trailing_cairo1_revert_trace, Cairo1RevertHeader } ;
4346use crate :: execution:: syscalls:: hint_processor:: { ENTRYPOINT_NOT_FOUND_ERROR , OUT_OF_GAS_ERROR } ;
4447use crate :: execution:: { deprecated_entry_point_execution, entry_point_execution} ;
48+ use crate :: fee:: resources;
4549use crate :: state:: errors:: StateError ;
4650use crate :: state:: state_api:: State ;
51+ use crate :: utils:: { add_maps, u64_from_usize} ;
4752
4853pub type Args = Vec < CairoArg > ;
4954
@@ -364,3 +369,84 @@ pub fn poseidon_hash_many_cost(data_length: usize) -> ExecutionResources {
364369 builtin_instance_counter : HashMap :: from ( [ ( BuiltinName :: poseidon, data_length / 2 + 1 ) ] ) ,
365370 }
366371}
372+
373+ mod blake_cost {
374+ // U-32 counts
375+ pub const N_U32S_MESSAGE : usize = 16 ;
376+ pub const N_U32S_BIG_FELT : usize = 8 ;
377+ pub const N_U32S_SMALL_FELT : usize = 2 ;
378+
379+ // Steps counts
380+ pub const STEPS_BIG_FELT : usize = 45 ;
381+ pub const STEPS_SMALL_FELT : usize = 15 ;
382+
383+ // One-time segment setup cost (full vs partial)
384+ pub const BASE_STEPS_FULL_MSG : usize = 217 ;
385+ pub const BASE_STEPS_PARTIAL_MSG : usize = 195 ;
386+ pub const STEPS_PER_2_U32_REMINDER : usize = 3 ;
387+
388+ // TODO(AvivG): This is a placeholder, add the actual gas cost for the BLAKE opcode
389+ pub const BLAKE_OPCODE_GAS : usize = 0 ;
390+ }
391+
392+ /// Estimates the number of VM steps needed to hash the given felts with Blake in Starknet OS.
393+ /// Each small felt unpacks into 2 u32s, and each big felt into 8 u32s.
394+ /// Adds a base cost depending on whether the total fits exactly into full 16-u32 messages.
395+ fn compute_blake_hash_steps ( n_big_felts : usize , n_small_felts : usize ) -> usize {
396+ let total_u32s =
397+ n_big_felts * blake_cost:: N_U32S_BIG_FELT + n_small_felts * blake_cost:: N_U32S_SMALL_FELT ;
398+ let rem_u32s = total_u32s % blake_cost:: N_U32S_MESSAGE ;
399+
400+ let base_steps = if rem_u32s == 0 {
401+ blake_cost:: BASE_STEPS_FULL_MSG
402+ } else {
403+ blake_cost:: BASE_STEPS_PARTIAL_MSG + blake_cost:: STEPS_PER_2_U32_REMINDER * ( rem_u32s / 2 )
404+ } ;
405+
406+ n_big_felts * blake_cost:: STEPS_BIG_FELT
407+ + n_small_felts * blake_cost:: STEPS_SMALL_FELT
408+ + base_steps
409+ }
410+
411+ /// Returns the number of BLAKE opcodes needed to hash the given felts.
412+ /// Each BLAKE opcode processes 16 u32s (partial messages are padded).
413+ fn count_blake_opcode ( n_big_felts : usize , n_small_felts : usize ) -> usize {
414+ // Count the total number of u32s to be hashed.
415+ let total_u32s =
416+ n_big_felts * blake_cost:: N_U32S_BIG_FELT + n_small_felts * blake_cost:: N_U32S_SMALL_FELT ;
417+
418+ let full_msgs = total_u32s / blake_cost:: N_U32S_MESSAGE ;
419+ let has_partial = total_u32s % blake_cost:: N_U32S_MESSAGE != 0 ;
420+
421+ if has_partial { full_msgs + 1 } else { full_msgs }
422+ }
423+
424+ /// Estimates the VM resources for `encode_felt252_data_and_calc_blake_hash` in the Starknet OS.
425+ /// Assumes small felts unpack into 2 u32s and big felts into 8 u32s.
426+ pub fn cost_of_encode_felt252_data_and_calc_blake_hash < F > (
427+ n_big_felts : usize ,
428+ n_small_felts : usize ,
429+ resources_to_gas_fn : F ,
430+ ) -> GasAmount
431+ where
432+ F : Fn ( & ExecutionResources ) -> GasAmount ,
433+ {
434+ let n_steps = compute_blake_hash_steps ( n_big_felts, n_small_felts) ;
435+ let n_felts = n_big_felts + n_small_felts;
436+ // One `range_check` per input felt to validate its size.
437+ let builtins = HashMap :: from ( [ ( BuiltinName :: range_check, n_felts) ] ) ;
438+ let resources =
439+ ExecutionResources { n_steps, n_memory_holes : 0 , builtin_instance_counter : builtins } ;
440+ let resources_gas = resources_to_gas_fn ( & resources) ;
441+
442+ let blake_op_count = count_blake_opcode ( n_big_felts, n_small_felts) ;
443+ let blake_op_gas = blake_op_count
444+ . checked_mul ( blake_cost:: BLAKE_OPCODE_GAS )
445+ . map ( u64_from_usize)
446+ . map ( GasAmount )
447+ . expect ( "Overflow computing Blake opcode gas." ) ;
448+
449+ resources_gas
450+ . checked_add ( blake_op_gas)
451+ . expect ( "Overflow adding Blake opcode gas to VM resource gas." )
452+ }
0 commit comments