diff --git a/runnair/crates/runner/src/lib.rs b/runnair/crates/runner/src/lib.rs index eb291915..088c2af0 100644 --- a/runnair/crates/runner/src/lib.rs +++ b/runnair/crates/runner/src/lib.rs @@ -1 +1,2 @@ pub mod memory; +pub mod vm; diff --git a/runnair/crates/runner/src/memory/mod.rs b/runnair/crates/runner/src/memory/mod.rs index b66cc608..fa5584a7 100644 --- a/runnair/crates/runner/src/memory/mod.rs +++ b/runnair/crates/runner/src/memory/mod.rs @@ -5,12 +5,25 @@ use std::ops::Index; use stwo_prover::core::fields::m31::M31; use stwo_prover::core::fields::qm31::QM31; -use self::relocatable::{MaybeRelocatable, RelocationTable}; +use self::relocatable::{assert_and_project, MaybeRelocatable, RelocationTable}; pub mod relocatable; -type MaybeRelocatableAddr = MaybeRelocatable; -type MaybeRelocatableValue = MaybeRelocatable; +pub type MaybeRelocatableAddr = MaybeRelocatable; +pub type MaybeRelocatableValue = MaybeRelocatable; + +impl From for MaybeRelocatableAddr { + fn from(value: MaybeRelocatableValue) -> Self { + match value { + MaybeRelocatableValue::Relocatable(relocatable) => { + MaybeRelocatableAddr::Relocatable(relocatable) + } + MaybeRelocatableValue::Absolute(value) => { + MaybeRelocatable::Absolute(assert_and_project(value)) + } + } + } +} #[derive(Debug, Clone, Default)] pub struct Memory { @@ -85,7 +98,7 @@ mod test { memory.insert(Relocatable::from((0, 0)), QM31::zero()); memory.insert(Relocatable::from((1, 1)), Relocatable::from((1, 12))); - let table = [(0, 1), (1, 1234)].iter().cloned().collect(); + let table = [(0, M31(1)), (1, M31(1234))].iter().cloned().collect(); memory.relocate(&table); diff --git a/runnair/crates/runner/src/memory/relocatable.rs b/runnair/crates/runner/src/memory/relocatable.rs index fad16a28..fb4514b6 100644 --- a/runnair/crates/runner/src/memory/relocatable.rs +++ b/runnair/crates/runner/src/memory/relocatable.rs @@ -1,26 +1,31 @@ use std::collections::HashMap; +use std::ops::{Add, Mul}; + +use num_traits::Zero; +use stwo_prover::core::fields::m31::M31; +use stwo_prover::core::fields::qm31::QM31; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Relocatable { segment: isize, - offset: u32, + offset: M31, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum MaybeRelocatable> { +pub enum MaybeRelocatable> { Relocatable(Relocatable), Absolute(T), } -pub type RelocationTable = HashMap; +pub type RelocationTable = HashMap; impl Relocatable { - pub fn relocate(&self, table: &RelocationTable) -> u32 { + pub fn relocate(&self, table: &RelocationTable) -> M31 { table[&self.segment] + self.offset } } -impl + Copy> MaybeRelocatable { +impl + Copy> MaybeRelocatable { pub fn relocate(&self, table: &RelocationTable) -> T { match self { MaybeRelocatable::Relocatable(relocatable) => relocatable.relocate(table).into(), @@ -29,20 +34,166 @@ impl + Copy> MaybeRelocatable { } } +impl From<(isize, M31)> for Relocatable { + fn from((segment, offset): (isize, M31)) -> Self { + Relocatable { segment, offset } + } +} + impl From<(isize, u32)> for Relocatable { fn from((segment, offset): (isize, u32)) -> Self { - Relocatable { segment, offset } + Relocatable { + segment, + offset: M31(offset), + } } } -impl> From for MaybeRelocatable { +impl> From for MaybeRelocatable { fn from(relocatable: Relocatable) -> Self { MaybeRelocatable::Relocatable(relocatable) } } -impl> From for MaybeRelocatable { +impl> From for MaybeRelocatable { fn from(value: T) -> Self { MaybeRelocatable::Absolute(value) } } + +impl Add for Relocatable { + type Output = Self; + fn add(self, rhs: M31) -> Self { + Self { + segment: self.segment, + offset: self.offset + rhs, + } + } +} + +// TODO(alont): Can this be generalized? +impl Add> for MaybeRelocatable { + type Output = Self; + fn add(self, rhs: Self) -> Self { + match (self, rhs) { + (MaybeRelocatable::Relocatable(lhs), MaybeRelocatable::Absolute(rhs)) => { + MaybeRelocatable::Relocatable(lhs + rhs) + } + (MaybeRelocatable::Absolute(lhs), MaybeRelocatable::Relocatable(rhs)) => { + MaybeRelocatable::Relocatable(rhs + lhs) + } + (MaybeRelocatable::Relocatable(_), MaybeRelocatable::Relocatable(_)) => { + panic!("Cannot add two relocatables.") + } + (MaybeRelocatable::Absolute(lhs), MaybeRelocatable::Absolute(rhs)) => { + MaybeRelocatable::Absolute(lhs + rhs) + } + } + } +} + +/// Assert that the input is in the base field and return the projection to the base field. +pub fn assert_and_project(x: QM31) -> M31 { + assert!(x.1.is_zero()); + assert!(x.0 .1.is_zero()); + x.0 .0 +} + +impl Add> for MaybeRelocatable { + type Output = MaybeRelocatable; + fn add(self, rhs: MaybeRelocatable) -> MaybeRelocatable { + match (self, rhs) { + (MaybeRelocatable::Relocatable(lhs), MaybeRelocatable::Absolute(rhs)) => { + MaybeRelocatable::Relocatable(lhs + assert_and_project(rhs)) + } + (MaybeRelocatable::Absolute(lhs), MaybeRelocatable::Relocatable(rhs)) => { + MaybeRelocatable::Relocatable(rhs + lhs) + } + (MaybeRelocatable::Relocatable(_), MaybeRelocatable::Relocatable(_)) => { + panic!("Cannot add two relocatables.") + } + (MaybeRelocatable::Absolute(lhs), MaybeRelocatable::Absolute(rhs)) => { + MaybeRelocatable::Absolute(lhs + rhs) + } + } + } +} + +impl Add> for MaybeRelocatable { + type Output = Self; + fn add(self, rhs: MaybeRelocatable) -> Self { + match (self, rhs) { + (MaybeRelocatable::Relocatable(lhs), MaybeRelocatable::Absolute(rhs)) => { + MaybeRelocatable::Relocatable(lhs + rhs) + } + (MaybeRelocatable::Absolute(lhs), MaybeRelocatable::Relocatable(rhs)) => { + MaybeRelocatable::Relocatable(rhs + assert_and_project(lhs)) + } + (MaybeRelocatable::Relocatable(_), MaybeRelocatable::Relocatable(_)) => { + panic!("Cannot add two relocatables.") + } + (MaybeRelocatable::Absolute(lhs), MaybeRelocatable::Absolute(rhs)) => { + MaybeRelocatable::Absolute(lhs + rhs) + } + } + } +} + +impl Add> for MaybeRelocatable { + type Output = Self; + fn add(self, rhs: Self) -> Self { + match (self, rhs) { + (MaybeRelocatable::Relocatable(lhs), MaybeRelocatable::Absolute(rhs)) => { + MaybeRelocatable::Relocatable(lhs + assert_and_project(rhs)) + } + (MaybeRelocatable::Absolute(lhs), MaybeRelocatable::Relocatable(rhs)) => { + MaybeRelocatable::Relocatable(rhs + assert_and_project(lhs)) + } + (MaybeRelocatable::Relocatable(_), MaybeRelocatable::Relocatable(_)) => { + panic!("Cannot add two relocatables.") + } + (MaybeRelocatable::Absolute(lhs), MaybeRelocatable::Absolute(rhs)) => { + MaybeRelocatable::Absolute(lhs + rhs) + } + } + } +} + +impl + From> Add for MaybeRelocatable { + type Output = Self; + fn add(self, rhs: M31) -> Self { + match self { + MaybeRelocatable::Relocatable(lhs) => MaybeRelocatable::Relocatable(lhs + rhs), + MaybeRelocatable::Absolute(lhs) => MaybeRelocatable::Absolute(lhs + rhs), + } + } +} + +impl + Mul, S: From> Mul> + for MaybeRelocatable +{ + type Output = MaybeRelocatable; + fn mul(self, rhs: MaybeRelocatable) -> Self::Output { + match (self, rhs) { + (MaybeRelocatable::Relocatable(_), _) => { + panic!("Cannot multiply a relocatable.") + } + (_, MaybeRelocatable::Relocatable(_)) => { + panic!("Cannot multiply a relocatable.") + } + (MaybeRelocatable::Absolute(lhs), MaybeRelocatable::Absolute(rhs)) => { + MaybeRelocatable::Absolute(lhs * rhs) + } + } + } +} + +impl + Mul> Mul for MaybeRelocatable { + type Output = Self; + fn mul(self, rhs: M31) -> Self { + match self { + MaybeRelocatable::Relocatable(_) => panic!("Cannot multiply a relocatable."), + MaybeRelocatable::Absolute(lhs) => MaybeRelocatable::Absolute(lhs * rhs), + } + } +} diff --git a/runnair/crates/runner/src/vm/add_ap.rs b/runnair/crates/runner/src/vm/add_ap.rs new file mode 100644 index 00000000..91a62831 --- /dev/null +++ b/runnair/crates/runner/src/vm/add_ap.rs @@ -0,0 +1,45 @@ +use stwo_prover::core::fields::m31::M31; + +use super::{Instruction, State}; +use crate::memory::relocatable::assert_and_project; +use crate::memory::{MaybeRelocatableValue, Memory}; + +pub fn addap(state: State, summand: M31) -> State { + State { + ap: state.ap + summand, + fp: state.fp, + pc: state.pc, + } +} + +macro_rules! addap_with_operand { + ($instruction:ident, $operand:ident) => { + pub fn $instruction(memory: &mut Memory, state: State, instruction: Instruction) -> State { + if let MaybeRelocatableValue::Absolute(summand) = + crate::vm::operand::$operand(memory, state, &instruction.args) + { + addap(state, assert_and_project(summand)) + } else { + panic!("Can't addap by a relocatable.") + } + } + }; +} + +addap_with_operand!(addap_add_ap_ap, add_ap_ap); +addap_with_operand!(addap_add_ap_fp, add_ap_fp); +addap_with_operand!(addap_add_fp_ap, add_fp_ap); +addap_with_operand!(addap_add_fp_fp, add_fp_fp); +addap_with_operand!(addap_add_imm_ap, add_imm_ap); +addap_with_operand!(addap_add_imm_fp, add_imm_fp); +addap_with_operand!(addap_deref_ap, deref_ap); +addap_with_operand!(addap_deref_fp, deref_fp); +addap_with_operand!(addap_double_deref_ap, double_deref_ap); +addap_with_operand!(addap_double_deref_fp, double_deref_fp); +addap_with_operand!(addap_imm, imm); +addap_with_operand!(addap_mul_ap_ap, mul_ap_ap); +addap_with_operand!(addap_mul_ap_fp, mul_ap_fp); +addap_with_operand!(addap_mul_fp_ap, mul_fp_ap); +addap_with_operand!(addap_mul_fp_fp, mul_fp_fp); +addap_with_operand!(addap_mul_imm_ap, mul_imm_ap); +addap_with_operand!(addap_mul_imm_fp, mul_imm_fp); diff --git a/runnair/crates/runner/src/vm/mod.rs b/runnair/crates/runner/src/vm/mod.rs new file mode 100644 index 00000000..63aa2664 --- /dev/null +++ b/runnair/crates/runner/src/vm/mod.rs @@ -0,0 +1,209 @@ +pub mod add_ap; +pub mod operand; + +use stwo_prover::core::fields::m31::M31; + +use self::add_ap::{ + addap_add_ap_ap, addap_add_ap_fp, addap_add_fp_ap, addap_add_fp_fp, addap_add_imm_ap, + addap_add_imm_fp, addap_deref_ap, addap_deref_fp, addap_double_deref_ap, addap_double_deref_fp, + addap_imm, addap_mul_ap_ap, addap_mul_ap_fp, addap_mul_fp_ap, addap_mul_fp_fp, + addap_mul_imm_ap, addap_mul_imm_fp, +}; +use crate::memory::Memory; + +#[derive(Clone, Copy, Debug)] +pub struct State { + ap: M31, + fp: M31, + pc: M31, +} + +pub struct VM { + memory: Memory, + state: State, +} + +pub type InstructionArgs = [M31; 3]; + +pub struct Instruction { + op: M31, + args: InstructionArgs, +} + +// TODO(alont): autogenerate this. +pub fn opcode_to_instruction(opcode: usize) -> fn(&mut Memory, State, Instruction) -> State { + match opcode { + 0 => addap_add_ap_ap, + 1 => addap_add_ap_fp, + 2 => addap_add_fp_ap, + 3 => addap_add_fp_fp, + 4 => addap_add_imm_ap, + 5 => addap_add_imm_fp, + 6 => addap_deref_ap, + 7 => addap_deref_fp, + 8 => addap_double_deref_ap, + 9 => addap_double_deref_fp, + 10 => addap_imm, + 11 => addap_mul_ap_ap, + 12 => addap_mul_ap_fp, + 13 => addap_mul_fp_ap, + 14 => addap_mul_fp_fp, + 15 => addap_mul_imm_ap, + 16 => addap_mul_imm_fp, + 17 => assert_ap_add_ap_ap, + 18 => assert_ap_add_ap_ap_appp, + 19 => assert_ap_add_ap_fp, + 20 => assert_ap_add_ap_fp_appp, + 21 => assert_ap_add_fp_ap, + 22 => assert_ap_add_fp_ap_appp, + 23 => assert_ap_add_fp_fp, + 24 => assert_ap_add_fp_fp_appp, + 25 => assert_ap_add_imm_ap, + 26 => assert_ap_add_imm_ap_appp, + 27 => assert_ap_add_imm_fp, + 28 => assert_ap_add_imm_fp_appp, + 29 => assert_ap_deref_ap, + 30 => assert_ap_deref_ap_appp, + 31 => assert_ap_deref_fp, + 32 => assert_ap_deref_fp_appp, + 33 => assert_ap_double_deref_ap, + 34 => assert_ap_double_deref_ap_appp, + 35 => assert_ap_double_deref_fp, + 36 => assert_ap_double_deref_fp_appp, + 37 => assert_ap_imm, + 38 => assert_ap_imm_appp, + 39 => assert_ap_mul_ap_ap, + 40 => assert_ap_mul_ap_ap_appp, + 41 => assert_ap_mul_ap_fp, + 42 => assert_ap_mul_ap_fp_appp, + 43 => assert_ap_mul_fp_ap, + 44 => assert_ap_mul_fp_ap_appp, + 45 => assert_ap_mul_fp_fp, + 46 => assert_ap_mul_fp_fp_appp, + 47 => assert_ap_mul_imm_ap, + 48 => assert_ap_mul_imm_ap_appp, + 49 => assert_ap_mul_imm_fp, + 50 => assert_ap_mul_imm_fp_appp, + 51 => assert_fp_add_ap_ap, + 52 => assert_fp_add_ap_ap_appp, + 53 => assert_fp_add_ap_fp, + 54 => assert_fp_add_ap_fp_appp, + 55 => assert_fp_add_fp_ap, + 56 => assert_fp_add_fp_ap_appp, + 57 => assert_fp_add_fp_fp, + 58 => assert_fp_add_fp_fp_appp, + 59 => assert_fp_add_imm_ap, + 60 => assert_fp_add_imm_ap_appp, + 61 => assert_fp_add_imm_fp, + 62 => assert_fp_add_imm_fp_appp, + 63 => assert_fp_deref_ap, + 64 => assert_fp_deref_ap_appp, + 65 => assert_fp_deref_fp, + 66 => assert_fp_deref_fp_appp, + 67 => assert_fp_double_deref_ap, + 68 => assert_fp_double_deref_ap_appp, + 69 => assert_fp_double_deref_fp, + 70 => assert_fp_double_deref_fp_appp, + 71 => assert_fp_imm, + 72 => assert_fp_imm_appp, + 73 => assert_fp_mul_ap_ap, + 74 => assert_fp_mul_ap_ap_appp, + 75 => assert_fp_mul_ap_fp, + 76 => assert_fp_mul_ap_fp_appp, + 77 => assert_fp_mul_fp_ap, + 78 => assert_fp_mul_fp_ap_appp, + 79 => assert_fp_mul_fp_fp, + 80 => assert_fp_mul_fp_fp_appp, + 81 => assert_fp_mul_imm_ap, + 82 => assert_fp_mul_imm_ap_appp, + 83 => assert_fp_mul_imm_fp, + 84 => assert_fp_mul_imm_fp_appp, + 85 => call_abs_ap, + 86 => call_abs_fp, + 87 => call_abs_imm, + 88 => call_rel_ap, + 89 => call_rel_fp, + 90 => call_rel_imm, + 91 => jmp_abs_add_ap_ap, + 92 => jmp_abs_add_ap_ap_appp, + 93 => jmp_abs_add_ap_fp, + 94 => jmp_abs_add_ap_fp_appp, + 95 => jmp_abs_add_fp_ap, + 96 => jmp_abs_add_fp_ap_appp, + 97 => jmp_abs_add_fp_fp, + 98 => jmp_abs_add_fp_fp_appp, + 99 => jmp_abs_add_imm_ap, + 100 => jmp_abs_add_imm_ap_appp, + 101 => jmp_abs_add_imm_fp, + 102 => jmp_abs_add_imm_fp_appp, + 103 => jmp_abs_deref_ap, + 104 => jmp_abs_deref_ap_appp, + 105 => jmp_abs_deref_fp, + 106 => jmp_abs_deref_fp_appp, + 107 => jmp_abs_double_deref_ap, + 108 => jmp_abs_double_deref_ap_appp, + 109 => jmp_abs_double_deref_fp, + 110 => jmp_abs_double_deref_fp_appp, + 111 => jmp_abs_imm, + 112 => jmp_abs_imm_appp, + 113 => jmp_abs_mul_ap_ap, + 114 => jmp_abs_mul_ap_ap_appp, + 115 => jmp_abs_mul_ap_fp, + 116 => jmp_abs_mul_ap_fp_appp, + 117 => jmp_abs_mul_fp_ap, + 118 => jmp_abs_mul_fp_ap_appp, + 119 => jmp_abs_mul_fp_fp, + 120 => jmp_abs_mul_fp_fp_appp, + 121 => jmp_abs_mul_imm_ap, + 122 => jmp_abs_mul_imm_ap_appp, + 123 => jmp_abs_mul_imm_fp, + 124 => jmp_abs_mul_imm_fp_appp, + 125 => jmp_rel_add_ap_ap, + 126 => jmp_rel_add_ap_ap_appp, + 127 => jmp_rel_add_ap_fp, + 128 => jmp_rel_add_ap_fp_appp, + 129 => jmp_rel_add_fp_ap, + 130 => jmp_rel_add_fp_ap_appp, + 131 => jmp_rel_add_fp_fp, + 132 => jmp_rel_add_fp_fp_appp, + 133 => jmp_rel_add_imm_ap, + 134 => jmp_rel_add_imm_ap_appp, + 135 => jmp_rel_add_imm_fp, + 136 => jmp_rel_add_imm_fp_appp, + 137 => jmp_rel_deref_ap, + 138 => jmp_rel_deref_ap_appp, + 139 => jmp_rel_deref_fp, + 140 => jmp_rel_deref_fp_appp, + 141 => jmp_rel_double_deref_ap, + 142 => jmp_rel_double_deref_ap_appp, + 143 => jmp_rel_double_deref_fp, + 144 => jmp_rel_double_deref_fp_appp, + 145 => jmp_rel_imm, + 146 => jmp_rel_imm_appp, + 147 => jmp_rel_mul_ap_ap, + 148 => jmp_rel_mul_ap_ap_appp, + 149 => jmp_rel_mul_ap_fp, + 150 => jmp_rel_mul_ap_fp_appp, + 151 => jmp_rel_mul_fp_ap, + 152 => jmp_rel_mul_fp_ap_appp, + 153 => jmp_rel_mul_fp_fp, + 154 => jmp_rel_mul_fp_fp_appp, + 155 => jmp_rel_mul_imm_ap, + 156 => jmp_rel_mul_imm_ap_appp, + 157 => jmp_rel_mul_imm_fp, + 158 => jmp_rel_mul_imm_fp_appp, + 159 => jnz_ap_ap, + 160 => jnz_ap_ap_appp, + 161 => jnz_ap_fp, + 162 => jnz_ap_fp_appp, + 163 => jnz_fp_ap, + 164 => jnz_fp_ap_appp, + 165 => jnz_fp_fp, + 166 => jnz_fp_fp_appp, + 167 => jnz_imm_ap, + 168 => jnz_imm_ap_appp, + 169 => jnz_imm_fp, + 170 => jnz_imm_fp_appp, + 171 => ret, + } +} diff --git a/runnair/crates/runner/src/vm/operand.rs b/runnair/crates/runner/src/vm/operand.rs new file mode 100644 index 00000000..1dd38ff6 --- /dev/null +++ b/runnair/crates/runner/src/vm/operand.rs @@ -0,0 +1,75 @@ +use stwo_prover::core::fields::m31::M31; + +use super::State; +use crate::memory::{MaybeRelocatableValue, Memory}; + +// Adds: +pub fn add_ap_ap(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[state.ap + args[0]] + memory[state.ap + args[1]] +} + +pub fn add_ap_fp(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[state.ap + args[0]] + memory[state.fp + args[1]] +} + +pub fn add_fp_ap(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[state.fp + args[0]] + memory[state.ap + args[1]] +} + +pub fn add_fp_fp(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[state.fp + args[0]] + memory[state.fp + args[1]] +} + +pub fn add_imm_ap(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[state.ap + args[1]] + args[0] +} + +pub fn add_imm_fp(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[state.fp + args[1]] + args[0] +} + +// Muls: +pub fn mul_ap_ap(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[state.ap + args[0]] * memory[state.ap + args[1]] +} + +pub fn mul_ap_fp(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[state.ap + args[0]] * memory[state.fp + args[1]] +} + +pub fn mul_fp_ap(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[state.fp + args[0]] * memory[state.ap + args[1]] +} + +pub fn mul_fp_fp(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[state.fp + args[0]] * memory[state.fp + args[1]] +} + +pub fn mul_imm_ap(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[state.ap + args[1]] * args[0] +} + +pub fn mul_imm_fp(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[state.fp + args[1]] * args[0] +} + +// Derefs: +pub fn imm(_memory: &Memory, _state: State, args: &[M31]) -> MaybeRelocatableValue { + MaybeRelocatableValue::Absolute(args[0].into()) +} + +pub fn deref_ap(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[state.ap + args[0]] +} + +pub fn deref_fp(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[state.fp + args[0]] +} + +pub fn double_deref_ap(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[memory[state.ap + args[0]] + args[1]] +} + +pub fn double_deref_fp(memory: &Memory, state: State, args: &[M31]) -> MaybeRelocatableValue { + memory[memory[state.fp + args[0]] + args[1]] +}