diff --git a/zkmemory/README.md b/zkmemory/README.md index aeded9e..59be553 100644 --- a/zkmemory/README.md +++ b/zkmemory/README.md @@ -1,4 +1,4 @@ -# An universal memory prover in Zero-Knowledge Proof +# A universal memory prover in Zero-Knowledge Proof ## Testing and Coverage @@ -53,24 +53,24 @@ TOTAL 224 43 80.80% 99 ## Overview -The idea is to create an independent module that can be used by any zkVM. You might aware that the memory can be constructed as a simple state machine with `2` instructions `READ` and `WRITE`, and configurable `WORD_SIZE`. Our memory state machine is only able access the exactly `WORD_SIZE` for every executed instruction. That is, if you want to access arbitrary data size, it must be translated to multiple accesses. +The idea is to create an independent module that can be used by any zkVM. You might be aware that the memory can be constructed as a simple state machine with `2` instructions `READ` and `WRITE`, and a configurable `WORD_SIZE`. Our memory state machine is only able to access exactly `WORD_SIZE` bits for every executed instruction. That is, if you want to access arbitrary data sizes, it must be translated to multiple accesses. -These instructions need to be satisfied following conditions: +These instructions need to satisfy the following conditions: - **`READ` instruction** - - `READ` on a memory was not wrote should return `0` - - Every`READ` access for the same location, must have the value to be equal to the previous `WRITE`. + - `READ` on a memory location that has not been written to should return `0` + - Every `READ` access for the same location must return a value equal to the previous `WRITE` - **`WRITE` instruction** - - Every `WRITE` access must write on writable memory chunks _(some areas of the memory might be read only)_. + - Every `WRITE` access must write to writable memory chunks _(some areas of the memory might be read-only)_ ## Features ### Configurable Word Size -For now we support `U256`, `u64`, and `u32` word size. +For now, we support `U256`, `u64`, and `u32` word sizes. -- `U256` word size with this feature it can be generate the execution trace for the following for zkEVM. -- `u64` and `u32` word size allow us to emulate wide range of VM namely RISC-V, x86, ARM, etc. +- `U256` word size: with this feature, it can generate the execution trace for zkEVMs +- `u64` and `u32` word sizes allow us to emulate a wide range of VMs namely RISC-V, x86, ARM, etc. ### Memory Layout @@ -140,10 +140,10 @@ cargo llvm-cov --html --open ## For more detail check `256bits-machine` example -In this example we tried to simulate a 256bits machine with 256bits word size. +In this example, we tried to simulate a 256-bit machine with a 256-bit word size. ```text -cargo run --example 256bits-machine.rs +cargo run --example 256bits-machine ``` ## License diff --git a/zkmemory/examples/256bits-machine.rs b/zkmemory/examples/256bits-machine.rs index 40da4fd..cffdb57 100644 --- a/zkmemory/examples/256bits-machine.rs +++ b/zkmemory/examples/256bits-machine.rs @@ -1,340 +1,103 @@ -use rbtree::RBTree; -use std::{marker::PhantomData, println}; +// Example: 256-bits RAM program using Halo2 proof engine +extern crate alloc; +use alloc::vec; +use ethnum::U256; +use rand::Rng; use zkmemory::{ - base::{Base, B256}, - config::{AllocatedSection, Config, ConfigArgs, DefaultConfig}, - error::Error, - impl_register_machine, impl_stack_machine, impl_state_machine, - machine::{ - AbstractContext, AbstractInstruction, AbstractMachine, CellInteraction, Register, - TraceRecord, - }, + base::B256, config::DefaultConfig, constraints::helper::build_and_test_circuit, + default_state_machine::StandardStateMachine, }; -/// My instruction set for the machine -#[derive(Debug, Clone, Copy)] -pub enum MyInstruction -where - K: Base, - V: Base, -{ - /// Read from memory - Read(K), - /// Write to memory - Write(K, V), - /// Push to stack - Push(V), - /// Pop from stack - Pop(V), - /// Move from register to register (Mov(r2, r1) moves the value of r1 to r2) - Mov(Register, Register), - /// Swap value from top stack to register - Swap(Register), - /// Load from memory to register - Load(Register, K), - /// Save from register to memory - Save(K, Register), - /// Invalid instruction - Invalid(PhantomData), - /// Add two registers, register 1 = register 1 + register 2 - Add(Register, Register), -} - -/// Type alias Instruction -pub type Instruction = MyInstruction, B256, B256, 32, 32>; - -/// RAM Machine -#[derive(Debug, Clone)] -pub struct StateMachine -where - K: Base, - V: Base, -{ - // Memory - memory: RBTree, - memory_allocated: AllocatedSection, - word_size: K, - time_log: u64, - - // Stack - stack_allocated: AllocatedSection, - max_stack_depth: u64, - stack_depth: u64, - stack_ptr: K, - - // Register - register_allocated: AllocatedSection, - - /// Register r0 - pub r0: Register, - /// Register r1 - pub r1: Register, - /// Register r2 - pub r2: Register, - /// Register r3 - pub r3: Register, - - // Trace - execution_trace: RBTree, PhantomData<()>>, -} - -impl AbstractContext for StateMachine -where - Self: core::fmt::Debug - + Sized - + AbstractMachine, - K: Base, - V: Base, - M: AbstractMachine>, -{ - fn set_stack_depth(&mut self, stack_depth: u64) { - self.stack_depth = stack_depth; - } - - fn stack_depth(&self) -> u64 { - self.stack_depth - } - - fn stack_ptr(&self) -> K { - self.stack_ptr - } - - fn time_log(&self) -> u64 { - self.time_log - } - - fn set_time_log(&mut self, time_log: u64) { - self.time_log = time_log; - } - - fn set_stack_ptr(&mut self, stack_ptr: K) { - self.stack_ptr = stack_ptr; - } - - fn memory(&mut self) -> &'_ mut RBTree { - &mut self.memory - } -} - -impl AbstractInstruction - for MyInstruction -where - Self: core::fmt::Debug + Sized, - K: Base, - V: Base, - M: AbstractMachine>, -{ - fn exec(&self, machine: &mut M::Machine) { - match self { - MyInstruction::Invalid(_) => { - panic!("Invalid instruction") - } - MyInstruction::Read(addr) => { - if !machine.memory_allocated.contain(*addr) { - panic!("{}", Error::MemoryAccessDeinied); - } else { - machine.read(*addr).expect("Unable to read to memory"); - } - } - MyInstruction::Write(addr, val) => { - if !machine.memory_allocated.contain(*addr) { - panic!("{}", Error::MemoryAccessDeinied); - } else { - machine - .write(*addr, *val) - .expect("Unable to write to memory"); - } - } - MyInstruction::Push(value) => { - machine.push(*value).expect("Unable to push value to stack"); - } - MyInstruction::Pop(_) => { - machine.pop().expect("Unable to pop value from stack"); - } - MyInstruction::Mov(reg1, reg2) => { - match machine.get(*reg2).expect("Unable to access register 1") { - CellInteraction::SingleCell(_, _, value) => { - machine.set(*reg1, value).expect("Unable to set register 2"); - } - _ => panic!("Register unable to be two cells"), - } - // Mov value from register 2 to register 1 - } - MyInstruction::Swap(reg) => { - match machine.pop().expect("Unable to pop value from stack") { - (_, CellInteraction::SingleCell(_op, _addr, value)) => { - machine - .push(value) - .expect("Unable to push register's value to stack"); - machine.set(*reg, value).expect("Unable to set register"); - } - _ => panic!("Stack unable to be two cells"), - }; - } - MyInstruction::Load(reg, addr) => { - match machine.read(*addr).expect("Unable to read memory") { - CellInteraction::SingleCell(_, _, value) => { - machine.set(*reg, value).expect("Unable to set register"); - } - CellInteraction::DoubleCell(_, _, cvalue, _, _, _, _) => { - machine.set(*reg, cvalue).expect("Unable to set register"); - } - }; - } - MyInstruction::Save(address, reg) => { - match machine.get(*reg).expect("Unable to access register") { - CellInteraction::SingleCell(_, _, value) => { - machine - .write(*address, value) - .expect("Unable to write to memory"); - } - _ => panic!("Register unable to be two cells"), - } - } - MyInstruction::Add(reg1, reg2) => { - match machine.get(*reg1).expect("Unable to access register 1") { - CellInteraction::SingleCell(_, _, value1) => { - match machine.get(*reg2).expect("Unable to access register 2") { - CellInteraction::SingleCell(_, _, value2) => { - machine - .set(*reg1, value1 + value2) - .expect("Unable to set register 1"); - } - _ => panic!("Register unable to be two cells"), - } - } - _ => panic!("Register unable to be two cells"), - } - } - } - } -} - -impl StateMachine -where - K: Base, - V: Base, -{ - /// Create a new RAM machine - pub fn new(config: ConfigArgs) -> Self { - let config = Config::new(K::WORD_SIZE, config); - Self { - // Memory section - memory: RBTree::new(), - memory_allocated: config.memory, - word_size: config.word_size, - time_log: 0, - - // Stack - stack_allocated: config.stack, - max_stack_depth: config.stack_depth.into(), - stack_depth: 0, - stack_ptr: K::zero(), - - // Register - register_allocated: config.register, - r0: config.create_register(0), - r1: config.create_register(1), - r2: config.create_register(2), - r3: config.create_register(3), - - // Execution trace - execution_trace: RBTree::new(), - } - } - - /// Show address maps of memory, stack and registers sections - pub fn show_sections_maps(&self) { - println!( - "Memory section map: from {} to {}", - self.memory_allocated.low(), - self.memory_allocated.high() - ); - println!( - "Register section map: from {} to {}", - self.register_allocated.low(), - self.register_allocated.high() - ); - println!( - "Stack section map: from {} to {}", - self.stack_allocated.low(), - self.stack_allocated.high() - ); - } -} - -impl AbstractMachine for StateMachine -where - K: Base, - V: Base, -{ - type Machine = Self; - type Context = Self; - type Instruction = MyInstruction; - type TraceRecord = TraceRecord; - - fn context(&mut self) -> &'_ mut Self::Context { - self - } - - fn word_size(&self) -> K { - self.word_size - } - - fn register_start(&self) -> K { - self.register_allocated.low() - } - - fn ro_context(&self) -> &'_ Self::Context { - self - } - - fn track(&mut self, trace: Self::TraceRecord) { - self.execution_trace.insert(trace, PhantomData); - } - - fn trace(&self) -> Vec { - self.execution_trace.keys().copied().collect() - } - - fn exec(&mut self, instruction: &Self::Instruction) { - instruction.exec(self); - } - - fn base_address(&self) -> K { - self.memory_allocated.low() - } - - fn get_memory_address(&self) -> (K, K) { - (self.memory_allocated.low(), self.memory_allocated.high()) - } - - fn get_stack_depth(&self) -> u64 { - self.ro_context().stack_depth - } - - fn max_stack_depth(&self) -> u64 { - self.ro_context().max_stack_depth - } -} - -impl_register_machine!(StateMachine); -impl_stack_machine!(StateMachine); -impl_state_machine!(StateMachine); +use zkmemory::{base::Base, default_state_machine::StandardInstruction, machine::AbstractMachine}; +type CustomStateMachine = StandardStateMachine; +type Instruction = StandardInstruction; fn main() { // Define the desired machine configuration - let mut machine = StateMachine::::new(DefaultConfig::default_config()); + let mut machine = CustomStateMachine::new(DefaultConfig::default_config()); // Show the section map - machine.show_sections_maps(); + let sections = machine.get_sections_maps(); + for (i, (start, end)) in sections.iter().enumerate() { + let section_name = match i { + 0 => "Memory", + 1 => "Register", + 2 => "Stack", + _ => "Unknown", + }; + println!("{}: ({}, {})", section_name, start, end); + } + + assert_eq!(sections.len(), 3); + + // Memory section: (33856, 115792089237316195423570985008687907853269984665640564039457584007913129639935) + assert_eq!(sections[0].0, B256::from(33856)); + assert_eq!( + sections[0].1, + B256::from( + U256::from_str_radix( + "115792089237316195423570985008687907853269984665640564039457584007913129639935", + 10 + ) + .unwrap() + .to_be_bytes() + ) + ); + // Register section: (32800, 33824) + assert_eq!(sections[1].0, B256::from(32800)); + assert_eq!(sections[1].1, B256::from(33824)); + // Stack section: (0, 32768) + assert_eq!(sections[2].0, B256::zero()); + assert_eq!(sections[2].1, B256::from(32768)); // Get the base address of the memory section let base = machine.base_address(); - println!("{}", base); + println!("Base address of memory: {}", base); + let mut randomize = rand::thread_rng(); + randomize.gen_range(u64::MAX / 2..u64::MAX); // Define your desired program let program = vec![ + Instruction::Write( + base + B256::from(16), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Write( + base + B256::from(48), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Write( + base + B256::from(80), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Write( + base + B256::from(112), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Write( + base + B256::from(320), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Read(base + B256::from(16)), + Instruction::Write( + base + B256::from(10000), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Read(base + B256::from(48)), + Instruction::Read(base + B256::from(320)), + Instruction::Write( + base + B256::from(10016), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Write( + base + B256::from(10032), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Read(base + B256::from(16)), + Instruction::Read(base + B256::from(48)), + Instruction::Push(B256::from(777)), + Instruction::Swap(machine.r0), + Instruction::Mov(machine.r1, machine.r0), Instruction::Write(base + B256::from(16), B256::from(1025)), Instruction::Write(base + B256::from(48), B256::from(1111)), Instruction::Write(base + B256::from(80), B256::from(1000)), @@ -342,17 +105,19 @@ fn main() { Instruction::Load(machine.r0, base + B256::from(16)), Instruction::Push(B256::from(3735013596u64)), Instruction::Swap(machine.r1), - Instruction::Add(machine.r0, machine.r1), - Instruction::Save(base + B256::from(24), machine.r0), ]; - + let mut trace_record = vec![]; // Execute the program for instruction in program { + println!("Intruction: {:?}", instruction); machine.exec(&instruction); } - - // Print the trace record (prettified), sorted by ascending address by default + // Print the trace record (prettified), sorted by time in ascending order by default for x in machine.trace().into_iter() { println!("{:?}", x); + trace_record.push(x); } + + // If build_and_test_circuit does not panic, then the trace is valid. + build_and_test_circuit(trace_record, 10); } diff --git a/zkmemory/examples/memory-consistency.rs b/zkmemory/src/default_state_machine.rs similarity index 58% rename from zkmemory/examples/memory-consistency.rs rename to zkmemory/src/default_state_machine.rs index cbaf87f..a392a9b 100644 --- a/zkmemory/examples/memory-consistency.rs +++ b/zkmemory/src/default_state_machine.rs @@ -1,10 +1,9 @@ -use rand::Rng; -use rbtree::RBTree; -use std::{marker::PhantomData, println}; -use zkmemory::{ - base::{Base, B256}, - config::{AllocatedSection, Config, ConfigArgs, DefaultConfig}, - constraints::helper::build_and_test_circuit, +extern crate alloc; // Import the alloc crate +use alloc::vec::Vec; + +use crate::{ + base::Base, + config::{AllocatedSection, Config, ConfigArgs}, error::Error, impl_register_machine, impl_stack_machine, impl_state_machine, machine::{ @@ -12,10 +11,12 @@ use zkmemory::{ TraceRecord, }, }; +use core::marker::PhantomData; +use rbtree::RBTree; /// My instruction set for the machine #[derive(Debug, Clone, Copy)] -pub enum MyInstruction +pub enum StandardInstruction where K: Base, V: Base, @@ -42,12 +43,9 @@ where Add(Register, Register), } -/// Type alias Instruction -pub type Instruction = MyInstruction, B256, B256, 32, 32>; - /// RAM Machine #[derive(Debug, Clone)] -pub struct StateMachine +pub struct StandardStateMachine where K: Base, V: Base, @@ -80,14 +78,15 @@ where execution_trace: RBTree, PhantomData<()>>, } -impl AbstractContext for StateMachine +impl AbstractContext + for StandardStateMachine where Self: core::fmt::Debug + Sized + AbstractMachine, K: Base, V: Base, - M: AbstractMachine>, + M: AbstractMachine>, { fn set_stack_depth(&mut self, stack_depth: u64) { self.stack_depth = stack_depth; @@ -119,26 +118,26 @@ where } impl AbstractInstruction - for MyInstruction + for StandardInstruction where Self: core::fmt::Debug + Sized, K: Base, V: Base, - M: AbstractMachine>, + M: AbstractMachine>, { fn exec(&self, machine: &mut M::Machine) { match self { - MyInstruction::Invalid(_) => { + StandardInstruction::Invalid(_) => { panic!("Invalid instruction") } - MyInstruction::Read(addr) => { + StandardInstruction::Read(addr) => { if !machine.memory_allocated.contain(*addr) { panic!("{}", Error::MemoryAccessDeinied); } else { machine.read(*addr).expect("Unable to read to memory"); } } - MyInstruction::Write(addr, val) => { + StandardInstruction::Write(addr, val) => { if !machine.memory_allocated.contain(*addr) { panic!("{}", Error::MemoryAccessDeinied); } else { @@ -147,13 +146,13 @@ where .expect("Unable to write to memory"); } } - MyInstruction::Push(value) => { + StandardInstruction::Push(value) => { machine.push(*value).expect("Unable to push value to stack"); } - MyInstruction::Pop(_) => { + StandardInstruction::Pop(_) => { machine.pop().expect("Unable to pop value from stack"); } - MyInstruction::Mov(reg1, reg2) => { + StandardInstruction::Mov(reg1, reg2) => { match machine.get(*reg2).expect("Unable to access register 1") { CellInteraction::SingleCell(_, _, value) => { machine.set(*reg1, value).expect("Unable to set register 2"); @@ -162,7 +161,7 @@ where } // Mov value from register 2 to register 1 } - MyInstruction::Swap(reg) => { + StandardInstruction::Swap(reg) => { match machine.pop().expect("Unable to pop value from stack") { (_, CellInteraction::SingleCell(_op, _addr, value)) => { machine @@ -173,7 +172,7 @@ where _ => panic!("Stack unable to be two cells"), }; } - MyInstruction::Load(reg, addr) => { + StandardInstruction::Load(reg, addr) => { match machine.read(*addr).expect("Unable to read memory") { CellInteraction::SingleCell(_, _, value) => { machine.set(*reg, value).expect("Unable to set register"); @@ -183,7 +182,7 @@ where } }; } - MyInstruction::Save(address, reg) => { + StandardInstruction::Save(address, reg) => { match machine.get(*reg).expect("Unable to access register") { CellInteraction::SingleCell(_, _, value) => { machine @@ -193,7 +192,7 @@ where _ => panic!("Register unable to be two cells"), } } - MyInstruction::Add(reg1, reg2) => { + StandardInstruction::Add(reg1, reg2) => { match machine.get(*reg1).expect("Unable to access register 1") { CellInteraction::SingleCell(_, _, value1) => { match machine.get(*reg2).expect("Unable to access register 2") { @@ -212,7 +211,7 @@ where } } -impl StateMachine +impl StandardStateMachine where K: Base, V: Base, @@ -244,35 +243,28 @@ where execution_trace: RBTree::new(), } } - /// Show address maps of memory, stack and registers sections - pub fn show_sections_maps(&self) { - println!( - "Memory section map: from {} to {}", - self.memory_allocated.low(), - self.memory_allocated.high() - ); - println!( - "Register section map: from {} to {}", - self.register_allocated.low(), - self.register_allocated.high() - ); - println!( - "Stack section map: from {} to {}", - self.stack_allocated.low(), - self.stack_allocated.high() - ); + pub fn get_sections_maps(&self) -> [(K, K); 3] { + [ + (self.memory_allocated.low(), self.memory_allocated.high()), + ( + self.register_allocated.low(), + self.register_allocated.high(), + ), + (self.stack_allocated.low(), self.stack_allocated.high()), + ] } } -impl AbstractMachine for StateMachine +impl AbstractMachine + for StandardStateMachine where K: Base, V: Base, { type Machine = Self; type Context = Self; - type Instruction = MyInstruction; + type Instruction = StandardInstruction; type TraceRecord = TraceRecord; fn context(&mut self) -> &'_ mut Self::Context { @@ -320,76 +312,109 @@ where } } -impl_register_machine!(StateMachine); -impl_stack_machine!(StateMachine); -impl_state_machine!(StateMachine); - -fn main() { - // Define the desired machine configuration - let mut machine = StateMachine::::new(DefaultConfig::default_config()); - - // Show the section map - machine.show_sections_maps(); - - // Get the base address of the memory section - let base = machine.base_address(); - println!("{}", base); - - let mut randomize = rand::thread_rng(); - randomize.gen_range(u64::MAX / 2..u64::MAX); - // Define your desired program - let program = vec![ - Instruction::Write( - base + B256::from(16), - B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), - ), - Instruction::Write( - base + B256::from(48), - B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), - ), - Instruction::Write( - base + B256::from(80), - B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), - ), - Instruction::Write( - base + B256::from(112), - B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), - ), - Instruction::Write( - base + B256::from(320), - B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), - ), - Instruction::Read(base + B256::from(16)), - Instruction::Write( - base + B256::from(10000), - B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), - ), - Instruction::Read(base + B256::from(48)), - Instruction::Read(base + B256::from(320)), - Instruction::Write( - base + B256::from(10016), - B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), - ), - Instruction::Write( - base + B256::from(10032), - B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), - ), - Instruction::Read(base + B256::from(16)), - Instruction::Read(base + B256::from(48)), - ]; - let mut trace_record = vec![]; - // Execute the program - for instruction in program { - machine.exec(&instruction); - } - // Print the trace record (prettified), sorted by ascending time by default - for x in machine.trace().into_iter() { - println!("{:?}", x); - trace_record.push(x); - } +impl_register_machine!(StandardStateMachine); +impl_stack_machine!(StandardStateMachine); +impl_state_machine!(StandardStateMachine); + +#[cfg(test)] +mod tests { + use super::*; + use crate::{base::B256, config::DefaultConfig, constraints::helper::build_and_test_circuit}; + use alloc::vec; + use ethnum::U256; + use rand::Rng; + + #[test] + fn base_struct_test() { + // Define the desired machine configuration + type MyMachine = StandardStateMachine; + type Instruction = StandardInstruction; + let mut machine = MyMachine::new(DefaultConfig::default_config()); + + // Show the section map + let sections = machine.get_sections_maps(); + + assert_eq!(sections.len(), 3); + + // Memory section: (33856, 115792089237316195423570985008687907853269984665640564039457584007913129639935) + assert_eq!(sections[0].0, B256::from(33856)); + assert_eq!( + sections[0].1, + B256::from(U256::from_str_radix("115792089237316195423570985008687907853269984665640564039457584007913129639935", 10).unwrap().to_be_bytes()) + ); + // Register section: (32800, 33824) + assert_eq!(sections[1].0, B256::from(32800)); + assert_eq!(sections[1].1, B256::from(33824)); + // Stack section: (0, 32768) + assert_eq!(sections[2].0, B256::zero()); + assert_eq!(sections[2].1, B256::from(32768)); + + // Get the base address of the memory section + let base = machine.base_address(); + + let mut randomize = rand::thread_rng(); + randomize.gen_range(u64::MAX / 2..u64::MAX); + // Define your desired program + let program = vec![ + Instruction::Write( + base + B256::from(16), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Write( + base + B256::from(48), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Write( + base + B256::from(80), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Write( + base + B256::from(112), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Write( + base + B256::from(320), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Read(base + B256::from(16)), + Instruction::Write( + base + B256::from(10000), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Read(base + B256::from(48)), + Instruction::Read(base + B256::from(320)), + Instruction::Write( + base + B256::from(10016), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Write( + base + B256::from(10032), + B256::from(randomize.gen_range(u64::MAX / 2..u64::MAX)), + ), + Instruction::Read(base + B256::from(16)), + Instruction::Read(base + B256::from(48)), + Instruction::Push(B256::from(777)), + Instruction::Swap(machine.r0), + Instruction::Mov(machine.r1, machine.r0), + Instruction::Write(base + B256::from(16), B256::from(1025)), + Instruction::Write(base + B256::from(48), B256::from(1111)), + Instruction::Write(base + B256::from(80), B256::from(1000)), + Instruction::Write(base + B256::from(112), B256::from(9999)), + Instruction::Load(machine.r0, base + B256::from(16)), + Instruction::Push(B256::from(3735013596u64)), + Instruction::Swap(machine.r1), + ]; + let mut trace_record = vec![]; + // Execute the program + for instruction in program { + machine.exec(&instruction); + } + // Print the trace record (prettified), sorted by ascending time by default + for x in machine.trace().into_iter() { + trace_record.push(x); + } - println!("Verifying memory consistency..."); - // If build_and_test_circuit does not panic, then the trace is valid. - build_and_test_circuit(trace_record, 10); - println!("Memory consistency check done. The execution trace is valid."); + // If build_and_test_circuit does not panic, then the trace is valid. + build_and_test_circuit(trace_record, 10); + } } diff --git a/zkmemory/src/lib.rs b/zkmemory/src/lib.rs index ef83f09..ffb415e 100644 --- a/zkmemory/src/lib.rs +++ b/zkmemory/src/lib.rs @@ -21,6 +21,8 @@ pub mod commitment; pub mod config; /// Constraints for checking the lexicographic ordering pub mod constraints; +/// Default state machine implementation +pub mod default_state_machine; /// Define all errors of `StateMachine` pub mod error; /// Definition of abstract machine (instruction, trace and context) @@ -29,6 +31,7 @@ pub mod machine; pub mod nova; /// Memory consistency circuit using Supernova proof system pub mod supernova; + #[cfg(test)] mod tests { extern crate alloc; diff --git a/zkmemory/src/machine.rs b/zkmemory/src/machine.rs index 729078a..85e52f3 100644 --- a/zkmemory/src/machine.rs +++ b/zkmemory/src/machine.rs @@ -517,7 +517,7 @@ where /// Export macro for implementing [AbstractMemoryMachine](crate::machine::AbstractMemoryMachine) trait macro_rules! impl_state_machine { ($machine_struct: ident) => { - use zkmemory::machine::AbstractMemoryMachine; + use $crate::machine::AbstractMemoryMachine; impl AbstractMemoryMachine for $machine_struct @@ -534,7 +534,7 @@ macro_rules! impl_state_machine { /// Export macro for implementing [AbstractRegisterMachine](crate::machine::AbstractRegisterMachine) trait macro_rules! impl_register_machine { ($machine_struct: ident) => { - use zkmemory::machine::AbstractRegisterMachine; + use $crate::machine::AbstractRegisterMachine; impl AbstractRegisterMachine for $machine_struct @@ -543,10 +543,7 @@ macro_rules! impl_register_machine { V: Base, Self: AbstractMemoryMachine, { - fn new_register( - &self, - register_index: usize, - ) -> Option> { + fn new_register(&self, register_index: usize) -> Option<$crate::machine::Register> { Some(Register::new( register_index, self.register_start() + K::from(register_index) * K::WORD_SIZE, @@ -560,7 +557,7 @@ macro_rules! impl_register_machine { /// Export macro for implementing [AbstractStackMachine](crate::machine::AbstractStackMachine) trait macro_rules! impl_stack_machine { ($machine_struct: ident) => { - use zkmemory::machine::AbstractStackMachine; + use $crate::machine::AbstractStackMachine; impl AbstractStackMachine for $machine_struct