sp1_core_executor/program.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
//! Programs that can be executed by the SP1 zkVM.
use std::{fs::File, io::Read};
use hashbrown::HashMap;
use p3_field::Field;
use serde::{Deserialize, Serialize};
use sp1_stark::air::{MachineAir, MachineProgram};
use crate::{
disassembler::{transpile, Elf},
instruction::Instruction,
CoreShape,
};
/// A program that can be executed by the SP1 zkVM.
///
/// Contains a series of instructions along with the initial memory image. It also contains the
/// start address and base address of the program.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Program {
/// The instructions of the program.
pub instructions: Vec<Instruction>,
/// The start address of the program.
pub pc_start: u32,
/// The base address of the program.
pub pc_base: u32,
/// The initial memory image, useful for global constants.
pub memory_image: HashMap<u32, u32>,
/// The shape for the preprocessed tables.
pub preprocessed_shape: Option<CoreShape>,
}
impl Program {
/// Create a new [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,
}
}
/// Disassemble a RV32IM ELF to a program that be executed by the VM.
///
/// # Errors
///
/// This function may return an error if the ELF is not valid.
pub fn from(input: &[u8]) -> eyre::Result<Self> {
// Decode the bytes as an ELF.
let elf = Elf::decode(input)?;
// Transpile the RV32IM instructions.
let instructions = transpile(&elf.instructions);
// Return the program.
Ok(Program {
instructions,
pc_start: elf.pc_start,
pc_base: elf.pc_base,
memory_image: elf.memory_image,
preprocessed_shape: None,
})
}
/// Disassemble a RV32IM ELF to a program that be executed by the VM from a file path.
///
/// # Errors
///
/// This function will return an error if the file cannot be opened or read.
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)
}
/// Custom logic for padding the trace to a power of two according to the proof shape.
pub fn fixed_log2_rows<F: Field, A: MachineAir<F>>(&self, air: &A) -> Option<usize> {
self.preprocessed_shape
.as_ref()
.map(|shape| {
shape
.inner
.get(&air.name())
.unwrap_or_else(|| panic!("Chip {} not found in specified shape", air.name()))
})
.copied()
}
}
impl<F: Field> MachineProgram<F> for Program {
fn pc_start(&self) -> F {
F::from_canonical_u32(self.pc_start)
}
}