Skip to content

Commit 4c99ed7

Browse files
Script to parse blobs and decrypt
1 parent 7193cc2 commit 4c99ed7

File tree

3 files changed

+161
-0
lines changed

3 files changed

+161
-0
lines changed

Cargo.lock

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

crates/starknet_os/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ strum.workspace = true
6060
strum_macros.workspace = true
6161
thiserror.workspace = true
6262
tracing.workspace = true
63+
clap = { workspace = true, features = ["derive"] }
64+
hex.workspace = true
6365

6466
[dev-dependencies]
6567
apollo_infra_utils = { workspace = true, features = ["testing"] }
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
use c_kzg::BYTES_PER_BLOB;
2+
use clap::Parser;
3+
use hex;
4+
use starknet_types_core::felt::Felt;
5+
6+
use starknet_os::hints::hint_implementation::kzg::utils::decode_blobs;
7+
use starknet_os::hints::hint_implementation::state_diff_encryption::utils::{
8+
decrypt_state_diff_from_blobs, DecryptionError,
9+
};
10+
use starknet_os::io::os_output_types::{PartialOsStateDiff, TryFromOutputIter};
11+
12+
#[derive(Parser, Debug)]
13+
#[command(author, version, about, long_about = None)]
14+
struct Args {
15+
/// Path to blob file (hex encoded, one blob per line, or binary file)
16+
#[arg(short, long)]
17+
blob_file: String,
18+
19+
/// Optional private key for decryption (hex format)
20+
#[arg(long)]
21+
private_key: Option<String>,
22+
23+
/// Committee index for decryption (default: 0)
24+
#[arg(long, default_value = "0")]
25+
committee_index: usize,
26+
}
27+
28+
fn main() -> Result<(), Box<dyn std::error::Error>> {
29+
let args = Args::parse();
30+
31+
// Read blobs from file
32+
let blob_data = read_blobs_from_file(&args.blob_file)?;
33+
34+
let private_key = args.private_key.as_ref().map(|key_str| {
35+
Felt::from_hex(key_str)
36+
.expect("Failed to parse private key")
37+
});
38+
39+
parse_blobs_to_state_diff(blob_data, private_key, args.committee_index)
40+
}
41+
42+
fn read_blobs_from_file(file_path: &str) -> Result<Vec<[u8; BYTES_PER_BLOB]>, Box<dyn std::error::Error>> {
43+
use std::fs;
44+
45+
println!("Reading blobs from file: {}", file_path);
46+
47+
let content = fs::read(file_path)?;
48+
49+
// Try to parse as hex strings (one per line)
50+
let lines: Vec<&str> = std::str::from_utf8(&content)?
51+
.lines()
52+
.map(|l| l.trim())
53+
.filter(|l| !l.is_empty())
54+
.collect();
55+
56+
if !lines.is_empty() {
57+
// Try parsing as hex strings
58+
let mut blob_data = Vec::new();
59+
for (i, line) in lines.iter().enumerate() {
60+
let line = line.strip_prefix("0x").unwrap_or(line);
61+
let blob_bytes = hex::decode(line)
62+
.map_err(|e| format!("Failed to decode blob {} from hex: {}", i, e))?;
63+
64+
if blob_bytes.len() != BYTES_PER_BLOB {
65+
return Err(format!(
66+
"Blob {} has wrong size: expected {}, got {}",
67+
i, BYTES_PER_BLOB, blob_bytes.len()
68+
).into());
69+
}
70+
71+
let blob_array: [u8; BYTES_PER_BLOB] = blob_bytes
72+
.try_into()
73+
.map_err(|_| format!("Failed to convert blob {} to array", i))?;
74+
75+
blob_data.push(blob_array);
76+
}
77+
78+
if !blob_data.is_empty() {
79+
println!("Read {} blobs from file", blob_data.len());
80+
return Ok(blob_data);
81+
}
82+
}
83+
84+
// Try parsing as raw binary (must be multiple of BYTES_PER_BLOB)
85+
if content.len() % BYTES_PER_BLOB == 0 {
86+
let num_blobs = content.len() / BYTES_PER_BLOB;
87+
let mut blob_data = Vec::new();
88+
for i in 0..num_blobs {
89+
let start = i * BYTES_PER_BLOB;
90+
let end = start + BYTES_PER_BLOB;
91+
let blob_array: [u8; BYTES_PER_BLOB] = content[start..end]
92+
.try_into()
93+
.map_err(|_| format!("Failed to extract blob {}", i))?;
94+
blob_data.push(blob_array);
95+
}
96+
println!("Read {} blobs from binary file", blob_data.len());
97+
return Ok(blob_data);
98+
}
99+
100+
Err(format!(
101+
"File size {} is not a multiple of blob size {}",
102+
content.len(), BYTES_PER_BLOB
103+
).into())
104+
}
105+
106+
/// Helper function to parse blobs once we have the raw blob data
107+
fn parse_blobs_to_state_diff(
108+
blob_data: Vec<[u8; BYTES_PER_BLOB]>,
109+
private_key: Option<Felt>,
110+
committee_index: usize,
111+
) -> Result<(), Box<dyn std::error::Error>> {
112+
println!("Decoding {} blobs...", blob_data.len());
113+
114+
// If we have a private key, try decryption first
115+
if let Some(private_key) = private_key {
116+
println!("\n=== Attempting decryption with private key ===");
117+
match decrypt_state_diff_from_blobs(blob_data.clone(), private_key, committee_index) {
118+
Ok(state_diff) => {
119+
println!("✓ Successfully decrypted and parsed as PartialOsStateDiff!");
120+
println!(" Contracts: {}", state_diff.contracts.len());
121+
println!(" Classes: {}", state_diff.classes.len());
122+
println!("The PartialOsStateDiff is: {:#?}", state_diff);
123+
return Ok(());
124+
}
125+
Err(DecryptionError::Fft(e)) => {
126+
println!("✗ FFT error during decryption: {}", e);
127+
println!(" Trying without decryption...");
128+
}
129+
Err(DecryptionError::Parsing(e)) => {
130+
println!("✗ Parsing error after decryption: {}", e);
131+
println!(" Trying without decryption...");
132+
}
133+
}
134+
}
135+
136+
// Decode blobs without decryption
137+
let decoded_felts = decode_blobs(blob_data)?;
138+
println!("Decoded {} field elements", decoded_felts.len());
139+
140+
// Try parsing as PartialOsStateDiff (with decompression)
141+
println!("\n=== Attempting to parse as PartialOsStateDiff ===");
142+
let mut iter = decoded_felts.iter().copied();
143+
match PartialOsStateDiff::try_from_output_iter(&mut iter, None) {
144+
Ok(state_diff) => {
145+
println!("✓ Successfully parsed as PartialOsStateDiff!");
146+
println!(" Contracts: {}", state_diff.contracts.len());
147+
println!(" Classes: {}", state_diff.classes.len());
148+
println!("The PartialOsStateDiff is: {:#?}", state_diff);
149+
Ok(())
150+
}
151+
Err(e) => {
152+
println!("✗ Failed to parse as PartialOsStateDiff: {}", e);
153+
Err(format!("Failed to parse blobs as PartialOsStateDiff: {}", e).into())
154+
}
155+
}
156+
}
157+

0 commit comments

Comments
 (0)