Skip to content

Commit cf90eea

Browse files
feat(apollo_starknet_os_program): add aggregator program + program hash(es)
1 parent 1cd12cf commit cf90eea

File tree

5 files changed

+83
-24
lines changed

5 files changed

+83
-24
lines changed

crates/apollo_starknet_os_program/build.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,25 @@ use apollo_infra_utils::compile_time_cargo_manifest_dir;
66
/// Build script for the `apollo_starknet_os_program` crate.
77
/// Recompiles the OS program if the source files change.
88
fn main() {
9-
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR not set.");
9+
let out_dir = PathBuf::from(std::env::var("OUT_DIR").expect("OUT_DIR not set."));
10+
1011
println!("cargo::warning=Compiling Starknet OS program...");
1112
let starknet_os_bytes = compile_starknet_os();
1213
println!("cargo::warning=Done. Writing compiled bytes to output directory.");
13-
let starknet_os_bytes_path = PathBuf::from(out_dir).join("starknet_os_bytes");
14+
let starknet_os_bytes_path = out_dir.join("starknet_os_bytes");
1415
std::fs::write(&starknet_os_bytes_path, &starknet_os_bytes)
1516
.expect("Failed to write the compiled OS bytes to the output directory.");
17+
18+
println!("cargo::warning=Compiling Starknet aggregator program...");
19+
let starknet_aggregator_bytes = compile_starknet_aggregator();
20+
println!("cargo::warning=Done. Writing compiled bytes to output directory.");
21+
let starknet_aggregator_bytes_path = out_dir.join("starknet_aggregator_bytes");
22+
std::fs::write(&starknet_aggregator_bytes_path, &starknet_aggregator_bytes)
23+
.expect("Failed to write the compiled aggregator bytes to the output directory.");
1624
}
1725

18-
/// Compile the StarkNet OS program.
19-
fn compile_starknet_os() -> Vec<u8> {
20-
let cairo_root_path = PathBuf::from(compile_time_cargo_manifest_dir!()).join("src/cairo");
21-
let os_main_path = cairo_root_path.join("starkware/starknet/core/os/os.cairo");
22-
match compile_cairo0_program(os_main_path, cairo_root_path) {
26+
fn compile_program(path_to_main_file: PathBuf) -> Vec<u8> {
27+
match compile_cairo0_program(path_to_main_file, cairo_root_path()) {
2328
Ok(bytes) => bytes,
2429
Err(Cairo0CompilerError::Cairo0CompilerVersion(error)) => {
2530
panic!(
@@ -30,7 +35,19 @@ fn compile_starknet_os() -> Vec<u8> {
3035
)
3136
}
3237
Err(other_error) => {
33-
panic!("Failed to compile the StarkNet OS program. Error:\n{other_error}.")
38+
panic!("Failed to compile the program. Error:\n{other_error}.")
3439
}
3540
}
3641
}
42+
43+
fn cairo_root_path() -> PathBuf {
44+
PathBuf::from(compile_time_cargo_manifest_dir!()).join("src/cairo")
45+
}
46+
47+
fn compile_starknet_os() -> Vec<u8> {
48+
compile_program(cairo_root_path().join("starkware/starknet/core/os/os.cairo"))
49+
}
50+
51+
fn compile_starknet_aggregator() -> Vec<u8> {
52+
compile_program(cairo_root_path().join("starkware/starknet/core/aggregator/main.cairo"))
53+
}

crates/apollo_starknet_os_program/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@ use crate::program_hash::{ProgramHash, PROGRAM_HASH_PATH};
88
pub mod program_hash;
99

1010
pub const OS_PROGRAM_BYTES: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/starknet_os_bytes"));
11+
pub const AGGREGATOR_PROGRAM_BYTES: &[u8] =
12+
include_bytes!(concat!(env!("OUT_DIR"), "/starknet_aggregator_bytes"));
1113

1214
pub static OS_PROGRAM: LazyLock<Program> = LazyLock::new(|| {
1315
Program::from_bytes(OS_PROGRAM_BYTES, Some("main")).expect("Failed to load the OS bytes.")
1416
});
17+
pub static AGGREGATOR_PROGRAM: LazyLock<Program> = LazyLock::new(|| {
18+
Program::from_bytes(AGGREGATOR_PROGRAM_BYTES, Some("main"))
19+
.expect("Failed to load the aggregator bytes.")
20+
});
1521

1622
pub static PROGRAM_HASH: LazyLock<ProgramHash> = LazyLock::new(|| {
1723
serde_json::from_reader(
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
{
2-
"os": "0x588ec9f078983180b2027b9cdf264cbd1cd6ddf2ca3f3cfabd305f4c7112288"
2+
"os": "0x588ec9f078983180b2027b9cdf264cbd1cd6ddf2ca3f3cfabd305f4c7112288",
3+
"aggregator": "0x30925cb9d051953287ecc2324890442fc41b2e24ef96287158ce3873e34e579",
4+
"aggregator_with_prefix": "0x32ff44735759337ba12dd15b456dc30f64e0ba618b3cf888b267ebfa6de892"
35
}

crates/apollo_starknet_os_program/src/program_hash.rs

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ use std::sync::LazyLock;
44
use apollo_infra_utils::compile_time_cargo_manifest_dir;
55
use cairo_vm::types::builtin_name::BuiltinName;
66
use cairo_vm::types::errors::program_errors::ProgramError;
7+
use cairo_vm::types::program::Program;
78
use serde::{Deserialize, Serialize};
89
use starknet_types_core::felt::Felt;
910
use starknet_types_core::hash::{Pedersen, StarkHash};
1011

11-
use crate::OS_PROGRAM;
12+
use crate::{AGGREGATOR_PROGRAM, OS_PROGRAM};
1213

1314
#[cfg(test)]
1415
#[path = "program_hash_test.rs"]
@@ -31,10 +32,27 @@ pub(crate) static PROGRAM_HASH_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
3132
#[derive(Debug, Deserialize, Serialize, PartialEq)]
3233
pub struct ProgramHash {
3334
pub os: Felt,
35+
pub aggregator: Felt,
36+
pub aggregator_with_prefix: Felt,
37+
}
38+
39+
pub struct AggregatorHash {
40+
pub with_prefix: Felt,
41+
pub without_prefix: Felt,
3442
}
3543

3644
const BOOTLOADER_VERSION: u8 = 0;
3745

46+
fn pad_to_32_bytes(data: &[u8]) -> [u8; 32] {
47+
let mut padded = [0; 32];
48+
let len = data.len();
49+
if len > 32 {
50+
panic!("Data length exceeds 32 bytes.");
51+
}
52+
padded[32 - len..].copy_from_slice(data);
53+
padded
54+
}
55+
3856
fn pedersen_hash_chain(data: Vec<Felt>) -> Felt {
3957
let length = Felt::from(data.len());
4058
vec![length]
@@ -45,35 +63,40 @@ fn pedersen_hash_chain(data: Vec<Felt>) -> Felt {
4563
.expect("Hash data chain is not empty.")
4664
}
4765

48-
pub fn compute_os_program_hash() -> Result<Felt, ProgramHashError> {
49-
let builtins = OS_PROGRAM
66+
fn compute_program_hash(program: &Program) -> Result<Felt, ProgramHashError> {
67+
let builtins = program
5068
.iter_builtins()
5169
.map(|builtin| {
5270
let builtin_bytes = builtin.to_str().to_string().into_bytes();
5371
if builtin_bytes.len() > 32 {
5472
Err(ProgramHashError::BuiltinNameTooLong(*builtin))
5573
} else {
56-
let mut padded_builtin_bytes = [0].repeat(32 - builtin_bytes.len());
57-
padded_builtin_bytes.extend(builtin_bytes);
58-
Ok(Felt::from_bytes_be(
59-
padded_builtin_bytes
60-
.as_slice()
61-
.try_into()
62-
.expect("Padded bytes are 32 bytes long."),
63-
))
74+
Ok(Felt::from_bytes_be(&pad_to_32_bytes(&builtin_bytes)))
6475
}
6576
})
6677
.collect::<Result<Vec<Felt>, _>>()?;
6778
let program_header = vec![
6879
Felt::from(BOOTLOADER_VERSION),
69-
Felt::from(OS_PROGRAM.get_stripped_program()?.main),
80+
Felt::from(program.get_stripped_program()?.main),
7081
Felt::from(builtins.len()),
7182
];
72-
let data = OS_PROGRAM
83+
let data = program
7384
.iter_data()
7485
.map(|data| data.get_int().ok_or(ProgramHashError::UnexpectedRelocatable))
7586
.collect::<Result<Vec<Felt>, _>>()?;
7687

7788
let data_chain: Vec<Felt> = program_header.into_iter().chain(builtins).chain(data).collect();
7889
Ok(pedersen_hash_chain(data_chain))
7990
}
91+
92+
pub fn compute_os_program_hash() -> Result<Felt, ProgramHashError> {
93+
compute_program_hash(&OS_PROGRAM)
94+
}
95+
96+
pub fn compute_aggregator_program_hash() -> Result<AggregatorHash, ProgramHashError> {
97+
let hash = compute_program_hash(&AGGREGATOR_PROGRAM)?;
98+
Ok(AggregatorHash {
99+
with_prefix: Pedersen::hash(&Felt::from_bytes_be(&pad_to_32_bytes(b"AGGREGATOR")), &hash),
100+
without_prefix: hash,
101+
})
102+
}

crates/apollo_starknet_os_program/src/program_hash_test.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
use crate::program_hash::{compute_os_program_hash, ProgramHash, PROGRAM_HASH_PATH};
1+
use crate::program_hash::{
2+
compute_aggregator_program_hash,
3+
compute_os_program_hash,
4+
AggregatorHash,
5+
ProgramHash,
6+
PROGRAM_HASH_PATH,
7+
};
28
use crate::PROGRAM_HASH;
39

410
/// Asserts the program hash of the compiled Starknet OS program matches the program hash in the
@@ -9,7 +15,12 @@ use crate::PROGRAM_HASH;
915
/// ```
1016
#[test]
1117
fn test_program_hash() {
12-
let computed_hash = ProgramHash { os: compute_os_program_hash().unwrap() };
18+
let AggregatorHash { with_prefix, without_prefix } = compute_aggregator_program_hash().unwrap();
19+
let computed_hash = ProgramHash {
20+
os: compute_os_program_hash().unwrap(),
21+
aggregator: without_prefix,
22+
aggregator_with_prefix: with_prefix,
23+
};
1324
if std::env::var("FIX_PROGRAM_HASH").is_ok() {
1425
std::fs::write(
1526
PROGRAM_HASH_PATH.as_path(),

0 commit comments

Comments
 (0)