sp1_core_executor/
program.rs1use std::{fs::File, io::Read, str::FromStr};
4
5use crate::{
6 disassembler::{transpile, Elf},
7 instruction::Instruction,
8 RiscvAirId,
9};
10use hashbrown::HashMap;
11use p3_field::{AbstractExtensionField, Field, PrimeField32};
12use p3_maybe_rayon::prelude::{IntoParallelIterator, ParallelBridge, ParallelIterator};
13use serde::{Deserialize, Serialize};
14use sp1_stark::{
15 air::{MachineAir, MachineProgram},
16 septic_curve::{SepticCurve, SepticCurveComplete},
17 septic_digest::SepticDigest,
18 septic_extension::SepticExtension,
19 shape::Shape,
20 InteractionKind,
21};
22
23#[derive(Debug, Clone, Default, Serialize, Deserialize)]
28pub struct Program {
29 pub instructions: Vec<Instruction>,
31 pub pc_start: u32,
33 pub pc_base: u32,
35 pub memory_image: HashMap<u32, u32>,
37 pub preprocessed_shape: Option<Shape<RiscvAirId>>,
39}
40
41impl Program {
42 #[must_use]
44 pub fn new(instructions: Vec<Instruction>, pc_start: u32, pc_base: u32) -> Self {
45 Self {
46 instructions,
47 pc_start,
48 pc_base,
49 memory_image: HashMap::new(),
50 preprocessed_shape: None,
51 }
52 }
53
54 pub fn from(input: &[u8]) -> eyre::Result<Self> {
60 let elf = Elf::decode(input)?;
62
63 let instructions = transpile(&elf.instructions);
65
66 Ok(Program {
68 instructions,
69 pc_start: elf.pc_start,
70 pc_base: elf.pc_base,
71 memory_image: elf.memory_image,
72 preprocessed_shape: None,
73 })
74 }
75
76 pub fn from_elf(path: &str) -> eyre::Result<Self> {
82 let mut elf_code = Vec::new();
83 File::open(path)?.read_to_end(&mut elf_code)?;
84 Program::from(&elf_code)
85 }
86
87 pub fn fixed_log2_rows<F: Field, A: MachineAir<F>>(&self, air: &A) -> Option<usize> {
89 let id = RiscvAirId::from_str(&air.name()).unwrap();
90 self.preprocessed_shape.as_ref().map(|shape| {
91 shape
92 .log2_height(&id)
93 .unwrap_or_else(|| panic!("Chip {} not found in specified shape", air.name()))
94 })
95 }
96
97 #[must_use]
98 pub fn fetch(&self, pc: u32) -> &Instruction {
100 let idx = ((pc - self.pc_base) / 4) as usize;
101 &self.instructions[idx]
102 }
103}
104
105impl<F: PrimeField32> MachineProgram<F> for Program {
106 fn pc_start(&self) -> F {
107 F::from_canonical_u32(self.pc_start)
108 }
109
110 fn initial_global_cumulative_sum(&self) -> SepticDigest<F> {
111 let mut digests: Vec<SepticCurveComplete<F>> = self
112 .memory_image
113 .iter()
114 .par_bridge()
115 .map(|(&addr, &word)| {
116 let values = [
117 (InteractionKind::Memory as u32) << 16,
118 0,
119 addr,
120 word & 255,
121 (word >> 8) & 255,
122 (word >> 16) & 255,
123 (word >> 24) & 255,
124 ];
125 let x_start =
126 SepticExtension::<F>::from_base_fn(|i| F::from_canonical_u32(values[i]));
127 let (point, _, _, _) = SepticCurve::<F>::lift_x(x_start);
128 SepticCurveComplete::Affine(point.neg())
129 })
130 .collect();
131 digests.push(SepticCurveComplete::Affine(SepticDigest::<F>::zero().0));
132 SepticDigest(
133 digests.into_par_iter().reduce(|| SepticCurveComplete::Infinity, |a, b| a + b).point(),
134 )
135 }
136}