Skip to content

Commit 7e5d772

Browse files
feat(apollo_starknet_os_program): define and implement static ProgramHash
1 parent 84eeaec commit 7e5d772

File tree

6 files changed

+96
-0
lines changed

6 files changed

+96
-0
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/apollo_starknet_os_program/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ workspace = true
1515

1616
[dependencies]
1717
cairo-vm.workspace = true
18+
serde = { workspace = true, features = ["derive"] }
1819
serde_json.workspace = true
20+
starknet-types-core.workspace = true
21+
thiserror.workspace = true
1922

2023
[build-dependencies]
2124
apollo_infra_utils.workspace = true

crates/apollo_starknet_os_program/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ use std::sync::LazyLock;
44

55
use cairo_vm::types::program::Program;
66

7+
use crate::program_hash::ProgramHash;
8+
9+
pub mod program_hash;
10+
711
#[cfg(feature = "dump_source_files")]
812
pub static CAIRO_FILES_MAP: LazyLock<HashMap<String, String>> = LazyLock::new(|| {
913
serde_json::from_str(include_str!(concat!(env!("OUT_DIR"), "/cairo_files_map.json")))
@@ -17,3 +21,8 @@ pub static OS_PROGRAM: LazyLock<Program> = LazyLock::new(|| {
1721
)
1822
.expect("Failed to load the OS bytes.")
1923
});
24+
25+
pub static PROGRAM_HASH: LazyLock<ProgramHash> = LazyLock::new(|| {
26+
serde_json::from_str(include_str!("program_hash.json"))
27+
.expect("Failed to deserialize program_hash.json.")
28+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"os": "0x1a2e53ac2b85c63107ef7232a6b96ee3d7b7a3fc25e0ba6e223e01a79e3739b"
3+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use cairo_vm::types::builtin_name::BuiltinName;
2+
use cairo_vm::types::errors::program_errors::ProgramError;
3+
use serde::{Deserialize, Serialize};
4+
use starknet_types_core::felt::Felt;
5+
use starknet_types_core::hash::{Pedersen, StarkHash};
6+
7+
use crate::OS_PROGRAM;
8+
9+
#[cfg(test)]
10+
#[path = "program_hash_test.rs"]
11+
pub mod test;
12+
13+
#[derive(thiserror::Error, Debug)]
14+
pub enum ProgramHashError {
15+
#[error("Builtin name is too long: {0}.")]
16+
BuiltinNameTooLong(BuiltinName),
17+
#[error(transparent)]
18+
Program(#[from] ProgramError),
19+
#[error("Program data contains unexpected relocatable.")]
20+
UnexpectedRelocatable,
21+
}
22+
23+
#[derive(Deserialize, Serialize)]
24+
pub struct ProgramHash {
25+
os: Felt,
26+
}
27+
28+
const BOOTLOADER_VERSION: u8 = 0;
29+
30+
fn pedersen_hash_chain(data: Vec<Felt>) -> Felt {
31+
let length = Felt::from(data.len());
32+
vec![length]
33+
.into_iter()
34+
.chain(data)
35+
.rev()
36+
.reduce(|x, y| Pedersen::hash(&y, &x))
37+
.expect("Hash data chain is not empty.")
38+
}
39+
40+
pub fn compute_os_program_hash() -> Result<Felt, ProgramHashError> {
41+
let builtins = OS_PROGRAM
42+
.iter_builtins()
43+
.map(|builtin| {
44+
let builtin_bytes = builtin.to_str().to_string().into_bytes();
45+
if builtin_bytes.len() > 32 {
46+
Err(ProgramHashError::BuiltinNameTooLong(*builtin))
47+
} else {
48+
let mut padded_builtin_bytes = [0].repeat(32 - builtin_bytes.len());
49+
padded_builtin_bytes.extend(builtin_bytes);
50+
Ok(Felt::from_bytes_be(
51+
padded_builtin_bytes
52+
.as_slice()
53+
.try_into()
54+
.expect("Padded bytes are 32 bytes long."),
55+
))
56+
}
57+
})
58+
.collect::<Result<Vec<Felt>, _>>()?;
59+
let program_header = vec![
60+
Felt::from(BOOTLOADER_VERSION),
61+
Felt::from(OS_PROGRAM.get_stripped_program()?.main),
62+
Felt::from(builtins.len()),
63+
];
64+
let data = OS_PROGRAM
65+
.iter_data()
66+
.map(|data| data.get_int().ok_or(ProgramHashError::UnexpectedRelocatable))
67+
.collect::<Result<Vec<Felt>, _>>()?;
68+
69+
let data_chain: Vec<Felt> = program_header.into_iter().chain(builtins).chain(data).collect();
70+
Ok(pedersen_hash_chain(data_chain))
71+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use crate::program_hash::compute_os_program_hash;
2+
use crate::PROGRAM_HASH;
3+
4+
#[test]
5+
fn test_program_hash() {
6+
assert_eq!(compute_os_program_hash().unwrap(), PROGRAM_HASH.os)
7+
}

0 commit comments

Comments
 (0)