cairo_proof_parser/
program.rs

1use starknet_crypto::{poseidon_hash_many, FieldElement};
2use std::collections::HashMap;
3use std::convert::TryInto;
4
5use crate::parse_raw;
6
7pub struct ExtractProgramResult {
8    pub program: Vec<FieldElement>,
9    pub program_hash: FieldElement,
10}
11
12pub fn extract_program(input: String) -> anyhow::Result<ExtractProgramResult> {
13    // Parse the input string into a proof structure
14    let proof = parse_raw(&input)?;
15
16    // Retrieve the program segment from the proof
17    let program_segment = proof
18        .public_input
19        .segments
20        .first()
21        .ok_or_else(|| anyhow::Error::msg("Program segment not found"))?;
22
23    // Retrieve the execution segment from the proof
24    let execution_segment = proof
25        .public_input
26        .segments
27        .get(1)
28        .ok_or_else(|| anyhow::Error::msg("Execution segment not found"))?;
29
30    // Construct a map for the main page elements
31    let mut main_page_map = HashMap::new();
32    for element in &proof.public_input.main_page {
33        let value_bytes = element.value.to_bytes_be();
34        let padded_value = vec![0u8; 32 - value_bytes.len()]
35            .iter()
36            .chain(value_bytes.iter())
37            .copied()
38            .collect::<Vec<u8>>();
39        let field_element = FieldElement::from_bytes_be(
40            &padded_value.try_into().expect("Failed to convert to array"),
41        )
42        .expect("Failed to convert to FieldElement");
43
44        main_page_map.insert(element.address, field_element);
45    }
46
47    let initial_pc = program_segment.begin_addr;
48    let initial_fp = execution_segment.begin_addr;
49
50    // Extract program bytecode using the address range in the segments
51    let program: Vec<FieldElement> = (initial_pc..(initial_fp - initial_pc - 1))
52        .map(|addr| {
53            *main_page_map
54                .get(&addr)
55                .expect("Address not found in main page map")
56        })
57        .collect();
58
59    // Calculate the Poseidon hash of the program output
60    let program_hash = poseidon_hash_many(&program);
61
62    Ok(ExtractProgramResult {
63        program,
64        program_hash,
65    })
66}