Skip to content

blockifier: move execution utils logic to casm_estimation #8693

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: avivg/blockifier/encode_and_blake_hash_resources_in_trait
Choose a base branch
from

Conversation

avivg-starkware
Copy link
Contributor

No description provided.

@reviewable-StarkWare
Copy link

This change is Reviewable

@avivg-starkware avivg-starkware changed the base branch from avivg/blockifier/move_logic_to_feltsize to graphite-base/8693 August 19, 2025 17:01
@avivg-starkware avivg-starkware force-pushed the avivg/blockfier/move_logic_to_casm_estimation branch from a3db1a9 to 7e2b9a6 Compare August 19, 2025 17:01
@avivg-starkware avivg-starkware changed the base branch from graphite-base/8693 to avivg/blockifier/encode_and_blake_hash_resources_in_trait August 19, 2025 17:01
@avivg-starkware avivg-starkware force-pushed the avivg/blockifier/encode_and_blake_hash_resources_in_trait branch from 1b8280e to e6c3e18 Compare August 20, 2025 07:34
@avivg-starkware avivg-starkware force-pushed the avivg/blockfier/move_logic_to_casm_estimation branch from 7e2b9a6 to a75f17b Compare August 20, 2025 07:34
@avivg-starkware avivg-starkware force-pushed the avivg/blockifier/encode_and_blake_hash_resources_in_trait branch from e6c3e18 to fbdc226 Compare August 20, 2025 07:52
@avivg-starkware avivg-starkware force-pushed the avivg/blockfier/move_logic_to_casm_estimation branch from a75f17b to 2ff9768 Compare August 20, 2025 07:52
@avivg-starkware avivg-starkware force-pushed the avivg/blockifier/encode_and_blake_hash_resources_in_trait branch from fbdc226 to 73a49b2 Compare August 20, 2025 08:12
@avivg-starkware avivg-starkware force-pushed the avivg/blockfier/move_logic_to_casm_estimation branch 2 times, most recently from 25ac177 to c308621 Compare August 20, 2025 08:39
@avivg-starkware avivg-starkware force-pushed the avivg/blockifier/encode_and_blake_hash_resources_in_trait branch from 73a49b2 to c26eb39 Compare August 20, 2025 08:39
@avivg-starkware avivg-starkware force-pushed the avivg/blockfier/move_logic_to_casm_estimation branch 2 times, most recently from 17d92ae to 6bfccae Compare August 20, 2025 10:24
@avivg-starkware avivg-starkware force-pushed the avivg/blockifier/encode_and_blake_hash_resources_in_trait branch from c26eb39 to 6008f4b Compare August 20, 2025 11:16
@avivg-starkware avivg-starkware force-pushed the avivg/blockfier/move_logic_to_casm_estimation branch from 6bfccae to 01152d3 Compare August 20, 2025 11:16
@avivg-starkware avivg-starkware force-pushed the avivg/blockifier/encode_and_blake_hash_resources_in_trait branch from 6008f4b to 35d81db Compare August 20, 2025 12:07
@avivg-starkware avivg-starkware force-pushed the avivg/blockfier/move_logic_to_casm_estimation branch 2 times, most recently from 81fa65b to df203aa Compare August 20, 2025 13:28
@avivg-starkware avivg-starkware force-pushed the avivg/blockifier/encode_and_blake_hash_resources_in_trait branch from 9af27b6 to 6e19b77 Compare August 20, 2025 13:30
@avivg-starkware avivg-starkware force-pushed the avivg/blockfier/move_logic_to_casm_estimation branch from df203aa to 75548a3 Compare August 20, 2025 13:30
Copy link
Contributor

@AvivYossef-starkware AvivYossef-starkware left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AvivYossef-starkware reviewed 2 of 5 files at r1, all commit messages.
Reviewable status: 2 of 5 files reviewed, 3 unresolved discussions (waiting on @noaov1)


crates/blockifier/src/execution/casm_hash_estimation.rs line 227 at r1 (raw file):

    pub const BASE_RANGE_CHECK_NON_EMPTY: usize = 3;
    // Empty input steps.
    pub const STEPS_EMPTY_INPUT: usize = 170;

move those const under impl CasmV2HashResourceEstimate
instead of new mode

Code quote:

    // Per-felt step cost (measured).
    pub const STEPS_BIG_FELT: usize = 45;
    pub const STEPS_SMALL_FELT: usize = 15;

    // One-time overhead.
    // Overhead when input fills a full Blake message (16 u32s).
    pub const BASE_STEPS_FULL_MSG: usize = 217;
    // Overhead when input results in a partial message (remainder < 16 u32s).
    pub const BASE_STEPS_PARTIAL_MSG: usize = 195;
    // Extra steps per 2-u32 remainder in partial messages.
    pub const STEPS_PER_2_U32_REMINDER: usize = 3;
    // Overhead when input for `encode_felt252_data_and_calc_blake_hash` is non-empty.
    pub const BASE_RANGE_CHECK_NON_EMPTY: usize = 3;
    // Empty input steps.
    pub const STEPS_EMPTY_INPUT: usize = 170;

crates/blockifier/src/execution/casm_hash_estimation.rs line 230 at r1 (raw file):

}

fn base_steps_for_blake_hash(n_u32s: usize) -> usize {

plz doc what the function does

Code quote:

base_steps_for_blake_hash

crates/blockifier/src/execution/casm_hash_estimation.rs line 242 at r1 (raw file):

}

fn felts_steps(n_big_felts: usize, n_small_felts: usize) -> usize {

this function should get FeltSizeCount is it happen in a later PR?

Code quote:

felts_steps

crates/blockifier/src/execution/casm_hash_estimation.rs line 242 at r1 (raw file):

}

fn felts_steps(n_big_felts: usize, n_small_felts: usize) -> usize {

plz doc and cosider renaming

Code quote:

felts_steps

crates/blockifier/src/execution/casm_hash_estimation.rs line 329 at r1 (raw file):

        Some(blake_opcode_gas),
    )
}

move everything under impl CasmV2HashResourceEstimate

Code quote:

// Constants used for estimating the cost of BLAKE hashing inside Starknet OS.
// These values are based on empirical measurement by running
// `encode_felt252_data_and_calc_blake_hash` on various combinations of big and small felts.
mod blake_estimation {
    // Per-felt step cost (measured).
    pub const STEPS_BIG_FELT: usize = 45;
    pub const STEPS_SMALL_FELT: usize = 15;

    // One-time overhead.
    // Overhead when input fills a full Blake message (16 u32s).
    pub const BASE_STEPS_FULL_MSG: usize = 217;
    // Overhead when input results in a partial message (remainder < 16 u32s).
    pub const BASE_STEPS_PARTIAL_MSG: usize = 195;
    // Extra steps per 2-u32 remainder in partial messages.
    pub const STEPS_PER_2_U32_REMINDER: usize = 3;
    // Overhead when input for `encode_felt252_data_and_calc_blake_hash` is non-empty.
    pub const BASE_RANGE_CHECK_NON_EMPTY: usize = 3;
    // Empty input steps.
    pub const STEPS_EMPTY_INPUT: usize = 170;
}

fn base_steps_for_blake_hash(n_u32s: usize) -> usize {
    let rem_u32s = n_u32s % FeltSizeCount::U32_WORDS_PER_MESSAGE;
    if rem_u32s == 0 {
        blake_estimation::BASE_STEPS_FULL_MSG
    } else {
        // This computation is based on running blake2s with different inputs.
        // Note: all inputs expand to an even number of u32s --> `rem_u32s` is always even.
        blake_estimation::BASE_STEPS_PARTIAL_MSG
            + (rem_u32s / 2) * blake_estimation::STEPS_PER_2_U32_REMINDER
    }
}

fn felts_steps(n_big_felts: usize, n_small_felts: usize) -> usize {
    let big_steps = n_big_felts
        .checked_mul(blake_estimation::STEPS_BIG_FELT)
        .expect("Overflow computing big felt steps");
    let small_steps = n_small_felts
        .checked_mul(blake_estimation::STEPS_SMALL_FELT)
        .expect("Overflow computing small felt steps");
    big_steps.checked_add(small_steps).expect("Overflow computing total felt steps")
}

/// Estimates the number of VM steps needed to hash the given felts with Blake in Starknet OS.
/// Each small felt unpacks into 2 u32s, and each big felt into 8 u32s.
/// Adds a base cost depending on whether the total fits exactly into full 16-u32 messages.
fn estimate_steps_of_encode_felt252_data_and_calc_blake_hash(
    felt_size_groups: &FeltSizeCount,
) -> usize {
    let total_u32s = felt_size_groups.encoded_u32_len();
    if total_u32s == 0 {
        // The empty input case is a special case.
        return blake_estimation::STEPS_EMPTY_INPUT;
    }

    let base_steps = base_steps_for_blake_hash(total_u32s);
    let felt_steps = felts_steps(felt_size_groups.large, felt_size_groups.small);

    base_steps.checked_add(felt_steps).expect("Overflow computing total Blake hash steps")
}

/// Estimates resource usage for `encode_felt252_data_and_calc_blake_hash` in the Starknet OS.
///
/// # Encoding Details
/// - Small felts → 2 `u32`s each; Big felts → 8 `u32`s each.
/// - Each felt requires one `range_check` operation.
///
/// # Returns:
/// - `ExecutionResources`: VM resource usage (e.g., n_steps, range checks).
/// - `usize`: number of Blake opcodes used, accounted for separately as those are not reported via
///   `ExecutionResources`.
pub fn encode_and_blake_hash_resources(
    felt_size_groups: &FeltSizeCount,
) -> EstimatedExecutionResources {
    let n_steps = estimate_steps_of_encode_felt252_data_and_calc_blake_hash(felt_size_groups);
    let builtin_instance_counter = match felt_size_groups.n_felts() {
        // The empty case does not use builtins at all.
        0 => HashMap::new(),
        // One `range_check` per input felt to validate its size + Overhead for the non empty case.
        _ => HashMap::from([(
            BuiltinName::range_check,
            felt_size_groups.n_felts() + blake_estimation::BASE_RANGE_CHECK_NON_EMPTY,
        )]),
    };

    let resources = ExecutionResources { n_steps, n_memory_holes: 0, builtin_instance_counter };

    EstimatedExecutionResources::V2Hash {
        resources,
        blake_count: felt_size_groups.blake_opcode_count(),
    }
}

/// Converts the execution resources and blake opcode count to L2 gas.
///
/// Used for both Stwo ("proving_gas") and Stone ("sierra_gas") estimations, which differ in
/// builtin costs. This unified logic is valid because only the `range_check` builtin is used,
/// and its cost is identical across provers (see `bouncer.get_tx_weights`).
// TODO(AvivG): Move inside blake estimation struct.
pub fn blake_execution_resources_estimation_to_gas(
    resources: EstimatedExecutionResources,
    versioned_constants: &VersionedConstants,
    blake_opcode_gas: usize,
) -> GasAmount {
    // TODO(AvivG): Remove this once gas computation is separated from resource estimation.
    assert!(
        resources
            .resources()
            .builtin_instance_counter
            .keys()
            .all(|&k| k == BuiltinName::range_check),
        "Expected either empty builtins or only `range_check` builtin, got: {:?}. This breaks the \
         assumption that builtin costs are identical between provers.",
        resources.resources().builtin_instance_counter.keys().collect::<Vec<_>>()
    );

    resources.to_sierra_gas(
        |resources| vm_resources_to_sierra_gas(resources, versioned_constants),
        Some(blake_opcode_gas),
    )
}

crates/blockifier/src/execution/casm_hash_estimation_test.rs line 140 at r1 (raw file):

    assert_eq!(resources.resources(), &expected, "Unexpected resources values for zero-input hash");
    assert_eq!(resources.blake_count(), 0, "Expected zero BLAKE opcodes for zero inputs");
}

Out of scope move it to different PR

Code quote:

#[test]
fn test_u32_constants() {
    // Small value < 2^63, will encode to 2 u32s.
    let small_felt = Felt::ONE;
    // Large value >= 2^63, will encode to 8 u32s (Just above 2^63).
    let big_felt = Felt::from_hex_unchecked("8000000000000001");

    let small_u32s = encode_felts_to_u32s(vec![small_felt]);
    let big_u32s = encode_felts_to_u32s(vec![big_felt]);

    // Blake estimation constants should match the actual encoding.
    assert_eq!(small_u32s.len(), FeltSizeCount::U32_WORDS_PER_SMALL_FELT);
    assert_eq!(big_u32s.len(), FeltSizeCount::U32_WORDS_PER_LARGE_FELT);
}

/// Test the edge case of hashing an empty array of felt values.
#[test]
fn test_zero_inputs() {
    // logic was written.
    let steps = estimate_steps_of_encode_felt252_data_and_calc_blake_hash(&FeltSizeCount {
        large: 0,
        small: 0,
    });
    assert_eq!(steps, STEPS_EMPTY_INPUT, "Unexpected base step cost for zero inputs");

    // No opcodes should be emitted.
    let opcodes = FeltSizeCount::default().blake_opcode_count();
    assert_eq!(opcodes, 0, "Expected zero BLAKE opcodes for zero inputs");

    // Should result in base cost only (no opcode cost).
    let resources = encode_and_blake_hash_resources(&FeltSizeCount::default());
    let expected = ExecutionResources { n_steps: STEPS_EMPTY_INPUT, ..Default::default() };
    assert_eq!(resources.resources(), &expected, "Unexpected resources values for zero-input hash");
    assert_eq!(resources.blake_count(), 0, "Expected zero BLAKE opcodes for zero inputs");
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants