From 8b75bd959b69efe62607e7a0ba966c49c820b1ae Mon Sep 17 00:00:00 2001 From: Dori Medini Date: Sat, 16 May 2026 13:02:25 +0300 Subject: [PATCH] blockifier,starknet_os: expect the blake constants in tests and check consistency --- crates/blockifier/Cargo.toml | 10 +++++- .../src/execution/casm_hash_estimation.rs | 16 +++++++++ .../execution/casm_hash_estimation_test.rs | 34 +++++++++++++++++++ .../blake2s/blake2s_test.rs | 20 +++++++---- 4 files changed, 73 insertions(+), 7 deletions(-) diff --git a/crates/blockifier/Cargo.toml b/crates/blockifier/Cargo.toml index 18eb9ade6f7..9de2a1409c7 100644 --- a/crates/blockifier/Cargo.toml +++ b/crates/blockifier/Cargo.toml @@ -22,7 +22,14 @@ native_blockifier = [] node_api = [] only-native = ["cairo_native"] reexecution = ["transaction_serde"] -testing = ["blockifier_test_utils", "rand", "rstest", "rstest_reuse", "starknet_api/testing"] +testing = [ + "blockifier_test_utils", + "expect-test", + "rand", + "rstest", + "rstest_reuse", + "starknet_api/testing", +] tracing = [] transaction_serde = [] @@ -56,6 +63,7 @@ derive_more = { workspace = true, features = [ "from", "into_iterator", ] } +expect-test = { workspace = true, optional = true } indexmap.workspace = true itertools.workspace = true keccak.workspace = true diff --git a/crates/blockifier/src/execution/casm_hash_estimation.rs b/crates/blockifier/src/execution/casm_hash_estimation.rs index 5a079238b66..3e411002e8b 100644 --- a/crates/blockifier/src/execution/casm_hash_estimation.rs +++ b/crates/blockifier/src/execution/casm_hash_estimation.rs @@ -237,6 +237,22 @@ impl EstimateCasmHashResources for CasmV1HashResourceEstimate { } } +/// Expected values for the CASM V2 (Blake) hash estimation. +/// Separate module, gated by `testing` feature, to avoid depending on the expect-test crate in +/// production code. Values used in production are defined as constants in the +/// [CasmV2HashResourceEstimate] struct (same names, without the _EXPECT suffix). +#[cfg(any(test, feature = "testing"))] +pub mod expected { + use expect_test::{expect, Expect}; + + pub static STEPS_EMPTY_INPUT_EXPECT: Expect = expect!["169"]; + pub static STEPS_PER_LARGE_FELT_EXPECT: Expect = expect!["45"]; + pub static STEPS_PER_SMALL_FELT_EXPECT: Expect = expect!["15"]; + pub static BASE_STEPS_FULL_MSG_EXPECT: Expect = expect!["216"]; + pub static BASE_STEPS_PARTIAL_MSG_EXPECT: Expect = expect!["194"]; + pub static STEPS_PER_2_U32_REMINDER_EXPECT: Expect = expect!["3"]; +} + pub struct CasmV2HashResourceEstimate {} impl CasmV2HashResourceEstimate { diff --git a/crates/blockifier/src/execution/casm_hash_estimation_test.rs b/crates/blockifier/src/execution/casm_hash_estimation_test.rs index 34e76d9ec29..837bbcaf833 100644 --- a/crates/blockifier/src/execution/casm_hash_estimation_test.rs +++ b/crates/blockifier/src/execution/casm_hash_estimation_test.rs @@ -3,6 +3,14 @@ use pretty_assertions::assert_eq; use starknet_types_core::hash::Blake2Felt252; use crate::execution::call_info::OpcodeName; +use crate::execution::casm_hash_estimation::expected::{ + BASE_STEPS_FULL_MSG_EXPECT, + BASE_STEPS_PARTIAL_MSG_EXPECT, + STEPS_EMPTY_INPUT_EXPECT, + STEPS_PER_2_U32_REMINDER_EXPECT, + STEPS_PER_LARGE_FELT_EXPECT, + STEPS_PER_SMALL_FELT_EXPECT, +}; use crate::execution::casm_hash_estimation::{ CasmV2HashResourceEstimate, EstimateCasmHashResources, @@ -22,6 +30,32 @@ fn test_u32_constants() { assert_eq!(large_u32s.len(), CasmV2HashResourceEstimate::U32_WORDS_PER_LARGE_FELT); } +/// Assert consistency between the blake constants used in production and the expected values +/// reproduced and auto-fixed by tests. +#[test] +fn test_expected_constants() { + macro_rules! assert_eq_expect { + ($expect:expr, $actual:ident) => { + assert_eq!( + $expect.data().parse::().unwrap(), + CasmV2HashResourceEstimate::$actual, + "Expect constant {} is not equal to constant CasmV2HashResourceEstimate::{} ({} \ + != {}). Fix the latter (manually) to match the former.", + stringify!($expect), + stringify!($actual), + $expect.data().parse::().unwrap(), + CasmV2HashResourceEstimate::$actual, + ); + }; + } + assert_eq_expect!(STEPS_EMPTY_INPUT_EXPECT, STEPS_EMPTY_INPUT); + assert_eq_expect!(STEPS_PER_LARGE_FELT_EXPECT, STEPS_PER_LARGE_FELT); + assert_eq_expect!(STEPS_PER_SMALL_FELT_EXPECT, STEPS_PER_SMALL_FELT); + assert_eq_expect!(BASE_STEPS_FULL_MSG_EXPECT, BASE_STEPS_FULL_MSG); + assert_eq_expect!(BASE_STEPS_PARTIAL_MSG_EXPECT, BASE_STEPS_PARTIAL_MSG); + assert_eq_expect!(STEPS_PER_2_U32_REMINDER_EXPECT, STEPS_PER_2_U32_REMINDER); +} + /// Test the edge case of hashing an empty array of felt values. #[test] fn test_zero_inputs() { diff --git a/crates/starknet_os/src/hints/hint_implementation/blake2s/blake2s_test.rs b/crates/starknet_os/src/hints/hint_implementation/blake2s/blake2s_test.rs index 5b793aae7d4..b90f5418531 100644 --- a/crates/starknet_os/src/hints/hint_implementation/blake2s/blake2s_test.rs +++ b/crates/starknet_os/src/hints/hint_implementation/blake2s/blake2s_test.rs @@ -1,5 +1,13 @@ use std::collections::HashMap; +use blockifier::execution::casm_hash_estimation::expected::{ + BASE_STEPS_FULL_MSG_EXPECT, + BASE_STEPS_PARTIAL_MSG_EXPECT, + STEPS_EMPTY_INPUT_EXPECT, + STEPS_PER_2_U32_REMINDER_EXPECT, + STEPS_PER_LARGE_FELT_EXPECT, + STEPS_PER_SMALL_FELT_EXPECT, +}; use blockifier::execution::casm_hash_estimation::{ CasmV2HashResourceEstimate, EstimateCasmHashResources, @@ -95,7 +103,7 @@ fn test_blake_step_constants() { // Test empty input. let steps_empty = cairo_encode_felt252_data_and_calc_blake_hash_steps(&[]); - assert_eq!(steps_empty, CasmV2HashResourceEstimate::STEPS_EMPTY_INPUT); + STEPS_EMPTY_INPUT_EXPECT.assert_eq(&steps_empty.to_string()); // Start with a baseline of one full word. let one_message_large_felts = vec![large_felt; LARGE_FELTS_PER_MESSAGE]; @@ -111,7 +119,7 @@ fn test_blake_step_constants() { .collect::>(), ) - baseline_steps) / LARGE_FELTS_PER_MESSAGE; - assert_eq!(large_felt_overhead, CasmV2HashResourceEstimate::STEPS_PER_LARGE_FELT); + STEPS_PER_LARGE_FELT_EXPECT.assert_eq(&large_felt_overhead.to_string()); // Add another full word of small felts to compute the overhead per small felt. let one_message_small_felts = vec![small_felt; SMALL_FELTS_PER_MESSAGE]; @@ -123,12 +131,12 @@ fn test_blake_step_constants() { .collect::>(), ) - baseline_steps) / SMALL_FELTS_PER_MESSAGE; - assert_eq!(small_felt_overhead, CasmV2HashResourceEstimate::STEPS_PER_SMALL_FELT); + STEPS_PER_SMALL_FELT_EXPECT.assert_eq(&small_felt_overhead.to_string()); // Compute the full-word overhead by subtracting the overhead of one word of large felts, from // the result of exactly one word of large felts. let full_word_overhead = baseline_steps - (large_felt_overhead * LARGE_FELTS_PER_MESSAGE); - assert_eq!(full_word_overhead, CasmV2HashResourceEstimate::BASE_STEPS_FULL_MSG); + BASE_STEPS_FULL_MSG_EXPECT.assert_eq(&full_word_overhead.to_string()); // Compute the two-word partial overhead by computing: // X, one full message of large felts + one half-message of small felts. @@ -153,7 +161,7 @@ fn test_blake_step_constants() { let remainder = one_plus_half_message_plus_small_felt_steps - one_plus_half_message_steps - small_felt_overhead; - assert_eq!(remainder, CasmV2HashResourceEstimate::STEPS_PER_2_U32_REMINDER); + STEPS_PER_2_U32_REMINDER_EXPECT.assert_eq(&remainder.to_string()); // Reuse the above computation to deduce the constant overhead for the case where the input does // not fit into an exact multiple of messages. @@ -162,7 +170,7 @@ fn test_blake_step_constants() { - (SMALL_FELTS_PER_MESSAGE / 2) * (small_felt_overhead + remainder) // Overhead of first (full) message: two large felts. - LARGE_FELTS_PER_MESSAGE * large_felt_overhead; - assert_eq!(partial_message_overhead, CasmV2HashResourceEstimate::BASE_STEPS_PARTIAL_MSG); + BASE_STEPS_PARTIAL_MSG_EXPECT.assert_eq(&partial_message_overhead.to_string()); } /// Test that compares Cairo and Rust implementations of