diff --git a/machine/src/lib.rs b/machine/src/lib.rs index a07b0ae5..eb76d756 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -3,12 +3,7 @@ extern crate alloc; extern crate self as valida_machine; -use alloc::vec::Vec; - -use byteorder::{ByteOrder, LittleEndian}; - pub use crate::core::Word; -use crate::proof::MachineProof; pub use chip::{BusArgument, Chip, Interaction, InteractionType, ValidaAirBuilder}; pub use p3_field::{ AbstractExtensionField, AbstractField, ExtensionField, Field, PrimeField, PrimeField64, @@ -22,152 +17,20 @@ pub mod config; pub mod core; mod debug_builder; mod folding_builder; +mod machine; +mod program; pub mod proof; mod quotient; mod symbolic; -use crate::config::StarkConfig; pub use advice::*; pub use chip::*; pub use core::*; +pub use machine::*; +pub use program::*; pub const OPERAND_ELEMENTS: usize = 5; pub const INSTRUCTION_ELEMENTS: usize = OPERAND_ELEMENTS + 1; pub const CPU_MEMORY_CHANNELS: usize = 3; pub const MEMORY_CELL_BYTES: usize = 4; pub const LOOKUP_DEGREE_BOUND: usize = 3; - -pub trait Instruction, F: Field> { - const OPCODE: u32; - - fn execute(state: &mut M, ops: Operands); - - fn execute_with_advice( - state: &mut M, - ops: Operands, - _advice: &mut Adv, - ) { - Self::execute(state, ops) - } -} - -#[derive(Copy, Clone, Default, Debug)] -pub struct InstructionWord { - pub opcode: u32, - pub operands: Operands, -} - -impl InstructionWord { - pub fn flatten(&self) -> [F; INSTRUCTION_ELEMENTS] { - let mut result = [F::default(); INSTRUCTION_ELEMENTS]; - result[0] = F::from_canonical_u32(self.opcode); - result[1..].copy_from_slice(&Operands::::from_i32_slice(&self.operands.0).0); - result - } -} - -#[derive(Copy, Clone, Default, Debug)] -pub struct Operands(pub [F; OPERAND_ELEMENTS]); - -impl Operands { - pub fn a(&self) -> F { - self.0[0] - } - pub fn b(&self) -> F { - self.0[1] - } - pub fn c(&self) -> F { - self.0[2] - } - pub fn d(&self) -> F { - self.0[3] - } - pub fn e(&self) -> F { - self.0[4] - } - pub fn is_imm(&self) -> F { - self.0[4] - } - pub fn imm32(&self) -> Word { - Word([self.0[1], self.0[2], self.0[3], self.0[4]]) - } -} - -impl Operands { - pub fn from_i32_slice(slice: &[i32]) -> Self { - let mut operands = [F::zero(); OPERAND_ELEMENTS]; - for (i, &operand) in slice.iter().enumerate() { - let abs = F::from_canonical_u32(operand.abs() as u32); - operands[i] = if operand < 0 { -abs } else { abs }; - } - Self(operands) - } -} - -#[derive(Default, Clone)] -pub struct ProgramROM(pub Vec>); - -impl ProgramROM { - pub fn new(instructions: Vec>) -> Self { - Self(instructions) - } - - pub fn get_instruction(&self, pc: u32) -> &InstructionWord { - &self.0[pc as usize] - } -} - -impl ProgramROM { - pub fn from_machine_code(mc: &[u8]) -> Self { - let mut instructions = Vec::new(); - for chunk in mc.chunks_exact(INSTRUCTION_ELEMENTS * 4) { - instructions.push(InstructionWord { - opcode: LittleEndian::read_u32(&chunk[0..4]), - operands: Operands([ - LittleEndian::read_i32(&chunk[4..8]), - LittleEndian::read_i32(&chunk[8..12]), - LittleEndian::read_i32(&chunk[12..16]), - LittleEndian::read_i32(&chunk[16..20]), - LittleEndian::read_i32(&chunk[20..24]), - ]), - }); - } - Self(instructions) - } - - #[cfg(feature = "std")] - pub fn from_file(filename: &str) -> std::io::Result { - use byteorder::ReadBytesExt; - use std::fs::File; - use std::io::BufReader; - - let file = File::open(filename)?; - let mut reader = BufReader::new(file); - let mut instructions = Vec::new(); - - while let Ok(opcode) = reader.read_u32::() { - let mut operands_arr = [0i32; OPERAND_ELEMENTS]; - for i in 0..OPERAND_ELEMENTS { - operands_arr[i] = reader.read_i32::()?; - } - let operands = Operands(operands_arr); - instructions.push(InstructionWord { opcode, operands }); - } - - Ok(ProgramROM::new(instructions)) - } -} - -pub trait Machine: Sync { - fn run(&mut self, program: &ProgramROM, advice: &mut Adv) - where - Adv: AdviceProvider; - - fn prove(&self, config: &SC) -> MachineProof - where - SC: StarkConfig; - - fn verify(config: &SC, proof: &MachineProof) -> Result<(), ()> - where - SC: StarkConfig; -} diff --git a/machine/src/machine.rs b/machine/src/machine.rs new file mode 100644 index 00000000..02d5719a --- /dev/null +++ b/machine/src/machine.rs @@ -0,0 +1,19 @@ +use crate::config::StarkConfig; +use crate::program::ProgramROM; +use crate::proof::MachineProof; +use crate::AdviceProvider; +use p3_field::Field; + +pub trait Machine: Sync { + fn run(&mut self, program: &ProgramROM, advice: &mut Adv) + where + Adv: AdviceProvider; + + fn prove(&self, config: &SC) -> MachineProof + where + SC: StarkConfig; + + fn verify(config: &SC, proof: &MachineProof) -> Result<(), ()> + where + SC: StarkConfig; +} diff --git a/machine/src/program.rs b/machine/src/program.rs new file mode 100644 index 00000000..5f77e58e --- /dev/null +++ b/machine/src/program.rs @@ -0,0 +1,124 @@ +use crate::{AdviceProvider, Machine, Word, INSTRUCTION_ELEMENTS, OPERAND_ELEMENTS}; +use byteorder::{ByteOrder, LittleEndian}; +use p3_field::Field; + +pub trait Instruction, F: Field> { + const OPCODE: u32; + + fn execute(state: &mut M, ops: Operands); + + fn execute_with_advice( + state: &mut M, + ops: Operands, + _advice: &mut Adv, + ) { + Self::execute(state, ops) + } +} + +#[derive(Copy, Clone, Default, Debug)] +pub struct InstructionWord { + pub opcode: u32, + pub operands: Operands, +} + +impl InstructionWord { + pub fn flatten(&self) -> [F; INSTRUCTION_ELEMENTS] { + let mut result = [F::default(); INSTRUCTION_ELEMENTS]; + result[0] = F::from_canonical_u32(self.opcode); + result[1..].copy_from_slice(&Operands::::from_i32_slice(&self.operands.0).0); + result + } +} + +#[derive(Copy, Clone, Default, Debug)] +pub struct Operands(pub [F; OPERAND_ELEMENTS]); + +impl Operands { + pub fn a(&self) -> F { + self.0[0] + } + pub fn b(&self) -> F { + self.0[1] + } + pub fn c(&self) -> F { + self.0[2] + } + pub fn d(&self) -> F { + self.0[3] + } + pub fn e(&self) -> F { + self.0[4] + } + pub fn is_imm(&self) -> F { + self.0[4] + } + pub fn imm32(&self) -> Word { + Word([self.0[1], self.0[2], self.0[3], self.0[4]]) + } +} + +impl Operands { + pub fn from_i32_slice(slice: &[i32]) -> Self { + let mut operands = [F::zero(); OPERAND_ELEMENTS]; + for (i, &operand) in slice.iter().enumerate() { + let abs = F::from_canonical_u32(operand.abs() as u32); + operands[i] = if operand < 0 { -abs } else { abs }; + } + Self(operands) + } +} + +#[derive(Default, Clone)] +pub struct ProgramROM(pub Vec>); + +impl ProgramROM { + pub fn new(instructions: Vec>) -> Self { + Self(instructions) + } + + pub fn get_instruction(&self, pc: u32) -> &InstructionWord { + &self.0[pc as usize] + } +} + +impl ProgramROM { + pub fn from_machine_code(mc: &[u8]) -> Self { + let mut instructions = Vec::new(); + for chunk in mc.chunks_exact(INSTRUCTION_ELEMENTS * 4) { + instructions.push(InstructionWord { + opcode: LittleEndian::read_u32(&chunk[0..4]), + operands: Operands([ + LittleEndian::read_i32(&chunk[4..8]), + LittleEndian::read_i32(&chunk[8..12]), + LittleEndian::read_i32(&chunk[12..16]), + LittleEndian::read_i32(&chunk[16..20]), + LittleEndian::read_i32(&chunk[20..24]), + ]), + }); + } + Self(instructions) + } + + #[cfg(feature = "std")] + pub fn from_file(filename: &str) -> std::io::Result { + use byteorder::ReadBytesExt; + use std::fs::File; + use std::io::BufReader; + + let file = File::open(filename)?; + let mut reader = BufReader::new(file); + let mut instructions = Vec::new(); + + while let Ok(opcode) = reader.read_u32::() { + let mut operands_arr = [0i32; OPERAND_ELEMENTS]; + for i in 0..OPERAND_ELEMENTS { + operands_arr[i] = reader.read_i32::()?; + } + let operands = Operands(operands_arr); + instructions.push(InstructionWord { opcode, operands }); + } + + Ok(ProgramROM::new(instructions)) + } +}