Skip to content

Commit f79b6de

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

File tree

5 files changed

+90
-25
lines changed

5 files changed

+90
-25
lines changed

crates/apollo_starknet_os_program/build.rs

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

19-
/// Compile the StarkNet OS program.
20-
fn compile_starknet_os() -> Vec<u8> {
27+
fn cairo_root_path() -> PathBuf {
28+
PathBuf::from(compile_time_cargo_manifest_dir!()).join("src/cairo")
29+
}
30+
31+
/// Compile a StarkNet program.
32+
fn compile_starknet_program(path_to_main_file: PathBuf) -> Vec<u8> {
2133
cairo0_compilers_correct_version().unwrap_or_else(|error| {
2234
panic!(
2335
"Failed to verify correct cairo0 package installation. Please make sure you do not \
2436
have a conflicting installation in your {}/bin directory.\nOriginal error: {error:?}.",
2537
std::env::var("CARGO_HOME").unwrap_or("${CARGO_HOME}".to_string())
2638
)
2739
});
28-
let cairo_root_path = PathBuf::from(compile_time_cargo_manifest_dir!()).join("src/cairo");
29-
let os_main_path = cairo_root_path.join("starkware/starknet/core/os/os.cairo");
30-
assert!(os_main_path.exists(), "OS main file does not exist at {os_main_path:?}.");
40+
assert!(
41+
path_to_main_file.exists(),
42+
"Main program file does not exist at {path_to_main_file:?}."
43+
);
3144
let mut compile_os_command = Command::new(CAIRO0_COMPILE);
3245
compile_os_command.args([
33-
os_main_path.to_str().expect("Path is valid unicode."),
46+
path_to_main_file.to_str().expect("Path is valid unicode."),
3447
"--debug_info_with_source",
3548
"--cairo_path",
36-
cairo_root_path.to_str().expect("Path to cairo is valid unicode."),
49+
cairo_root_path().to_str().expect("Path to cairo is valid unicode."),
3750
]);
3851
println!("cargo::warning=Running command {compile_os_command:?}.");
3952
let compile_os_output =
@@ -47,3 +60,13 @@ fn compile_starknet_os() -> Vec<u8> {
4760

4861
compile_os_output.stdout
4962
}
63+
64+
fn compile_starknet_os() -> Vec<u8> {
65+
compile_starknet_program(cairo_root_path().join("starkware/starknet/core/os/os.cairo"))
66+
}
67+
68+
fn compile_starknet_aggregator() -> Vec<u8> {
69+
compile_starknet_program(
70+
cairo_root_path().join("starkware/starknet/core/aggregator/main.cairo"),
71+
)
72+
}

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)