Skip to content

Commit b9a5e39

Browse files
blockifier: add fn encode_felt252_data_and_calc_blake_hash_cost
1 parent ed49dcd commit b9a5e39

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-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::{add_gas, 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+
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+
}

crates/blockifier/src/utils.rs

Lines changed: 7 additions & 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;
@@ -105,3 +106,9 @@ where
105106
.or_insert_with(|| value.clone());
106107
}
107108
}
109+
110+
pub fn add_gas(gas: &mut GasAmount, added_gas: GasAmount) {
111+
*gas = gas.checked_add(added_gas).unwrap_or_else(|| {
112+
panic!("add gas amount: overflow when adding {:?} to {:?}", added_gas, gas)
113+
});
114+
}

0 commit comments

Comments
 (0)