sp1_core_executor/
program.rsuse std::{fs::File, io::Read, str::FromStr};
use crate::{
disassembler::{transpile, Elf},
instruction::Instruction,
RiscvAirId,
};
use hashbrown::HashMap;
use p3_field::Field;
use p3_field::{AbstractExtensionField, PrimeField32};
use p3_maybe_rayon::prelude::IntoParallelIterator;
use p3_maybe_rayon::prelude::{ParallelBridge, ParallelIterator};
use serde::{Deserialize, Serialize};
use sp1_stark::septic_curve::{SepticCurve, SepticCurveComplete};
use sp1_stark::septic_digest::SepticDigest;
use sp1_stark::septic_extension::SepticExtension;
use sp1_stark::InteractionKind;
use sp1_stark::{
air::{MachineAir, MachineProgram},
shape::Shape,
};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Program {
pub instructions: Vec<Instruction>,
pub pc_start: u32,
pub pc_base: u32,
pub memory_image: HashMap<u32, u32>,
pub preprocessed_shape: Option<Shape<RiscvAirId>>,
}
impl Program {
#[must_use]
pub fn new(instructions: Vec<Instruction>, pc_start: u32, pc_base: u32) -> Self {
Self {
instructions,
pc_start,
pc_base,
memory_image: HashMap::new(),
preprocessed_shape: None,
}
}
pub fn from(input: &[u8]) -> eyre::Result<Self> {
let elf = Elf::decode(input)?;
let instructions = transpile(&elf.instructions);
Ok(Program {
instructions,
pc_start: elf.pc_start,
pc_base: elf.pc_base,
memory_image: elf.memory_image,
preprocessed_shape: None,
})
}
pub fn from_elf(path: &str) -> eyre::Result<Self> {
let mut elf_code = Vec::new();
File::open(path)?.read_to_end(&mut elf_code)?;
Program::from(&elf_code)
}
pub fn fixed_log2_rows<F: Field, A: MachineAir<F>>(&self, air: &A) -> Option<usize> {
let id = RiscvAirId::from_str(&air.name()).unwrap();
self.preprocessed_shape.as_ref().map(|shape| {
shape
.log2_height(&id)
.unwrap_or_else(|| panic!("Chip {} not found in specified shape", air.name()))
})
}
#[must_use]
pub fn fetch(&self, pc: u32) -> &Instruction {
let idx = ((pc - self.pc_base) / 4) as usize;
&self.instructions[idx]
}
}
impl<F: PrimeField32> MachineProgram<F> for Program {
fn pc_start(&self) -> F {
F::from_canonical_u32(self.pc_start)
}
fn initial_global_cumulative_sum(&self) -> SepticDigest<F> {
let mut digests: Vec<SepticCurveComplete<F>> = self
.memory_image
.iter()
.par_bridge()
.map(|(&addr, &word)| {
let values = [
(InteractionKind::Memory as u32) << 16,
0,
addr,
word & 255,
(word >> 8) & 255,
(word >> 16) & 255,
(word >> 24) & 255,
];
let x_start =
SepticExtension::<F>::from_base_fn(|i| F::from_canonical_u32(values[i]));
let (point, _, _, _) = SepticCurve::<F>::lift_x(x_start);
SepticCurveComplete::Affine(point.neg())
})
.collect();
digests.push(SepticCurveComplete::Affine(SepticDigest::<F>::zero().0));
SepticDigest(
digests.into_par_iter().reduce(|| SepticCurveComplete::Infinity, |a, b| a + b).point(),
)
}
}