Skip to content

Commit

Permalink
Reorganize a bit more
Browse files Browse the repository at this point in the history
  • Loading branch information
dlubarov committed Jan 24, 2024
1 parent 56a7505 commit 9f2f634
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 141 deletions.
145 changes: 4 additions & 141 deletions machine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<M: Machine<F>, F: Field> {
const OPCODE: u32;

fn execute(state: &mut M, ops: Operands<i32>);

fn execute_with_advice<Adv: AdviceProvider>(
state: &mut M,
ops: Operands<i32>,
_advice: &mut Adv,
) {
Self::execute(state, ops)
}
}

#[derive(Copy, Clone, Default, Debug)]
pub struct InstructionWord<F> {
pub opcode: u32,
pub operands: Operands<F>,
}

impl InstructionWord<i32> {
pub fn flatten<F: Field>(&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::<F>::from_i32_slice(&self.operands.0).0);
result
}
}

#[derive(Copy, Clone, Default, Debug)]
pub struct Operands<F>(pub [F; OPERAND_ELEMENTS]);

impl<F: Copy> Operands<F> {
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<F> {
Word([self.0[1], self.0[2], self.0[3], self.0[4]])
}
}

impl<F: Field> Operands<F> {
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<F>(pub Vec<InstructionWord<F>>);

impl<F> ProgramROM<F> {
pub fn new(instructions: Vec<InstructionWord<F>>) -> Self {
Self(instructions)
}

pub fn get_instruction(&self, pc: u32) -> &InstructionWord<F> {
&self.0[pc as usize]
}
}

impl ProgramROM<i32> {
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<Self> {
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::<LittleEndian>() {
let mut operands_arr = [0i32; OPERAND_ELEMENTS];
for i in 0..OPERAND_ELEMENTS {
operands_arr[i] = reader.read_i32::<LittleEndian>()?;
}
let operands = Operands(operands_arr);
instructions.push(InstructionWord { opcode, operands });
}

Ok(ProgramROM::new(instructions))
}
}

pub trait Machine<F: Field>: Sync {
fn run<Adv>(&mut self, program: &ProgramROM<i32>, advice: &mut Adv)
where
Adv: AdviceProvider;

fn prove<SC>(&self, config: &SC) -> MachineProof<SC>
where
SC: StarkConfig<Val = F>;

fn verify<SC>(config: &SC, proof: &MachineProof<SC>) -> Result<(), ()>
where
SC: StarkConfig<Val = F>;
}
19 changes: 19 additions & 0 deletions machine/src/machine.rs
Original file line number Diff line number Diff line change
@@ -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<F: Field>: Sync {
fn run<Adv>(&mut self, program: &ProgramROM<i32>, advice: &mut Adv)
where
Adv: AdviceProvider;

fn prove<SC>(&self, config: &SC) -> MachineProof<SC>
where
SC: StarkConfig<Val = F>;

fn verify<SC>(config: &SC, proof: &MachineProof<SC>) -> Result<(), ()>
where
SC: StarkConfig<Val = F>;
}
124 changes: 124 additions & 0 deletions machine/src/program.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
use crate::{AdviceProvider, Machine, Word, INSTRUCTION_ELEMENTS, OPERAND_ELEMENTS};
use byteorder::{ByteOrder, LittleEndian};
use p3_field::Field;

pub trait Instruction<M: Machine<F>, F: Field> {
const OPCODE: u32;

fn execute(state: &mut M, ops: Operands<i32>);

fn execute_with_advice<Adv: AdviceProvider>(
state: &mut M,
ops: Operands<i32>,
_advice: &mut Adv,
) {
Self::execute(state, ops)
}
}

#[derive(Copy, Clone, Default, Debug)]
pub struct InstructionWord<F> {
pub opcode: u32,
pub operands: Operands<F>,
}

impl InstructionWord<i32> {
pub fn flatten<F: Field>(&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::<F>::from_i32_slice(&self.operands.0).0);
result
}
}

#[derive(Copy, Clone, Default, Debug)]
pub struct Operands<F>(pub [F; OPERAND_ELEMENTS]);

impl<F: Copy> Operands<F> {
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<F> {
Word([self.0[1], self.0[2], self.0[3], self.0[4]])
}
}

impl<F: Field> Operands<F> {
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<F>(pub Vec<InstructionWord<F>>);

impl<F> ProgramROM<F> {
pub fn new(instructions: Vec<InstructionWord<F>>) -> Self {
Self(instructions)
}

pub fn get_instruction(&self, pc: u32) -> &InstructionWord<F> {
&self.0[pc as usize]
}
}

impl ProgramROM<i32> {
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<Self> {
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::<LittleEndian>() {
let mut operands_arr = [0i32; OPERAND_ELEMENTS];
for i in 0..OPERAND_ELEMENTS {
operands_arr[i] = reader.read_i32::<LittleEndian>()?;
}
let operands = Operands(operands_arr);
instructions.push(InstructionWord { opcode, operands });
}

Ok(ProgramROM::new(instructions))
}
}

0 comments on commit 9f2f634

Please sign in to comment.