Skip to content

Commit a1487a4

Browse files
starknet_os: define sha256 batch resources constants
1 parent 65993f8 commit a1487a4

2 files changed

Lines changed: 155 additions & 0 deletions

File tree

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
use std::collections::HashMap;
2+
3+
use apollo_starknet_os_program::OS_PROGRAM_BYTES;
4+
use cairo_vm::types::builtin_name::BuiltinName;
5+
use cairo_vm::types::layout_name::LayoutName;
6+
use cairo_vm::types::relocatable::MaybeRelocatable;
7+
use cairo_vm::vm::runners::cairo_runner::ExecutionResources;
8+
use rand::rngs::StdRng;
9+
use rand::{Rng, SeedableRng};
10+
use starknet_types_core::felt::Felt;
11+
12+
use crate::test_utils::cairo_runner::{
13+
initialize_cairo_runner,
14+
run_cairo_0_entrypoint,
15+
EndpointArg,
16+
EntryPointRunnerConfig,
17+
ImplicitArg,
18+
ValueArg,
19+
};
20+
use crate::test_utils::{SHA256_BATCH_RESOURCES_CONSTANT, SHA256_BATCH_RESOURCES_LINEAR};
21+
22+
/// SHA-256 block compression: takes 8 u32 state words and 16 u32 message words, returns the
23+
/// new 8 u32 state. Wraps `sha2::compress256` (message words are big-endian per the SHA-256 spec).
24+
fn sha_256_update_state(state: &[u32; 8], message: &[u32; 16]) -> [u32; 8] {
25+
let block = sha2::digest::generic_array::GenericArray::from_exact_iter(
26+
message.iter().flat_map(|word| word.to_be_bytes()),
27+
)
28+
.expect("message is exactly 64 bytes");
29+
let mut new_state = *state;
30+
sha2::compress256(&mut new_state, &[block]);
31+
new_state
32+
}
33+
34+
fn run_finalize_sha256(number_of_blocks: usize) -> ExecutionResources {
35+
// Build the SHA-256 instance array. Each instance is 32 felts:
36+
// [message (16) | initial_state (8) | output_state (8)].
37+
let mut rng = StdRng::seed_from_u64(42);
38+
let mut input: Vec<u32> = Vec::new();
39+
for _ in 0..number_of_blocks {
40+
let random_felts: Vec<u32> = (0..24).map(|_| rng.gen::<u32>()).collect();
41+
input.extend_from_slice(&random_felts);
42+
let len = input.len();
43+
let message: &[u32; 16] = input[len - 24..len - 8].try_into().unwrap();
44+
let state: &[u32; 8] = input[len - 8..].try_into().unwrap();
45+
let output_state = sha_256_update_state(state, message);
46+
input.extend_from_slice(&output_state);
47+
}
48+
49+
let runner_config = EntryPointRunnerConfig {
50+
layout: LayoutName::starknet,
51+
add_main_prefix_to_entrypoint: false,
52+
..Default::default()
53+
};
54+
let implicit_args = [
55+
ImplicitArg::Builtin(BuiltinName::range_check),
56+
ImplicitArg::Builtin(BuiltinName::bitwise),
57+
];
58+
let (mut cairo_runner, program, entrypoint) = initialize_cairo_runner(
59+
&runner_config,
60+
OS_PROGRAM_BYTES,
61+
"starkware.cairo.common.cairo_sha256.sha256_utils.finalize_sha256",
62+
&implicit_args,
63+
HashMap::new(),
64+
)
65+
.unwrap();
66+
67+
let sha256_start = cairo_runner
68+
.vm
69+
.gen_arg(
70+
&input.iter().map(|&word| MaybeRelocatable::Int(Felt::from(word))).collect::<Vec<_>>(),
71+
)
72+
.unwrap()
73+
.get_relocatable()
74+
.unwrap();
75+
let sha256_end = (sha256_start + input.len()).unwrap();
76+
77+
let explicit_args = [
78+
EndpointArg::Value(ValueArg::Single(MaybeRelocatable::RelocatableValue(sha256_start))),
79+
EndpointArg::Value(ValueArg::Single(MaybeRelocatable::RelocatableValue(sha256_end))),
80+
];
81+
run_cairo_0_entrypoint(
82+
entrypoint,
83+
&explicit_args,
84+
&implicit_args,
85+
None,
86+
&mut cairo_runner,
87+
&program,
88+
&runner_config,
89+
&[],
90+
)
91+
.unwrap();
92+
93+
cairo_runner.get_execution_resources().unwrap()
94+
}
95+
96+
/// Tests that the `finalize_sha256` Cairo function from the OS program consumes the expected
97+
/// resources.
98+
#[test]
99+
fn test_finalize_sha256() {
100+
// Sha256 batching resources has a linear factor and a constant factor. Sample the execution at
101+
// two points to compute both factors.
102+
let block_to_round = 7_usize;
103+
let number_of_blocks_1 = 8_usize;
104+
let number_of_rounds_1 = (number_of_blocks_1 - 1) / block_to_round + 1;
105+
let number_of_blocks_2 = number_of_blocks_1 + block_to_round;
106+
let number_of_rounds_2 = (number_of_blocks_2 - 1) / block_to_round + 1;
107+
let resources_1 = run_finalize_sha256(number_of_blocks_1);
108+
let resources_2 = run_finalize_sha256(number_of_blocks_2);
109+
110+
assert_eq!(number_of_rounds_2 - number_of_rounds_1, 1);
111+
let linear_factor = (&resources_2 - &resources_1).filter_unused_builtins();
112+
let constant_factor =
113+
(&resources_1 - &(&linear_factor * number_of_rounds_1)).filter_unused_builtins();
114+
115+
assert_eq!(linear_factor, *SHA256_BATCH_RESOURCES_LINEAR);
116+
assert_eq!(constant_factor, *SHA256_BATCH_RESOURCES_CONSTANT);
117+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,45 @@
1+
use std::collections::BTreeMap;
2+
use std::sync::LazyLock;
3+
4+
use cairo_vm::types::builtin_name::BuiltinName;
5+
use cairo_vm::vm::runners::cairo_runner::ExecutionResources;
6+
7+
use crate::hint_processor::constants::BUILTIN_INSTANCE_SIZES;
8+
19
pub mod cairo_dict;
210
pub mod cairo_runner;
311
pub mod coverage;
412
pub mod errors;
513
#[cfg(test)]
614
pub mod utils;
715
pub mod validations;
16+
17+
#[cfg(test)]
18+
#[path = "resource_utils_test.rs"]
19+
mod resource_utils_test;
20+
21+
// Resources consumed by the SHA-256 batch phase, separated into linear and constant factors.
22+
pub static SHA256_BATCH_RESOURCES_LINEAR: LazyLock<ExecutionResources> =
23+
LazyLock::new(|| ExecutionResources {
24+
n_steps: 11822,
25+
n_memory_holes: 0,
26+
builtin_instance_counter: BTreeMap::from([
27+
(
28+
BuiltinName::bitwise,
29+
7800 / BUILTIN_INSTANCE_SIZES.get(&BuiltinName::bitwise).unwrap(),
30+
),
31+
(
32+
BuiltinName::range_check,
33+
448 / BUILTIN_INSTANCE_SIZES.get(&BuiltinName::range_check).unwrap(),
34+
),
35+
]),
36+
});
37+
pub static SHA256_BATCH_RESOURCES_CONSTANT: LazyLock<ExecutionResources> =
38+
LazyLock::new(|| ExecutionResources {
39+
n_steps: 49,
40+
n_memory_holes: 0,
41+
builtin_instance_counter: BTreeMap::from([(
42+
BuiltinName::range_check,
43+
3 / BUILTIN_INSTANCE_SIZES.get(&BuiltinName::range_check).unwrap(),
44+
)]),
45+
});

0 commit comments

Comments
 (0)