Skip to content

Commit

Permalink
add memory commitments to trace
Browse files Browse the repository at this point in the history
  • Loading branch information
govereau committed Dec 13, 2023
1 parent 5b7ef5d commit 2a60d91
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 37 deletions.
57 changes: 57 additions & 0 deletions riscv/src/ark_serde.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use std::fmt;
use serde::{Serializer, Deserializer, de::Visitor};
use ark_serialize::{CanonicalSerialize, CanonicalDeserialize};

pub fn serialize<T, S>(t: &T, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: CanonicalSerialize,
{
let mut v = Vec::new();
t.serialize_uncompressed(&mut v)
.map_err(|_| serde::ser::Error::custom("ark error"))?;
s.serialize_bytes(&v)
}

pub fn deserialize<'a, D, T>(d: D) -> Result<T, D::Error>
where
D: Deserializer<'a>,
T: CanonicalDeserialize,
{
let v = d.deserialize_bytes(BV)?;
let t = T::deserialize_uncompressed(v.as_slice())
.map_err(|_| serde::de::Error::custom("ark Error"))?;
Ok(t)
}

struct BV;

impl<'a> Visitor<'a> for BV {
type Value = Vec<u8>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a byte sequence")
}

fn visit_bytes<E: serde::de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
Ok(v.to_vec())
}

fn visit_byte_buf<E: serde::de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
Ok(v)
}

fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'a>,
{
let mut v = Vec::new();
loop {
match seq.next_element() {
Ok(Some(x)) => v.push(x),
Ok(None) => return Ok(v),
Err(e) => return Err(e),
}
}
}
}
7 changes: 5 additions & 2 deletions riscv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
mod error;
pub mod rv32;
pub mod vm;
mod ark_serde;

#[cfg(test)]
mod tests;
Expand Down Expand Up @@ -129,14 +130,16 @@ pub fn eval(vm: &mut VM, show: bool) -> Result<()> {
}

loop {
if show {
print!("{:50} ", vm.inst);
}
eval_inst(vm)?;
if show {
println!("{:50} {:8x} {:8x}", vm.inst, vm.Z, vm.PC);
println!("{:8x} {:8x}", vm.Z, vm.regs.pc);
}
if vm.inst.inst == RV32::UNIMP {
break;
}
eval_writeback(vm);
}

fn table(name: &str, mem: &[u32]) {
Expand Down
58 changes: 33 additions & 25 deletions riscv/src/vm/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ pub struct VM {
pub mem: Memory,
/// current instruction
pub inst: Inst,
/// destination register
pub rd: u32,
/// internal result register
pub Z: u32,
/// internal program counter
pub PC: u32,
/// merkle tree root (if available)
pub root: Option<F>,
/// merkle tree path to instruction (if available)
pub pc_path: Option<Path>,
/// merkle tree path read (if available)
pub read_path: Option<Path>,
/// merkle tree update for write (if available)
pub write_path: Option<(F, Path)>,
}

// ArkWorks macros are not hygenic
Expand Down Expand Up @@ -110,54 +114,54 @@ fn alu_op(aop: AOP, x: u32, y: u32) -> u32 {
}
}

/// finalize previous instruction and update machine state.
pub fn eval_writeback(vm: &mut VM) {
vm.set_reg(vm.rd, vm.Z);
vm.regs.pc = vm.PC;
}

/// evaluate next instruction
pub fn eval_inst(vm: &mut VM) -> Result<()> {
vm.inst = parse_inst(vm.regs.pc, vm.mem.read_cell(vm.regs.pc)?.bytes())?;

// initialize micro-architecture state
vm.rd = 0;
vm.Z = 0;
vm.PC = 0;
vm.root = vm.mem.0.root();
vm.pc_path = vm.mem.0.path(vm.regs.pc);
vm.read_path = None;
vm.write_path = None;

let mut RD = 0u32;
let mut PC = 0;

match vm.inst.inst {
LUI { rd, imm } => {
vm.rd = rd;
RD = rd;
vm.Z = imm;
}
AUIPC { rd, imm } => {
vm.rd = rd;
RD = rd;
vm.Z = add32(vm.regs.pc, imm);
}
JAL { rd, imm } => {
vm.rd = rd;
RD = rd;
vm.Z = add32(vm.regs.pc, 4);
vm.PC = add32(vm.regs.pc, imm);
PC = add32(vm.regs.pc, imm);
}
JALR { rd, rs1, imm } => {
let X = vm.get_reg(rs1);
vm.rd = rd;
RD = rd;
vm.Z = add32(vm.regs.pc, 4);
vm.PC = add32(X, imm);
PC = add32(X, imm);
}
BR { bop, rs1, rs2, imm } => {
let X = vm.get_reg(rs1);
let Y = vm.get_reg(rs2);

if br_op(bop, X, Y) {
vm.PC = add32(vm.regs.pc, imm);
PC = add32(vm.regs.pc, imm);
}
}
LOAD { lop, rd, rs1, imm } => {
let X = vm.get_reg(rs1);
vm.rd = rd;
RD = rd;

let addr = add32(X, imm);
vm.read_path = vm.mem.0.path(addr);
match lop {
LB => vm.Z = vm.mem.lb(addr)?,
LH => vm.Z = vm.mem.lh(addr)?,
Expand All @@ -171,21 +175,23 @@ pub fn eval_inst(vm: &mut VM) -> Result<()> {
let Y = vm.get_reg(rs2);

let addr = add32(X, imm);
vm.read_path = vm.mem.0.path(addr);
match sop {
SB => vm.mem.sb(addr, Y)?,
SH => vm.mem.sh(addr, Y)?,
SW => vm.mem.sw(addr, Y)?,
}
vm.write_path = vm.mem.0.root_path(addr);
}
ALUI { aop, rd, rs1, imm } => {
vm.rd = rd;
RD = rd;
let X = vm.get_reg(rs1);
vm.Z = alu_op(aop, X, imm);
}
ALU { aop, rd, rs1, rs2 } => {
let X = vm.get_reg(rs1);
let Y = vm.get_reg(rs2);
vm.rd = rd;
RD = rd;
vm.Z = alu_op(aop, X, Y);
}
FENCE | EBREAK => {}
Expand All @@ -207,12 +213,14 @@ pub fn eval_inst(vm: &mut VM) -> Result<()> {
}
}
UNIMP => {
vm.PC = vm.inst.pc;
PC = vm.inst.pc;
}
}

if vm.PC == 0 {
vm.PC = add32(vm.inst.pc, vm.inst.len);
if PC == 0 {
PC = add32(vm.inst.pc, vm.inst.len);
}
vm.set_reg(RD, vm.Z);
vm.regs.pc = PC;
Ok(())
}
35 changes: 32 additions & 3 deletions riscv/src/vm/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

use std::collections::BTreeMap;

use ark_bn254::Fr as F;
pub use ark_bn254::Fr as F;
use ark_crypto_primitives::{
sponge::poseidon::{PoseidonConfig, find_poseidon_ark_and_mds},
crh::poseidon,
merkle_tree::{Config, IdentityDigestConverter, MerkleTree},
merkle_tree::{Config, IdentityDigestConverter, MerkleTree, Path as MTPath},
};

use crate::error::*;
Expand Down Expand Up @@ -135,11 +135,30 @@ pub trait Cells {

/// returns a mutable refernce to the cell at address `addr`.
fn cell_mut(&mut self, addr: u32) -> &mut Cell;

/// returns the current merkle-tree root
fn root(&self) -> Option<F> {
None
}

/// returns the merkle-path for an address if available
fn path(&self, _addr: u32) -> Option<Path> {
None
}

/// returns both the root and a path
fn root_path(&self, addr: u32) -> Option<(F, Path)> {
if let (Some(r), Some(p)) = (self.root(), self.path(addr)) {
Some((r, p))
} else {
None
}
}
}

/// The memory of the machine, implemented by a Cell container.
pub struct Memory(Box<dyn Cells>);
pub struct Memory(pub(crate) Box<dyn Cells>);

impl Default for Memory {
fn default() -> Self {
Expand Down Expand Up @@ -297,6 +316,8 @@ impl Config for MTConfig {
type TwoToOneHash = poseidon::TwoToOneCRH<F>;
}

pub type Path = MTPath<MTConfig>;

const FULL_ROUNDS: usize = 8;
const PARTIAL_ROUNDS: usize = 57;
const ALPHA: u64 = 5;
Expand Down Expand Up @@ -345,6 +366,14 @@ impl Cells for MerkleMem {
}
cell
}

fn root(&self) -> Option<F> {
Some(self.tree.root())
}

fn path(&self, addr: u32) -> Option<Path> {
self.tree.generate_proof(addr as usize).ok()
}
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit 2a60d91

Please sign in to comment.