Skip to content

Commit 59e66f7

Browse files
feat(apollo_starknet_os_program): define and implement static ProgramHash
1 parent 751a510 commit 59e66f7

File tree

6 files changed

+99
-0
lines changed

6 files changed

+99
-0
lines changed

Cargo.lock

Lines changed: 4 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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ workspace = true
1111

1212
[dependencies]
1313
cairo-vm.workspace = true
14+
serde = { workspace = true, features = ["derive"] }
15+
serde_json.workspace = true
16+
starknet-types-core.workspace = true
17+
thiserror.workspace = true
1418

1519
[build-dependencies]
1620
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
@@ -2,10 +2,19 @@ use std::sync::LazyLock;
22

33
use cairo_vm::types::program::Program;
44

5+
use crate::program_hash::ProgramHash;
6+
7+
pub mod program_hash;
8+
59
pub const OS_PROGRAM: LazyLock<Program> = LazyLock::new(|| {
610
Program::from_bytes(
711
include_bytes!(concat!(env!("OUT_DIR"), "/starknet_os_bytes")),
812
Some("main"),
913
)
1014
.expect("Failed to load the OS bytes.")
1115
});
16+
17+
pub const PROGRAM_HASH: LazyLock<ProgramHash> = LazyLock::new(|| {
18+
serde_json::from_str(include_str!("program_hash.json"))
19+
.expect("Failed to deserialize program_hash.json.")
20+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"os": "0x4c87691af69c8633ceab827eadea0374d645e315fe69c0ed3ec55803b3fbf0a"
3+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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.into_iter())
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.clone()))
47+
} else {
48+
let mut padded_builtin_bytes = vec![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> =
70+
program_header.into_iter().chain(builtins.into_iter()).chain(data.into_iter()).collect();
71+
Ok(pedersen_hash_chain(data_chain))
72+
}
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)