diff --git a/CHANGELOG.md b/CHANGELOG.md index 1509977ba..a18885e6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +#### Changes +- [BREAKING] `Process` no longer takes ownership of the `Host` (#1571) +- [BREAKING] `ProcessState` was converted from a trait to a struct (#1571) + ## 0.11.0 (2024-11-04) #### Enhancements diff --git a/miden/benches/program_execution.rs b/miden/benches/program_execution.rs index a8abd7050..6e3c20d4a 100644 --- a/miden/benches/program_execution.rs +++ b/miden/benches/program_execution.rs @@ -24,7 +24,7 @@ fn program_execution(c: &mut Criterion) { assembler.add_library(&stdlib).expect("failed to load stdlib"); let program = assembler.assemble_program(source).expect("Failed to compile test source."); bench.iter(|| { - execute(&program, StackInputs::default(), host.clone(), ExecutionOptions::default()) + execute(&program, StackInputs::default(), &mut host, ExecutionOptions::default()) }); }); diff --git a/miden/src/cli/debug/executor.rs b/miden/src/cli/debug/executor.rs index 1b53b2afc..d2a145fe0 100644 --- a/miden/src/cli/debug/executor.rs +++ b/miden/src/cli/debug/executor.rs @@ -29,7 +29,7 @@ impl DebugExecutor { source_manager: Arc, ) -> Result { let mut vm_state_iter = - processor::execute_iter(&program, stack_inputs, DefaultHost::new(advice_provider)); + processor::execute_iter(&program, stack_inputs, &mut DefaultHost::new(advice_provider)); let vm_state = vm_state_iter .next() .ok_or( diff --git a/miden/src/cli/prove.rs b/miden/src/cli/prove.rs index 377214bb2..92e41356c 100644 --- a/miden/src/cli/prove.rs +++ b/miden/src/cli/prove.rs @@ -96,15 +96,16 @@ impl ProveCmd { // fetch the stack and program inputs from the arguments let stack_inputs = input_data.parse_stack_inputs().map_err(Report::msg)?; - let host = DefaultHost::new(input_data.parse_advice_provider().map_err(Report::msg)?); + let mut host = DefaultHost::new(input_data.parse_advice_provider().map_err(Report::msg)?); let proving_options = self.get_proof_options().map_err(|err| Report::msg(format!("{err}")))?; // execute program and generate proof - let (stack_outputs, proof) = prover::prove(&program, stack_inputs, host, proving_options) - .into_diagnostic() - .wrap_err("Failed to prove program")?; + let (stack_outputs, proof) = + prover::prove(&program, stack_inputs, &mut host, proving_options) + .into_diagnostic() + .wrap_err("Failed to prove program")?; println!( "Program with hash {} proved in {} ms", diff --git a/miden/src/cli/run.rs b/miden/src/cli/run.rs index afb6c34a6..d726494d3 100644 --- a/miden/src/cli/run.rs +++ b/miden/src/cli/run.rs @@ -126,12 +126,12 @@ fn run_program(params: &RunCmd) -> Result<(ExecutionTrace, [u8; 32]), Report> { // fetch the stack and program inputs from the arguments let stack_inputs = input_data.parse_stack_inputs().map_err(Report::msg)?; - let host = DefaultHost::new(input_data.parse_advice_provider().map_err(Report::msg)?); + let mut host = DefaultHost::new(input_data.parse_advice_provider().map_err(Report::msg)?); let program_hash: [u8; 32] = program.hash().into(); // execute program and generate outputs - let trace = processor::execute(&program, stack_inputs, host, execution_options) + let trace = processor::execute(&program, stack_inputs, &mut host, execution_options) .into_diagnostic() .wrap_err("Failed to generate execution trace")?; diff --git a/miden/src/examples/mod.rs b/miden/src/examples/mod.rs index c377c8ec7..ffd37b7a9 100644 --- a/miden/src/examples/mod.rs +++ b/miden/src/examples/mod.rs @@ -116,7 +116,7 @@ impl ExampleOptions { let Example { program, stack_inputs, - host, + mut host, num_outputs, expected_result, .. @@ -126,7 +126,7 @@ impl ExampleOptions { // execute the program and generate the proof of execution let now = Instant::now(); let (stack_outputs, proof) = - miden_vm::prove(&program, stack_inputs.clone(), host, proof_options).unwrap(); + miden_vm::prove(&program, stack_inputs.clone(), &mut host, proof_options).unwrap(); println!("--------------------------------"); println!( @@ -173,13 +173,13 @@ where let Example { program, stack_inputs, - host, + mut host, num_outputs, expected_result, } = example; let (mut outputs, proof) = - miden_vm::prove(&program, stack_inputs.clone(), host, options).unwrap(); + miden_vm::prove(&program, stack_inputs.clone(), &mut host, options).unwrap(); assert_eq!( expected_result, diff --git a/miden/src/repl/mod.rs b/miden/src/repl/mod.rs index 692e29df5..198a13e35 100644 --- a/miden/src/repl/mod.rs +++ b/miden/src/repl/mod.rs @@ -321,7 +321,7 @@ fn execute( host.load_mast_forest(library.mast_forest().clone()); } - let state_iter = processor::execute_iter(&program, stack_inputs, host); + let state_iter = processor::execute_iter(&program, stack_inputs, &mut host); let (system, _, stack, chiplets, err) = state_iter.into_parts(); if let Some(err) = err { return Err(format!("{err}")); diff --git a/miden/src/tools/mod.rs b/miden/src/tools/mod.rs index 39d9d9ea5..7d932dbf5 100644 --- a/miden/src/tools/mod.rs +++ b/miden/src/tools/mod.rs @@ -209,7 +209,11 @@ impl fmt::Display for ExecutionDetails { } /// Returns program analysis of a given program. -fn analyze(program: &str, stack_inputs: StackInputs, host: H) -> Result +fn analyze( + program: &str, + stack_inputs: StackInputs, + mut host: H, +) -> Result where H: Host, { @@ -220,7 +224,7 @@ where .assemble_program(program)?; let mut execution_details = ExecutionDetails::default(); - let vm_state_iterator = processor::execute_iter(&program, stack_inputs, host); + let vm_state_iterator = processor::execute_iter(&program, stack_inputs, &mut host); execution_details.set_trace_len_summary(vm_state_iterator.trace_len_summary()); for state in vm_state_iterator { diff --git a/miden/tests/integration/operations/decorators/mod.rs b/miden/tests/integration/operations/decorators/mod.rs index ce4fb82af..9e4a17f35 100644 --- a/miden/tests/integration/operations/decorators/mod.rs +++ b/miden/tests/integration/operations/decorators/mod.rs @@ -31,43 +31,43 @@ impl Default for TestHost { } impl Host for TestHost { - fn get_advice( + fn get_advice( &mut self, - process: &S, + process: ProcessState, extractor: AdviceExtractor, ) -> Result { self.adv_provider.get_advice(process, &extractor) } - fn set_advice( + fn set_advice( &mut self, - process: &S, + process: ProcessState, injector: AdviceInjector, ) -> Result { self.adv_provider.set_advice(process, &injector) } - fn on_event( + fn on_event( &mut self, - _process: &S, + _process: ProcessState, event_id: u32, ) -> Result { self.event_handler.push(event_id); Ok(HostResponse::None) } - fn on_trace( + fn on_trace( &mut self, - _process: &S, + _process: ProcessState, trace_id: u32, ) -> Result { self.trace_handler.push(trace_id); Ok(HostResponse::None) } - fn on_debug( + fn on_debug( &mut self, - _process: &S, + _process: ProcessState, _options: &DebugOptions, ) -> Result { self.debug_handler.push(_options.to_string()); diff --git a/processor/src/chiplets/bitwise/mod.rs b/processor/src/chiplets/bitwise/mod.rs index b6f71c23f..48addfebc 100644 --- a/processor/src/chiplets/bitwise/mod.rs +++ b/processor/src/chiplets/bitwise/mod.rs @@ -48,6 +48,7 @@ const INIT_TRACE_CAPACITY: usize = 128; /// significant 4-bit limbs of the input values. With every subsequent row, the next most /// significant 4-bit limb of the result is appended to it. Thus, by the 8th row, column `z` /// contains the full result of the bitwise operation. +#[derive(Debug)] pub struct Bitwise { trace: [Vec; TRACE_WIDTH], } diff --git a/processor/src/chiplets/hasher/mod.rs b/processor/src/chiplets/hasher/mod.rs index 1aefb30b7..eba72ff77 100644 --- a/processor/src/chiplets/hasher/mod.rs +++ b/processor/src/chiplets/hasher/mod.rs @@ -54,7 +54,7 @@ mod tests; /// the trace of a control or span block that can be copied to be used later for program blocks /// encountered with the same digest instead of building it from scratch everytime. The hash of /// the block is used as the key here after converting it to a bytes array. -#[derive(Default)] +#[derive(Debug, Default)] pub struct Hasher { trace: HasherTrace, memoized_trace_map: BTreeMap<[u8; 32], (usize, usize)>, diff --git a/processor/src/chiplets/hasher/trace.rs b/processor/src/chiplets/hasher/trace.rs index d9dbe59b4..0c6226b99 100644 --- a/processor/src/chiplets/hasher/trace.rs +++ b/processor/src/chiplets/hasher/trace.rs @@ -15,7 +15,7 @@ use super::{Felt, HasherState, Selectors, TraceFragment, STATE_WIDTH, TRACE_WIDT /// - 3 selector columns. /// - 12 columns describing hasher state. /// - 1 node index column used for Merkle path related computations. -#[derive(Default)] +#[derive(Debug, Default)] pub struct HasherTrace { selectors: [Vec; 3], hasher_state: [Vec; STATE_WIDTH], diff --git a/processor/src/chiplets/kernel_rom/mod.rs b/processor/src/chiplets/kernel_rom/mod.rs index 4e0a2af84..226d3097a 100644 --- a/processor/src/chiplets/kernel_rom/mod.rs +++ b/processor/src/chiplets/kernel_rom/mod.rs @@ -38,6 +38,7 @@ type ProcHashBytes = [u8; 32]; /// change. /// - `h0` - `h3` columns contain roots of procedures in a given kernel. Together with `idx` column, /// these form tuples (index, procedure root) for all procedures in the kernel. +#[derive(Debug)] pub struct KernelRom { access_map: BTreeMap, kernel: Kernel, @@ -128,6 +129,7 @@ impl KernelRom { // ================================================================================================ /// Procedure access information for a given kernel procedure. +#[derive(Debug)] struct ProcAccessInfo { proc_hash: Word, num_accesses: usize, diff --git a/processor/src/chiplets/memory/mod.rs b/processor/src/chiplets/memory/mod.rs index 76690130c..99f78d0a6 100644 --- a/processor/src/chiplets/memory/mod.rs +++ b/processor/src/chiplets/memory/mod.rs @@ -76,7 +76,7 @@ const INIT_MEM_VALUE: Word = EMPTY_WORD; /// clock cycles computed as described above. /// /// For the first row of the trace, values in `d0`, `d1`, and `d_inv` are set to zeros. -#[derive(Default)] +#[derive(Debug, Default)] pub struct Memory { /// Memory segment traces sorted by their execution context ID. trace: BTreeMap, diff --git a/processor/src/chiplets/memory/segment.rs b/processor/src/chiplets/memory/segment.rs index 4bee448fc..495728656 100644 --- a/processor/src/chiplets/memory/segment.rs +++ b/processor/src/chiplets/memory/segment.rs @@ -19,7 +19,7 @@ use crate::{ContextId, ExecutionError}; /// A memory segment is an isolated address space accessible from a specific execution context. /// Within each segment, the memory is word-addressable. That is, four field elements are located /// at each memory address, and we can read and write elements to/from memory in batches of four. -#[derive(Default)] +#[derive(Debug, Default)] pub struct MemorySegmentTrace(BTreeMap>); impl MemorySegmentTrace { diff --git a/processor/src/chiplets/mod.rs b/processor/src/chiplets/mod.rs index a9fe8b777..d2c8c13aa 100644 --- a/processor/src/chiplets/mod.rs +++ b/processor/src/chiplets/mod.rs @@ -113,6 +113,7 @@ mod tests; /// | 1 | 1 | 1 | 1 |---------------------------------------------------------| /// +---+---+---+---+---------------------------------------------------------+ /// ``` +#[derive(Debug)] pub struct Chiplets { /// Current clock cycle of the VM. clk: RowIndex, diff --git a/processor/src/chiplets/tests.rs b/processor/src/chiplets/tests.rs index a0eab0162..89253f691 100644 --- a/processor/src/chiplets/tests.rs +++ b/processor/src/chiplets/tests.rs @@ -113,8 +113,8 @@ fn build_trace( kernel: Kernel, ) -> (ChipletsTrace, usize) { let stack_inputs = StackInputs::try_from_ints(stack_inputs.iter().copied()).unwrap(); - let host = DefaultHost::default(); - let mut process = Process::new(kernel, stack_inputs, host, ExecutionOptions::default()); + let mut host = DefaultHost::default(); + let mut process = Process::new(kernel, stack_inputs, ExecutionOptions::default()); let program = { let mut mast_forest = MastForest::new(); @@ -123,7 +123,7 @@ fn build_trace( Program::new(mast_forest.into(), basic_block_id) }; - process.execute(&program).unwrap(); + process.execute(&program, &mut host).unwrap(); let (trace, ..) = ExecutionTrace::test_finalize_trace(process); let trace_len = trace.num_rows() - ExecutionTrace::NUM_RAND_ROWS; diff --git a/processor/src/debug.rs b/processor/src/debug.rs index c30d53efd..ab908b560 100644 --- a/processor/src/debug.rs +++ b/processor/src/debug.rs @@ -9,7 +9,7 @@ use vm_core::{AssemblyOp, Operation, StackOutputs, Word}; use crate::{ range::RangeChecker, system::ContextId, Chiplets, ChipletsLengths, Decoder, ExecutionError, - Felt, Host, Process, Stack, System, TraceLenSummary, + Felt, Process, Stack, System, TraceLenSummary, }; /// VmState holds a current process state information at a specific clock cycle. @@ -63,11 +63,8 @@ pub struct VmStateIterator { } impl VmStateIterator { - pub fn new(process: Process, result: Result) -> Self - where - H: Host, - { - let (system, decoder, stack, mut range, chiplets, _) = process.into_parts(); + pub fn new(process: Process, result: Result) -> Self { + let (system, decoder, stack, mut range, chiplets) = process.into_parts(); let trace_len_summary = Self::build_trace_len_summary(&system, &mut range, &chiplets); Self { diff --git a/processor/src/decoder/mod.rs b/processor/src/decoder/mod.rs index a6248d0ef..2b7ee125a 100644 --- a/processor/src/decoder/mod.rs +++ b/processor/src/decoder/mod.rs @@ -19,9 +19,9 @@ use vm_core::{ }; use super::{ - ExecutionError, Felt, Host, OpBatch, Operation, Process, Word, EMPTY_WORD, MIN_TRACE_LEN, ONE, - ZERO, + ExecutionError, Felt, OpBatch, Operation, Process, Word, EMPTY_WORD, MIN_TRACE_LEN, ONE, ZERO, }; +use crate::Host; mod trace; use trace::DecoderTrace; @@ -47,18 +47,16 @@ const HASH_CYCLE_LEN: Felt = Felt::new(miden_air::trace::chiplets::hasher::HASH_ // DECODER PROCESS EXTENSION // ================================================================================================ -impl Process -where - H: Host, -{ +impl Process { // JOIN NODE // -------------------------------------------------------------------------------------------- /// Starts decoding of a JOIN node. - pub(super) fn start_join_node( + pub(super) fn start_join_node( &mut self, node: &JoinNode, program: &MastForest, + host: &mut H, ) -> Result<(), ExecutionError> { // use the hasher to compute the hash of the JOIN block; the row address returned by the // hasher is used as the ID of the block; the result of the hash is expected to be in @@ -84,16 +82,20 @@ where // start decoding the JOIN block; this appends a row with JOIN operation to the decoder // trace. when JOIN operation is executed, the rest of the VM state does not change self.decoder.start_join(child1_hash, child2_hash, addr); - self.execute_op(Operation::Noop) + self.execute_op(Operation::Noop, host) } /// Ends decoding of a JOIN node. - pub(super) fn end_join_node(&mut self, node: &JoinNode) -> Result<(), ExecutionError> { + pub(super) fn end_join_node( + &mut self, + node: &JoinNode, + host: &mut H, + ) -> Result<(), ExecutionError> { // this appends a row with END operation to the decoder trace. when END operation is // executed the rest of the VM state does not change self.decoder.end_control_block(node.digest().into()); - self.execute_op(Operation::Noop) + self.execute_op(Operation::Noop, host) } // SPLIT NODE @@ -101,10 +103,11 @@ where /// Starts decoding a SPLIT node. This also pops the value from the top of the stack and /// returns it. - pub(super) fn start_split_node( + pub(super) fn start_split_node( &mut self, node: &SplitNode, program: &MastForest, + host: &mut H, ) -> Result { let condition = self.stack.peek(); @@ -131,17 +134,21 @@ where // start decoding the SPLIT block. this appends a row with SPLIT operation to the decoder // trace. we also pop the value off the top of the stack and return it. self.decoder.start_split(child1_hash, child2_hash, addr); - self.execute_op(Operation::Drop)?; + self.execute_op(Operation::Drop, host)?; Ok(condition) } /// Ends decoding of a SPLIT node. - pub(super) fn end_split_node(&mut self, block: &SplitNode) -> Result<(), ExecutionError> { + pub(super) fn end_split_node( + &mut self, + block: &SplitNode, + host: &mut H, + ) -> Result<(), ExecutionError> { // this appends a row with END operation to the decoder trace. when END operation is // executed the rest of the VM state does not change self.decoder.end_control_block(block.digest().into()); - self.execute_op(Operation::Noop) + self.execute_op(Operation::Noop, host) } // LOOP NODE @@ -149,10 +156,11 @@ where /// Starts decoding a LOOP node. This also pops the value from the top of the stack and /// returns it. - pub(super) fn start_loop_node( + pub(super) fn start_loop_node( &mut self, node: &LoopNode, program: &MastForest, + host: &mut H, ) -> Result { let condition = self.stack.peek(); @@ -178,16 +186,17 @@ where // basically, if the top of the stack is ZERO, a LOOP operation should be immediately // followed by an END operation. self.decoder.start_loop(body_hash, addr, condition); - self.execute_op(Operation::Drop)?; + self.execute_op(Operation::Drop, host)?; Ok(condition) } /// Ends decoding of a LOOP block. If pop_stack is set to true, this also removes the /// value at the top of the stack. - pub(super) fn end_loop_node( + pub(super) fn end_loop_node( &mut self, node: &LoopNode, pop_stack: bool, + host: &mut H, ) -> Result<(), ExecutionError> { // this appends a row with END operation to the decoder trace. self.decoder.end_control_block(node.digest().into()); @@ -201,9 +210,9 @@ where #[cfg(debug_assertions)] debug_assert_eq!(ZERO, self.stack.peek()); - self.execute_op(Operation::Drop) + self.execute_op(Operation::Drop, host) } else { - self.execute_op(Operation::Noop) + self.execute_op(Operation::Noop, host) } } @@ -211,10 +220,11 @@ where // -------------------------------------------------------------------------------------------- /// Starts decoding of a CALL or a SYSCALL node. - pub(super) fn start_call_node( + pub(super) fn start_call_node( &mut self, node: &CallNode, program: &MastForest, + host: &mut H, ) -> Result<(), ExecutionError> { // use the hasher to compute the hash of the CALL or SYSCALL block; the row address // returned by the hasher is used as the ID of the block; the result of the hash is @@ -254,11 +264,15 @@ where } // the rest of the VM state does not change - self.execute_op(Operation::Noop) + self.execute_op(Operation::Noop, host) } /// Ends decoding of a CALL or a SYSCALL block. - pub(super) fn end_call_node(&mut self, node: &CallNode) -> Result<(), ExecutionError> { + pub(super) fn end_call_node( + &mut self, + node: &CallNode, + host: &mut H, + ) -> Result<(), ExecutionError> { // when a CALL block ends, stack depth must be exactly 16 let stack_depth = self.stack.depth(); if stack_depth > MIN_STACK_DEPTH { @@ -285,7 +299,7 @@ where ); // the rest of the VM state does not change - self.execute_op(Operation::Noop) + self.execute_op(Operation::Noop, host) } // DYN NODE @@ -295,7 +309,11 @@ where /// /// Note: even though we will write the callee hash to h[0..4] for the chiplets bus and block /// hash table, the issued hash request is still hash([ZERO; 8]). - pub(super) fn start_dyn_node(&mut self, dyn_node: &DynNode) -> Result { + pub(super) fn start_dyn_node( + &mut self, + dyn_node: &DynNode, + host: &mut H, + ) -> Result { debug_assert!(!dyn_node.is_dyncall()); let mem_addr = self.stack.get(0); @@ -313,7 +331,7 @@ where self.decoder.start_dyn(addr, callee_hash); // Pop the memory address off the stack. - self.execute_op(Operation::Drop)?; + self.execute_op(Operation::Drop, host)?; Ok(callee_hash) } @@ -371,16 +389,24 @@ where } /// Ends decoding of a DYN node. - pub(super) fn end_dyn_node(&mut self, dyn_node: &DynNode) -> Result<(), ExecutionError> { + pub(super) fn end_dyn_node( + &mut self, + dyn_node: &DynNode, + host: &mut H, + ) -> Result<(), ExecutionError> { // this appends a row with END operation to the decoder trace. when the END operation is // executed the rest of the VM state does not change self.decoder.end_control_block(dyn_node.digest().into()); - self.execute_op(Operation::Noop) + self.execute_op(Operation::Noop, host) } /// Ends decoding of a DYNCALL node. - pub(super) fn end_dyncall_node(&mut self, dyn_node: &DynNode) -> Result<(), ExecutionError> { + pub(super) fn end_dyncall_node( + &mut self, + dyn_node: &DynNode, + host: &mut H, + ) -> Result<(), ExecutionError> { // when a DYNCALL block ends, stack depth must be exactly 16 let stack_depth = self.stack.depth(); if stack_depth > MIN_STACK_DEPTH { @@ -406,16 +432,17 @@ where ctx_info.parent_next_overflow_addr, ); - self.execute_op(Operation::Noop) + self.execute_op(Operation::Noop, host) } // BASIC BLOCK NODE // -------------------------------------------------------------------------------------------- /// Starts decoding a BASIC BLOCK node. - pub(super) fn start_basic_block_node( + pub(super) fn start_basic_block_node( &mut self, basic_block: &BasicBlockNode, + host: &mut H, ) -> Result<(), ExecutionError> { // use the hasher to compute the hash of the SPAN block; the row address returned by the // hasher is used as the ID of the block; hash of a SPAN block is computed by sequentially @@ -430,19 +457,20 @@ where let num_op_groups = basic_block.num_op_groups(); self.decoder .start_basic_block(&op_batches[0], Felt::new(num_op_groups as u64), addr); - self.execute_op(Operation::Noop) + self.execute_op(Operation::Noop, host) } /// Ends decoding a BASIC BLOCK node. - pub(super) fn end_basic_block_node( + pub(super) fn end_basic_block_node( &mut self, block: &BasicBlockNode, + host: &mut H, ) -> Result<(), ExecutionError> { // this appends a row with END operation to the decoder trace. when END operation is // executed the rest of the VM state does not change self.decoder.end_basic_block(block.digest().into()); - self.execute_op(Operation::Noop) + self.execute_op(Operation::Noop, host) } /// Continues decoding a SPAN block by absorbing the next batch of operations. diff --git a/processor/src/decoder/tests.rs b/processor/src/decoder/tests.rs index c0a90bdec..664517b7a 100644 --- a/processor/src/decoder/tests.rs +++ b/processor/src/decoder/tests.rs @@ -1460,10 +1460,9 @@ fn set_user_op_helpers_many() { fn build_trace(stack_inputs: &[u64], program: &Program) -> (DecoderTrace, usize) { let stack_inputs = StackInputs::try_from_ints(stack_inputs.iter().copied()).unwrap(); - let host = DefaultHost::default(); - let mut process = - Process::new(Kernel::default(), stack_inputs, host, ExecutionOptions::default()); - process.execute(program).unwrap(); + let mut host = DefaultHost::default(); + let mut process = Process::new(Kernel::default(), stack_inputs, ExecutionOptions::default()); + process.execute(program, &mut host).unwrap(); let (trace, ..) = ExecutionTrace::test_finalize_trace(process); let trace_len = trace.num_rows() - ExecutionTrace::NUM_RAND_ROWS; @@ -1479,11 +1478,10 @@ fn build_trace(stack_inputs: &[u64], program: &Program) -> (DecoderTrace, usize) fn build_dyn_trace(stack_inputs: &[u64], program: &Program) -> (DecoderTrace, usize) { let stack_inputs = StackInputs::try_from_ints(stack_inputs.iter().copied()).unwrap(); - let host = DefaultHost::default(); - let mut process = - Process::new(Kernel::default(), stack_inputs, host, ExecutionOptions::default()); + let mut host = DefaultHost::default(); + let mut process = Process::new(Kernel::default(), stack_inputs, ExecutionOptions::default()); - process.execute(program).unwrap(); + process.execute(program, &mut host).unwrap(); let (trace, ..) = ExecutionTrace::test_finalize_trace(process); let trace_len = trace.num_rows() - ExecutionTrace::NUM_RAND_ROWS; @@ -1498,11 +1496,11 @@ fn build_dyn_trace(stack_inputs: &[u64], program: &Program) -> (DecoderTrace, us } fn build_call_trace(program: &Program, kernel: Kernel) -> (SystemTrace, DecoderTrace, usize) { - let host = DefaultHost::default(); + let mut host = DefaultHost::default(); let stack_inputs = crate::StackInputs::default(); - let mut process = Process::new(kernel, stack_inputs, host, ExecutionOptions::default()); + let mut process = Process::new(kernel, stack_inputs, ExecutionOptions::default()); - process.execute(program).unwrap(); + process.execute(program, &mut host).unwrap(); let (trace, ..) = ExecutionTrace::test_finalize_trace(process); let trace_len = trace.num_rows() - ExecutionTrace::NUM_RAND_ROWS; diff --git a/processor/src/host/advice/injectors/adv_map_injectors.rs b/processor/src/host/advice/injectors/adv_map_injectors.rs index 2577c4037..4eab49baf 100644 --- a/processor/src/host/advice/injectors/adv_map_injectors.rs +++ b/processor/src/host/advice/injectors/adv_map_injectors.rs @@ -29,9 +29,9 @@ use crate::ProcessState; /// - `start_addr` is greater than or equal to 2^32. /// - `end_addr` is greater than or equal to 2^32. /// - `start_addr` > `end_addr`. -pub(crate) fn insert_mem_values_into_adv_map( +pub(crate) fn insert_mem_values_into_adv_map( advice_provider: &mut A, - process: &S, + process: ProcessState, ) -> Result { let (start_addr, end_addr) = get_mem_addr_range(process, 4, 5)?; let ctx = process.ctx(); @@ -61,9 +61,9 @@ pub(crate) fn insert_mem_values_into_adv_map /// /// Where KEY is computed as hash(A || B, domain), where domain is provided via the immediate /// value. -pub(crate) fn insert_hdword_into_adv_map( +pub(crate) fn insert_hdword_into_adv_map( advice_provider: &mut A, - process: &S, + process: ProcessState, domain: Felt, ) -> Result { // get the top two words from the stack and hash them to compute the key value @@ -94,9 +94,9 @@ pub(crate) fn insert_hdword_into_adv_map( /// /// Where KEY is computed by extracting the digest elements from hperm([C, A, B]). For example, /// if C is [0, d, 0, 0], KEY will be set as hash(A || B, d). -pub(crate) fn insert_hperm_into_adv_map( +pub(crate) fn insert_hperm_into_adv_map( advice_provider: &mut A, - process: &S, + process: ProcessState, ) -> Result { // read the state from the stack let mut state = [ @@ -145,9 +145,9 @@ pub(crate) fn insert_hperm_into_adv_map( /// provider (i.e., the input trees are not removed). /// /// It is not checked whether the provided roots exist as Merkle trees in the advide providers. -pub(crate) fn merge_merkle_nodes( +pub(crate) fn merge_merkle_nodes( advice_provider: &mut A, - process: &S, + process: ProcessState, ) -> Result { // fetch the arguments from the stack let lhs = process.get_stack_word(1); @@ -164,8 +164,8 @@ pub(crate) fn merge_merkle_nodes( /// Reads (start_addr, end_addr) tuple from the specified elements of the operand stack ( /// without modifying the state of the stack), and verifies that memory range is valid. -fn get_mem_addr_range( - process: &S, +fn get_mem_addr_range( + process: ProcessState, start_idx: usize, end_idx: usize, ) -> Result<(u32, u32), ExecutionError> { diff --git a/processor/src/host/advice/injectors/adv_stack_injectors.rs b/processor/src/host/advice/injectors/adv_stack_injectors.rs index 9363e49c0..60f467860 100644 --- a/processor/src/host/advice/injectors/adv_stack_injectors.rs +++ b/processor/src/host/advice/injectors/adv_stack_injectors.rs @@ -32,9 +32,9 @@ type QuadFelt = QuadExtension; /// - The specified depth is either zero or greater than the depth of the Merkle tree identified by /// the specified root. /// - Value of the node at the specified depth and index is not known to the advice provider. -pub(crate) fn copy_merkle_node_to_adv_stack( +pub(crate) fn copy_merkle_node_to_adv_stack( advice_provider: &mut A, - process: &S, + process: ProcessState, ) -> Result { // read node depth, node index, and tree root from the stack let depth = process.get_stack_item(0); @@ -83,9 +83,9 @@ pub(crate) fn copy_merkle_node_to_adv_stack( /// # Errors /// Returns an error if the required key was not found in the key-value map or if stack offset /// is greater than 12. -pub(crate) fn copy_map_value_to_adv_stack( +pub(crate) fn copy_map_value_to_adv_stack( advice_provider: &mut A, - process: &S, + process: ProcessState, include_len: bool, key_offset: usize, ) -> Result { @@ -122,9 +122,9 @@ pub(crate) fn copy_map_value_to_adv_stack( /// /// # Errors /// Returns an error if the divisor is ZERO. -pub(crate) fn push_u64_div_result( +pub(crate) fn push_u64_div_result( advice_provider: &mut A, - process: &S, + process: ProcessState, ) -> Result { let divisor_hi = process.get_stack_item(0).as_int(); let divisor_lo = process.get_stack_item(1).as_int(); @@ -168,9 +168,9 @@ pub(crate) fn push_u64_div_result( /// /// # Errors /// Returns an error if the input is a zero element in the extension field. -pub(crate) fn push_ext2_inv_result( +pub(crate) fn push_ext2_inv_result( advice_provider: &mut A, - process: &S, + process: ProcessState, ) -> Result { let coef0 = process.get_stack_item(1); let coef1 = process.get_stack_item(0); @@ -215,9 +215,9 @@ pub(crate) fn push_ext2_inv_result( /// - `output_size` is 0 or is greater than the `input_size`. /// - `input_ptr` is greater than 2^32. /// - `input_ptr + input_size / 2` is greater than 2^32. -pub(crate) fn push_ext2_intt_result( +pub(crate) fn push_ext2_intt_result( advice_provider: &mut A, - process: &S, + process: ProcessState, ) -> Result { let output_size = process.get_stack_item(0).as_int() as usize; let input_size = process.get_stack_item(1).as_int() as usize; @@ -284,9 +284,9 @@ pub(crate) fn push_ext2_intt_result( /// - DATA is the needed data for signature verification in the VM. /// /// The advice provider is expected to contain the private key associated to the public key PK. -pub(crate) fn push_signature( +pub(crate) fn push_signature( advice_provider: &mut A, - process: &S, + process: ProcessState, kind: SignatureKind, ) -> Result { let pub_key = process.get_stack_word(0); @@ -307,9 +307,9 @@ pub(crate) fn push_signature( /// Outputs: /// Operand stack: [n, ...] /// Advice stack: [leading_zeros, ...] -pub(crate) fn push_leading_zeros( +pub(crate) fn push_leading_zeros( advice_provider: &mut A, - process: &S, + process: ProcessState, ) -> Result { push_transformed_stack_top(advice_provider, process, |stack_top| { Felt::from(stack_top.leading_zeros()) @@ -325,9 +325,9 @@ pub(crate) fn push_leading_zeros( /// Outputs: /// Operand stack: [n, ...] /// Advice stack: [trailing_zeros, ...] -pub(crate) fn push_trailing_zeros( +pub(crate) fn push_trailing_zeros( advice_provider: &mut A, - process: &S, + process: ProcessState, ) -> Result { push_transformed_stack_top(advice_provider, process, |stack_top| { Felt::from(stack_top.trailing_zeros()) @@ -343,9 +343,9 @@ pub(crate) fn push_trailing_zeros( /// Outputs: /// Operand stack: [n, ...] /// Advice stack: [leading_ones, ...] -pub(crate) fn push_leading_ones( +pub(crate) fn push_leading_ones( advice_provider: &mut A, - process: &S, + process: ProcessState, ) -> Result { push_transformed_stack_top(advice_provider, process, |stack_top| { Felt::from(stack_top.leading_ones()) @@ -361,9 +361,9 @@ pub(crate) fn push_leading_ones( /// Outputs: /// Operand stack: [n, ...] /// Advice stack: [trailing_ones, ...] -pub(crate) fn push_trailing_ones( +pub(crate) fn push_trailing_ones( advice_provider: &mut A, - process: &S, + process: ProcessState, ) -> Result { push_transformed_stack_top(advice_provider, process, |stack_top| { Felt::from(stack_top.trailing_ones()) @@ -381,9 +381,9 @@ pub(crate) fn push_trailing_ones( /// /// # Errors /// Returns an error if the logarithm argument (top stack element) equals ZERO. -pub(crate) fn push_ilog2( +pub(crate) fn push_ilog2( advice_provider: &mut A, - process: &S, + process: ProcessState, ) -> Result { let n = process.get_stack_item(0).as_int(); if n == 0 { @@ -405,9 +405,9 @@ fn u64_to_u32_elements(value: u64) -> (Felt, Felt) { /// Gets the top stack element, applies a provided function to it and pushes it to the advice /// provider. -fn push_transformed_stack_top( +fn push_transformed_stack_top( advice_provider: &mut A, - process: &S, + process: ProcessState, f: impl FnOnce(u32) -> Felt, ) -> Result { let stack_top = process.get_stack_item(0); diff --git a/processor/src/host/advice/injectors/merkle_store_injectors.rs b/processor/src/host/advice/injectors/merkle_store_injectors.rs index 565afbcd4..bf6166913 100644 --- a/processor/src/host/advice/injectors/merkle_store_injectors.rs +++ b/processor/src/host/advice/injectors/merkle_store_injectors.rs @@ -1,8 +1,8 @@ use super::super::{AdviceProvider, ExecutionError, HostResponse, ProcessState}; -pub(crate) fn update_operand_stack_merkle_node( +pub(crate) fn update_operand_stack_merkle_node( advice_provider: &mut A, - process: &S, + process: ProcessState, ) -> Result { let depth = process.get_stack_item(4); let index = process.get_stack_item(5); diff --git a/processor/src/host/advice/injectors/smt.rs b/processor/src/host/advice/injectors/smt.rs index 8481e1143..544c8ee4b 100644 --- a/processor/src/host/advice/injectors/smt.rs +++ b/processor/src/host/advice/injectors/smt.rs @@ -30,9 +30,9 @@ use crate::{AdviceProvider, ProcessState}; /// /// # Errors /// Returns an error if the provided Merkle root doesn't exist on the advice provider. -pub(crate) fn push_smtpeek_result( +pub(crate) fn push_smtpeek_result( advice_provider: &mut A, - process: &S, + process: ProcessState, ) -> Result { let empty_leaf = EmptySubtreeRoots::entry(SMT_DEPTH, SMT_DEPTH); // fetch the arguments from the operand stack @@ -68,17 +68,17 @@ pub(crate) fn push_smtpeek_result( } /// Currently unimplemented -pub(crate) fn push_smtget_inputs( +pub(crate) fn push_smtget_inputs( _advice_provider: &mut A, - _process: &S, + _process: ProcessState, ) -> Result { unimplemented!() } /// Currently unimplemented -pub(crate) fn push_smtset_inputs( +pub(crate) fn push_smtset_inputs( _advice_provider: &mut A, - _process: &S, + _process: ProcessState, ) -> Result { unimplemented!() } diff --git a/processor/src/host/advice/mod.rs b/processor/src/host/advice/mod.rs index 4eba93fe7..8f6c8bddc 100644 --- a/processor/src/host/advice/mod.rs +++ b/processor/src/host/advice/mod.rs @@ -52,9 +52,9 @@ pub trait AdviceProvider: Sized { // -------------------------------------------------------------------------------------------- /// Handles the specified advice injector request. - fn set_advice( + fn set_advice( &mut self, - process: &S, + process: ProcessState, advice_injector: &AdviceInjector, ) -> Result { match advice_injector { @@ -86,9 +86,9 @@ pub trait AdviceProvider: Sized { } /// Handles the specified advice extractor request. - fn get_advice( + fn get_advice( &mut self, - process: &S, + process: ProcessState, advice_extractor: &AdviceExtractor, ) -> Result { match advice_extractor { @@ -122,9 +122,9 @@ pub trait AdviceProvider: Sized { /// - `start_addr` is greater than or equal to 2^32. /// - `end_addr` is greater than or equal to 2^32. /// - `start_addr` > `end_addr`. - fn insert_mem_values_into_adv_map( + fn insert_mem_values_into_adv_map( &mut self, - process: &S, + process: ProcessState, ) -> Result { injectors::adv_map_injectors::insert_mem_values_into_adv_map(self, process) } @@ -142,9 +142,9 @@ pub trait AdviceProvider: Sized { /// /// Where KEY is computed as hash(A || B, domain), where domain is provided via the immediate /// value. - fn insert_hdword_into_adv_map( + fn insert_hdword_into_adv_map( &mut self, - process: &S, + process: ProcessState, domain: Felt, ) -> Result { injectors::adv_map_injectors::insert_hdword_into_adv_map(self, process, domain) @@ -163,9 +163,9 @@ pub trait AdviceProvider: Sized { /// /// Where KEY is computed by extracting the digest elements from hperm([C, A, B]). For example, /// if C is [0, d, 0, 0], KEY will be set as hash(A || B, d). - fn insert_hperm_into_adv_map( + fn insert_hperm_into_adv_map( &mut self, - process: &S, + process: ProcessState, ) -> Result { injectors::adv_map_injectors::insert_hperm_into_adv_map(self, process) } @@ -185,9 +185,9 @@ pub trait AdviceProvider: Sized { /// provider (i.e., the input trees are not removed). /// /// It is not checked whether the provided roots exist as Merkle trees in the advide providers. - fn merge_merkle_nodes( + fn merge_merkle_nodes( &mut self, - process: &S, + process: ProcessState, ) -> Result { injectors::adv_map_injectors::merge_merkle_nodes(self, process) } @@ -214,9 +214,9 @@ pub trait AdviceProvider: Sized { /// - The specified depth is either zero or greater than the depth of the Merkle tree identified /// by the specified root. /// - Value of the node at the specified depth and index is not known to the advice provider. - fn copy_merkle_node_to_adv_stack( + fn copy_merkle_node_to_adv_stack( &mut self, - process: &S, + process: ProcessState, ) -> Result { injectors::adv_stack_injectors::copy_merkle_node_to_adv_stack(self, process) } @@ -245,9 +245,9 @@ pub trait AdviceProvider: Sized { /// # Errors /// Returns an error if the required key was not found in the key-value map or if stack offset /// is greater than 12. - fn copy_map_value_to_adv_stack( + fn copy_map_value_to_adv_stack( &mut self, - process: &S, + process: ProcessState, include_len: bool, key_offset: usize, ) -> Result { @@ -277,9 +277,9 @@ pub trait AdviceProvider: Sized { /// /// # Errors /// Returns an error if the divisor is ZERO. - fn push_u64_div_result( + fn push_u64_div_result( &mut self, - process: &S, + process: ProcessState, ) -> Result { injectors::adv_stack_injectors::push_u64_div_result(self, process) } @@ -300,9 +300,9 @@ pub trait AdviceProvider: Sized { /// /// # Errors /// Returns an error if the input is a zero element in the extension field. - fn push_ext2_inv_result( + fn push_ext2_inv_result( &mut self, - process: &S, + process: ProcessState, ) -> Result { injectors::adv_stack_injectors::push_ext2_inv_result(self, process) } @@ -336,9 +336,9 @@ pub trait AdviceProvider: Sized { /// - `output_size` is 0 or is greater than the `input_size`. /// - `input_ptr` is greater than 2^32. /// - `input_ptr + input_size / 2` is greater than 2^32. - fn push_ext2_intt_result( + fn push_ext2_intt_result( &mut self, - process: &S, + process: ProcessState, ) -> Result { injectors::adv_stack_injectors::push_ext2_intt_result(self, process) } @@ -360,9 +360,9 @@ pub trait AdviceProvider: Sized { /// - DATA is the needed data for signature verification in the VM. /// /// The advice provider is expected to contain the private key associated to the public key PK. - fn push_signature( + fn push_signature( &mut self, - process: &S, + process: ProcessState, kind: SignatureKind, ) -> Result { injectors::adv_stack_injectors::push_signature(self, process, kind) @@ -377,9 +377,9 @@ pub trait AdviceProvider: Sized { /// Outputs: /// Operand stack: [n, ...] /// Advice stack: [leading_zeros, ...] - fn push_leading_zeros( + fn push_leading_zeros( &mut self, - process: &S, + process: ProcessState, ) -> Result { injectors::adv_stack_injectors::push_leading_zeros(self, process) } @@ -393,9 +393,9 @@ pub trait AdviceProvider: Sized { /// Outputs: /// Operand stack: [n, ...] /// Advice stack: [trailing_zeros, ...] - fn push_trailing_zeros( + fn push_trailing_zeros( &mut self, - process: &S, + process: ProcessState, ) -> Result { injectors::adv_stack_injectors::push_trailing_zeros(self, process) } @@ -409,10 +409,7 @@ pub trait AdviceProvider: Sized { /// Outputs: /// Operand stack: [n, ...] /// Advice stack: [leading_ones, ...] - fn push_leading_ones( - &mut self, - process: &S, - ) -> Result { + fn push_leading_ones(&mut self, process: ProcessState) -> Result { injectors::adv_stack_injectors::push_leading_ones(self, process) } @@ -425,9 +422,9 @@ pub trait AdviceProvider: Sized { /// Outputs: /// Operand stack: [n, ...] /// Advice stack: [trailing_ones, ...] - fn push_trailing_ones( + fn push_trailing_ones( &mut self, - process: &S, + process: ProcessState, ) -> Result { injectors::adv_stack_injectors::push_trailing_ones(self, process) } @@ -443,7 +440,7 @@ pub trait AdviceProvider: Sized { /// /// # Errors /// Returns an error if the logarithm argument (top stack element) equals ZERO. - fn push_ilog2(&mut self, process: &S) -> Result { + fn push_ilog2(&mut self, process: ProcessState) -> Result { injectors::adv_stack_injectors::push_ilog2(self, process) } @@ -463,9 +460,9 @@ pub trait AdviceProvider: Sized { /// Advice stack: [...] /// Merkle store: {path, ...} /// Return: \[path\] - fn update_operand_stack_merkle_node( + fn update_operand_stack_merkle_node( &mut self, - process: &S, + process: ProcessState, ) -> Result { injectors::merkle_store_injectors::update_operand_stack_merkle_node(self, process) } @@ -491,9 +488,9 @@ pub trait AdviceProvider: Sized { /// Advice map: {...} /// Merkle store: {path, ...} /// Return: \[path\] - fn get_operand_stack_merkle_path( + fn get_operand_stack_merkle_path( &mut self, - process: &S, + process: ProcessState, ) -> Result { let depth = process.get_stack_item(4); let index = process.get_stack_item(5); @@ -528,25 +525,25 @@ pub trait AdviceProvider: Sized { /// /// # Panics /// Will panic as unimplemented if the target depth is `64`. - fn push_smtpeek_result( + fn push_smtpeek_result( &mut self, - process: &S, + process: ProcessState, ) -> Result { injectors::smt::push_smtpeek_result(self, process) } /// Currently unimplemented - fn push_smtget_inputs( + fn push_smtget_inputs( &mut self, - process: &S, + process: ProcessState, ) -> Result { injectors::smt::push_smtget_inputs(self, process) } /// Currently unimplemented - fn push_smtset_inputs( + fn push_smtset_inputs( &mut self, - process: &S, + process: ProcessState, ) -> Result { injectors::smt::push_smtset_inputs(self, process) } @@ -579,7 +576,7 @@ pub trait AdviceProvider: Sized { /// /// # Errors /// Returns an error if the advice stack is empty. - fn pop_stack(&mut self, process: &S) -> Result; + fn pop_stack(&mut self, process: ProcessState) -> Result; /// Pops a word (4 elements) from the advice stack and returns it. /// @@ -588,7 +585,7 @@ pub trait AdviceProvider: Sized { /// /// # Errors /// Returns an error if the advice stack does not contain a full word. - fn pop_stack_word(&mut self, process: &S) -> Result; + fn pop_stack_word(&mut self, process: ProcessState) -> Result; /// Pops a double word (8 elements) from the advice stack and returns them. /// @@ -598,10 +595,7 @@ pub trait AdviceProvider: Sized { /// /// # Errors /// Returns an error if the advice stack does not contain two words. - fn pop_stack_dword( - &mut self, - process: &S, - ) -> Result<[Word; 2], ExecutionError>; + fn pop_stack_dword(&mut self, process: ProcessState) -> Result<[Word; 2], ExecutionError>; /// Pushes the value(s) specified by the source onto the advice stack. /// @@ -722,18 +716,15 @@ impl AdviceProvider for &mut T where T: AdviceProvider, { - fn pop_stack(&mut self, process: &S) -> Result { + fn pop_stack(&mut self, process: ProcessState) -> Result { T::pop_stack(self, process) } - fn pop_stack_word(&mut self, process: &S) -> Result { + fn pop_stack_word(&mut self, process: ProcessState) -> Result { T::pop_stack_word(self, process) } - fn pop_stack_dword( - &mut self, - process: &S, - ) -> Result<[Word; 2], ExecutionError> { + fn pop_stack_dword(&mut self, process: ProcessState) -> Result<[Word; 2], ExecutionError> { T::pop_stack_dword(self, process) } diff --git a/processor/src/host/advice/providers.rs b/processor/src/host/advice/providers.rs index 1b2bb4708..6cc10efe2 100644 --- a/processor/src/host/advice/providers.rs +++ b/processor/src/host/advice/providers.rs @@ -60,11 +60,11 @@ where // ADVICE STACK // -------------------------------------------------------------------------------------------- - fn pop_stack(&mut self, process: &P) -> Result { + fn pop_stack(&mut self, process: ProcessState) -> Result { self.stack.pop().ok_or(ExecutionError::AdviceStackReadFailed(process.clk())) } - fn pop_stack_word(&mut self, process: &P) -> Result { + fn pop_stack_word(&mut self, process: ProcessState) -> Result { if self.stack.len() < 4 { return Err(ExecutionError::AdviceStackReadFailed(process.clk())); } @@ -78,10 +78,7 @@ where Ok(result) } - fn pop_stack_dword( - &mut self, - process: &P, - ) -> Result<[Word; 2], ExecutionError> { + fn pop_stack_dword(&mut self, process: ProcessState) -> Result<[Word; 2], ExecutionError> { let word0 = self.pop_stack_word(process)?; let word1 = self.pop_stack_word(process)?; @@ -259,15 +256,15 @@ impl MemAdviceProvider { /// TODO: potentially do this via a macro. #[rustfmt::skip] impl AdviceProvider for MemAdviceProvider { - fn pop_stack(&mut self, process: &S)-> Result { + fn pop_stack(&mut self, process: ProcessState)-> Result { self.provider.pop_stack(process) } - fn pop_stack_word(&mut self, process: &S) -> Result { + fn pop_stack_word(&mut self, process: ProcessState) -> Result { self.provider.pop_stack_word(process) } - fn pop_stack_dword(&mut self, process: &S) -> Result<[Word; 2], ExecutionError> { + fn pop_stack_dword(&mut self, process: ProcessState) -> Result<[Word; 2], ExecutionError> { self.provider.pop_stack_dword(process) } @@ -377,15 +374,15 @@ impl RecAdviceProvider { /// TODO: potentially do this via a macro. #[rustfmt::skip] impl AdviceProvider for RecAdviceProvider { - fn pop_stack(&mut self, process: &S) -> Result { + fn pop_stack(&mut self, process: ProcessState) -> Result { self.provider.pop_stack(process) } - fn pop_stack_word(&mut self, process: &S) -> Result { + fn pop_stack_word(&mut self, process: ProcessState) -> Result { self.provider.pop_stack_word(process) } - fn pop_stack_dword(&mut self, process: &S) -> Result<[Word; 2], ExecutionError> { + fn pop_stack_dword(&mut self, process: ProcessState) -> Result<[Word; 2], ExecutionError> { self.provider.pop_stack_dword(process) } diff --git a/processor/src/host/debug.rs b/processor/src/host/debug.rs index 81913f164..6812d5bc6 100644 --- a/processor/src/host/debug.rs +++ b/processor/src/host/debug.rs @@ -11,7 +11,7 @@ use crate::system::ContextId; // ================================================================================================ /// Prints the info about the VM state specified by the provided options to stdout. -pub fn print_debug_info(process: &S, options: &DebugOptions) { +pub fn print_debug_info(process: ProcessState, options: &DebugOptions) { let printer = Printer::new(process.clk(), process.ctx(), process.fmp()); match options { DebugOptions::StackAll => { @@ -48,7 +48,7 @@ impl Printer { /// Prints the number of stack items specified by `n` if it is provided, otherwise prints /// the whole stack. - fn print_vm_stack(&self, process: &S, n: Option) { + fn print_vm_stack(&self, process: ProcessState, n: Option) { let stack = process.get_stack_state(); // determine how many items to print out @@ -72,7 +72,7 @@ impl Printer { } /// Prints the whole memory state at the cycle `clk` in context `ctx`. - fn print_mem_all(&self, process: &S) { + fn print_mem_all(&self, process: ProcessState) { let mem = process.get_mem_state(self.ctx); let padding = mem.iter().fold(0, |max, value| word_elem_max_len(Some(value.1)).max(max)) as usize; @@ -91,7 +91,7 @@ impl Printer { } /// Prints memory values in the provided addresses interval. - fn print_mem_interval(&self, process: &S, n: u32, m: u32) { + fn print_mem_interval(&self, process: ProcessState, n: u32, m: u32) { let mut mem_interval = Vec::new(); for addr in n..m + 1 { mem_interval.push((addr, process.get_mem_value(self.ctx, addr))); @@ -113,12 +113,7 @@ impl Printer { } /// Prints locals in provided indexes interval. - fn print_local_interval( - &self, - process: &S, - interval: (u32, u32), - num_locals: u32, - ) { + fn print_local_interval(&self, process: ProcessState, interval: (u32, u32), num_locals: u32) { let mut local_mem_interval = Vec::new(); let local_memory_offset = self.fmp - num_locals + 1; diff --git a/processor/src/host/mod.rs b/processor/src/host/mod.rs index 4e4289b33..0a5b7c65b 100644 --- a/processor/src/host/mod.rs +++ b/processor/src/host/mod.rs @@ -35,16 +35,16 @@ pub trait Host { // -------------------------------------------------------------------------------------------- /// Returns the requested advice, specified by [AdviceExtractor], from the host to the VM. - fn get_advice( + fn get_advice( &mut self, - process: &P, + process: ProcessState, extractor: AdviceExtractor, ) -> Result; /// Sets the requested advice, specified by [AdviceInjector], on the host. - fn set_advice( + fn set_advice( &mut self, - process: &P, + process: ProcessState, injector: AdviceInjector, ) -> Result; @@ -70,9 +70,9 @@ pub trait Host { } /// Handles the event emitted from the VM. - fn on_event( + fn on_event( &mut self, - _process: &S, + _process: ProcessState, _event_id: u32, ) -> Result { #[cfg(feature = "std")] @@ -86,9 +86,9 @@ pub trait Host { } /// Handles the debug request from the VM. - fn on_debug( + fn on_debug( &mut self, - _process: &S, + _process: ProcessState, _options: &DebugOptions, ) -> Result { #[cfg(feature = "std")] @@ -97,9 +97,9 @@ pub trait Host { } /// Handles the trace emitted from the VM. - fn on_trace( + fn on_trace( &mut self, - _process: &S, + _process: ProcessState, _trace_id: u32, ) -> Result { #[cfg(feature = "std")] @@ -113,7 +113,7 @@ pub trait Host { } /// Handles the failure of the assertion instruction. - fn on_assert_failed(&mut self, process: &S, err_code: u32) -> ExecutionError { + fn on_assert_failed(&mut self, process: ProcessState, err_code: u32) -> ExecutionError { ExecutionError::FailedAssertion { clk: process.clk(), err_code, @@ -125,7 +125,7 @@ pub trait Host { /// /// # Errors /// Returns an error if the advice stack is empty. - fn pop_adv_stack(&mut self, process: &S) -> Result { + fn pop_adv_stack(&mut self, process: ProcessState) -> Result { let response = self.get_advice(process, AdviceExtractor::PopStack)?; Ok(response.into()) } @@ -137,7 +137,7 @@ pub trait Host { /// /// # Errors /// Returns an error if the advice stack does not contain a full word. - fn pop_adv_stack_word(&mut self, process: &S) -> Result { + fn pop_adv_stack_word(&mut self, process: ProcessState) -> Result { let response = self.get_advice(process, AdviceExtractor::PopStackWord)?; Ok(response.into()) } @@ -150,10 +150,7 @@ pub trait Host { /// /// # Errors /// Returns an error if the advice stack does not contain two words. - fn pop_adv_stack_dword( - &mut self, - process: &S, - ) -> Result<[Word; 2], ExecutionError> { + fn pop_adv_stack_dword(&mut self, process: ProcessState) -> Result<[Word; 2], ExecutionError> { let response = self.get_advice(process, AdviceExtractor::PopStackDWord)?; Ok(response.into()) } @@ -167,10 +164,7 @@ pub trait Host { /// - The specified depth is either zero or greater than the depth of the Merkle tree identified /// by the specified root. /// - Path to the node at the specified depth and index is not known to this advice provider. - fn get_adv_merkle_path( - &mut self, - process: &S, - ) -> Result { + fn get_adv_merkle_path(&mut self, process: ProcessState) -> Result { let response = self.get_advice(process, AdviceExtractor::GetMerklePath)?; Ok(response.into()) } @@ -180,17 +174,17 @@ impl Host for &mut H where H: Host, { - fn get_advice( + fn get_advice( &mut self, - process: &S, + process: ProcessState, extractor: AdviceExtractor, ) -> Result { H::get_advice(self, process, extractor) } - fn set_advice( + fn set_advice( &mut self, - process: &S, + process: ProcessState, injector: AdviceInjector, ) -> Result { H::set_advice(self, process, injector) @@ -200,31 +194,31 @@ where H::get_mast_forest(self, node_digest) } - fn on_debug( + fn on_debug( &mut self, - process: &S, + process: ProcessState, options: &DebugOptions, ) -> Result { H::on_debug(self, process, options) } - fn on_event( + fn on_event( &mut self, - process: &S, + process: ProcessState, event_id: u32, ) -> Result { H::on_event(self, process, event_id) } - fn on_trace( + fn on_trace( &mut self, - process: &S, + process: ProcessState, trace_id: u32, ) -> Result { H::on_trace(self, process, trace_id) } - fn on_assert_failed(&mut self, process: &S, err_code: u32) -> ExecutionError { + fn on_assert_failed(&mut self, process: ProcessState, err_code: u32) -> ExecutionError { H::on_assert_failed(self, process, err_code) } } @@ -339,17 +333,17 @@ impl Host for DefaultHost where A: AdviceProvider, { - fn get_advice( + fn get_advice( &mut self, - process: &P, + process: ProcessState, extractor: AdviceExtractor, ) -> Result { self.adv_provider.get_advice(process, &extractor) } - fn set_advice( + fn set_advice( &mut self, - process: &P, + process: ProcessState, injector: AdviceInjector, ) -> Result { self.adv_provider.set_advice(process, &injector) diff --git a/processor/src/lib.rs b/processor/src/lib.rs index 037f9269b..0f3b41472 100644 --- a/processor/src/lib.rs +++ b/processor/src/lib.rs @@ -7,7 +7,6 @@ extern crate alloc; extern crate std; use alloc::vec::Vec; -use core::cell::RefCell; use miden_air::trace::{ CHIPLETS_WIDTH, DECODER_TRACE_WIDTH, MIN_TRACE_LEN, RANGE_CHECK_TRACE_WIDTH, STACK_TRACE_WIDTH, @@ -122,18 +121,18 @@ pub struct ChipletsTrace { /// Returns an execution trace resulting from executing the provided program against the provided /// inputs. +/// +/// The `host` parameter is used to provide the external environment to the program being executed, +/// such as access to the advice provider and libraries that the program depends on. #[tracing::instrument("execute_program", skip_all)] -pub fn execute( +pub fn execute( program: &Program, stack_inputs: StackInputs, - host: H, + host: &mut impl Host, options: ExecutionOptions, -) -> Result -where - H: Host, -{ - let mut process = Process::new(program.kernel().clone(), stack_inputs, host, options); - let stack_outputs = process.execute(program)?; +) -> Result { + let mut process = Process::new(program.kernel().clone(), stack_inputs, options); + let stack_outputs = process.execute(program, host)?; let trace = ExecutionTrace::new(process, stack_outputs); assert_eq!(&program.hash(), trace.program_hash(), "inconsistent program hash"); Ok(trace) @@ -141,12 +140,13 @@ where /// Returns an iterator which allows callers to step through the execution and inspect VM state at /// each execution step. -pub fn execute_iter(program: &Program, stack_inputs: StackInputs, host: H) -> VmStateIterator -where - H: Host, -{ - let mut process = Process::new_debug(program.kernel().clone(), stack_inputs, host); - let result = process.execute(program); +pub fn execute_iter( + program: &Program, + stack_inputs: StackInputs, + host: &mut impl Host, +) -> VmStateIterator { + let mut process = Process::new_debug(program.kernel().clone(), stack_inputs); + let result = process.execute(program, host); if result.is_ok() { assert_eq!( program.hash(), @@ -170,67 +170,49 @@ where /// to construct an instance of [Process] using [Process::new], invoke [Process::execute], and then /// get the execution trace using [ExecutionTrace::new] using the outputs produced by execution. #[cfg(not(any(test, feature = "testing")))] -pub struct Process -where - H: Host, -{ +pub struct Process { system: System, decoder: Decoder, stack: Stack, range: RangeChecker, chiplets: Chiplets, - host: RefCell, max_cycles: u32, enable_tracing: bool, } #[cfg(any(test, feature = "testing"))] -pub struct Process -where - H: Host, -{ +pub struct Process { pub system: System, pub decoder: Decoder, pub stack: Stack, pub range: RangeChecker, pub chiplets: Chiplets, - pub host: RefCell, pub max_cycles: u32, pub enable_tracing: bool, } -impl Process -where - H: Host, -{ +impl Process { // CONSTRUCTORS // -------------------------------------------------------------------------------------------- /// Creates a new process with the provided inputs. pub fn new( kernel: Kernel, stack_inputs: StackInputs, - host: H, execution_options: ExecutionOptions, ) -> Self { - Self::initialize(kernel, stack_inputs, host, execution_options) + Self::initialize(kernel, stack_inputs, execution_options) } /// Creates a new process with provided inputs and debug options enabled. - pub fn new_debug(kernel: Kernel, stack_inputs: StackInputs, host: H) -> Self { + pub fn new_debug(kernel: Kernel, stack_inputs: StackInputs) -> Self { Self::initialize( kernel, stack_inputs, - host, ExecutionOptions::default().with_tracing().with_debugging(), ) } - fn initialize( - kernel: Kernel, - stack: StackInputs, - host: H, - execution_options: ExecutionOptions, - ) -> Self { + fn initialize(kernel: Kernel, stack: StackInputs, execution_options: ExecutionOptions) -> Self { let in_debug_mode = execution_options.enable_debugging(); Self { system: System::new(execution_options.expected_cycles() as usize), @@ -238,7 +220,6 @@ where stack: Stack::new(&stack, execution_options.expected_cycles() as usize, in_debug_mode), range: RangeChecker::new(), chiplets: Chiplets::new(kernel), - host: RefCell::new(host), max_cycles: execution_options.max_cycles(), enable_tracing: execution_options.enable_tracing(), } @@ -248,12 +229,16 @@ where // -------------------------------------------------------------------------------------------- /// Executes the provided [`Program`] in this process. - pub fn execute(&mut self, program: &Program) -> Result { + pub fn execute( + &mut self, + program: &Program, + host: &mut impl Host, + ) -> Result { if self.system.clk() != 0 { return Err(ExecutionError::ProgramAlreadyExecuted); } - self.execute_mast_node(program.entrypoint(), &program.mast_forest().clone())?; + self.execute_mast_node(program.entrypoint(), &program.mast_forest().clone(), host)?; self.stack.build_stack_outputs() } @@ -265,27 +250,26 @@ where &mut self, node_id: MastNodeId, program: &MastForest, + host: &mut impl Host, ) -> Result<(), ExecutionError> { let node = program .get_node_by_id(node_id) .ok_or(ExecutionError::MastNodeNotFoundInForest { node_id })?; for &decorator_id in node.before_enter() { - self.execute_decorator(&program[decorator_id])?; + self.execute_decorator(&program[decorator_id], host)?; } match node { - MastNode::Block(node) => self.execute_basic_block_node(node, program)?, - MastNode::Join(node) => self.execute_join_node(node, program)?, - MastNode::Split(node) => self.execute_split_node(node, program)?, - MastNode::Loop(node) => self.execute_loop_node(node, program)?, - MastNode::Call(node) => self.execute_call_node(node, program)?, - MastNode::Dyn(node) => self.execute_dyn_node(node, program)?, + MastNode::Block(node) => self.execute_basic_block_node(node, program, host)?, + MastNode::Join(node) => self.execute_join_node(node, program, host)?, + MastNode::Split(node) => self.execute_split_node(node, program, host)?, + MastNode::Loop(node) => self.execute_loop_node(node, program, host)?, + MastNode::Call(node) => self.execute_call_node(node, program, host)?, + MastNode::Dyn(node) => self.execute_dyn_node(node, program, host)?, MastNode::External(external_node) => { let node_digest = external_node.digest(); - let mast_forest = self - .host - .borrow() + let mast_forest = host .get_mast_forest(&node_digest) .ok_or(ExecutionError::MastForestNotFound { root_digest: node_digest })?; @@ -301,12 +285,12 @@ where return Err(ExecutionError::CircularExternalNode(node_digest)); } - self.execute_mast_node(root_id, &mast_forest)?; + self.execute_mast_node(root_id, &mast_forest, host)?; }, } for &decorator_id in node.after_exit() { - self.execute_decorator(&program[decorator_id])?; + self.execute_decorator(&program[decorator_id], host)?; } Ok(()) @@ -318,14 +302,15 @@ where &mut self, node: &JoinNode, program: &MastForest, + host: &mut impl Host, ) -> Result<(), ExecutionError> { - self.start_join_node(node, program)?; + self.start_join_node(node, program, host)?; // execute first and then second child of the join block - self.execute_mast_node(node.first(), program)?; - self.execute_mast_node(node.second(), program)?; + self.execute_mast_node(node.first(), program, host)?; + self.execute_mast_node(node.second(), program, host)?; - self.end_join_node(node) + self.end_join_node(node, host) } /// Executes the specified [SplitNode]. @@ -334,20 +319,21 @@ where &mut self, node: &SplitNode, program: &MastForest, + host: &mut impl Host, ) -> Result<(), ExecutionError> { // start the SPLIT block; this also pops the stack and returns the popped element - let condition = self.start_split_node(node, program)?; + let condition = self.start_split_node(node, program, host)?; // execute either the true or the false branch of the split block based on the condition if condition == ONE { - self.execute_mast_node(node.on_true(), program)?; + self.execute_mast_node(node.on_true(), program, host)?; } else if condition == ZERO { - self.execute_mast_node(node.on_false(), program)?; + self.execute_mast_node(node.on_false(), program, host)?; } else { return Err(ExecutionError::NotBinaryValue(condition)); } - self.end_split_node(node) + self.end_split_node(node, host) } /// Executes the specified [LoopNode]. @@ -356,30 +342,31 @@ where &mut self, node: &LoopNode, program: &MastForest, + host: &mut impl Host, ) -> Result<(), ExecutionError> { // start the LOOP block; this also pops the stack and returns the popped element - let condition = self.start_loop_node(node, program)?; + let condition = self.start_loop_node(node, program, host)?; // if the top of the stack is ONE, execute the loop body; otherwise skip the loop body if condition == ONE { // execute the loop body at least once - self.execute_mast_node(node.body(), program)?; + self.execute_mast_node(node.body(), program, host)?; // keep executing the loop body until the condition on the top of the stack is no // longer ONE; each iteration of the loop is preceded by executing REPEAT operation // which drops the condition from the stack while self.stack.peek() == ONE { self.decoder.repeat(); - self.execute_op(Operation::Drop)?; - self.execute_mast_node(node.body(), program)?; + self.execute_op(Operation::Drop, host)?; + self.execute_mast_node(node.body(), program, host)?; } // end the LOOP block and drop the condition from the stack - self.end_loop_node(node, true) + self.end_loop_node(node, true, host) } else if condition == ZERO { // end the LOOP block, but don't drop the condition from the stack because it was // already dropped when we started the LOOP block - self.end_loop_node(node, false) + self.end_loop_node(node, false, host) } else { Err(ExecutionError::NotBinaryValue(condition)) } @@ -391,6 +378,7 @@ where &mut self, call_node: &CallNode, program: &MastForest, + host: &mut impl Host, ) -> Result<(), ExecutionError> { // if this is a syscall, make sure the call target exists in the kernel if call_node.is_syscall() { @@ -400,9 +388,9 @@ where self.chiplets.access_kernel_proc(callee.digest())?; } - self.start_call_node(call_node, program)?; - self.execute_mast_node(call_node.callee(), program)?; - self.end_call_node(call_node) + self.start_call_node(call_node, program, host)?; + self.execute_mast_node(call_node.callee(), program, host)?; + self.end_call_node(call_node, host) } /// Executes the specified [vm_core::mast::DynNode]. @@ -414,22 +402,21 @@ where &mut self, node: &DynNode, program: &MastForest, + host: &mut impl Host, ) -> Result<(), ExecutionError> { let callee_hash = if node.is_dyncall() { self.start_dyncall_node(node)? } else { - self.start_dyn_node(node)? + self.start_dyn_node(node, host)? }; // if the callee is not in the program's MAST forest, try to find a MAST forest for it in // the host (corresponding to an external library loaded in the host); if none are // found, return an error. match program.find_procedure_root(callee_hash.into()) { - Some(callee_id) => self.execute_mast_node(callee_id, program)?, + Some(callee_id) => self.execute_mast_node(callee_id, program, host)?, None => { - let mast_forest = self - .host - .borrow() + let mast_forest = host .get_mast_forest(&callee_hash.into()) .ok_or_else(|| ExecutionError::DynamicNodeNotFound(callee_hash.into()))?; @@ -439,14 +426,14 @@ where ExecutionError::MalformedMastForestInHost { root_digest: callee_hash.into() }, )?; - self.execute_mast_node(root_id, &mast_forest)? + self.execute_mast_node(root_id, &mast_forest, host)? }, } if node.is_dyncall() { - self.end_dyncall_node(node) + self.end_dyncall_node(node, host) } else { - self.end_dyn_node(node) + self.end_dyn_node(node, host) } } @@ -456,8 +443,9 @@ where &mut self, basic_block: &BasicBlockNode, program: &MastForest, + host: &mut impl Host, ) -> Result<(), ExecutionError> { - self.start_basic_block_node(basic_block)?; + self.start_basic_block_node(basic_block, host)?; let mut op_offset = 0; let mut decorator_ids = basic_block.decorator_iter(); @@ -468,6 +456,7 @@ where &mut decorator_ids, op_offset, program, + host, )?; op_offset += basic_block.op_batches()[0].ops().len(); @@ -476,12 +465,12 @@ where // of the stack for op_batch in basic_block.op_batches().iter().skip(1) { self.respan(op_batch); - self.execute_op(Operation::Noop)?; - self.execute_op_batch(op_batch, &mut decorator_ids, op_offset, program)?; + self.execute_op(Operation::Noop, host)?; + self.execute_op_batch(op_batch, &mut decorator_ids, op_offset, program, host)?; op_offset += op_batch.ops().len(); } - self.end_basic_block_node(basic_block)?; + self.end_basic_block_node(basic_block, host)?; // execute any decorators which have not been executed during span ops execution; this // can happen for decorators appearing after all operations in a block. these decorators @@ -491,7 +480,7 @@ where let decorator = program .get_decorator_by_id(decorator_id) .ok_or(ExecutionError::DecoratorNotFoundInForest { decorator_id })?; - self.execute_decorator(decorator)?; + self.execute_decorator(decorator, host)?; } Ok(()) @@ -510,6 +499,7 @@ where decorators: &mut DecoratorIterator, op_offset: usize, program: &MastForest, + host: &mut impl Host, ) -> Result<(), ExecutionError> { let op_counts = batch.op_counts(); let mut op_idx = 0; @@ -527,12 +517,12 @@ where let decorator = program .get_decorator_by_id(decorator_id) .ok_or(ExecutionError::DecoratorNotFoundInForest { decorator_id })?; - self.execute_decorator(decorator)?; + self.execute_decorator(decorator, host)?; } // decode and execute the operation self.decoder.execute_user_op(op, op_idx); - self.execute_op(op)?; + self.execute_op(op, host)?; // if the operation carries an immediate value, the value is stored at the next group // pointer; so, we advance the pointer to the following group @@ -552,7 +542,7 @@ where // bug somewhere in the assembler) debug_assert!(op_idx < OP_GROUP_SIZE - 1, "invalid op index"); self.decoder.execute_user_op(Operation::Noop, op_idx + 1); - self.execute_op(Operation::Noop)?; + self.execute_op(Operation::Noop, host)?; } // then, move to the next group and reset operation index @@ -575,7 +565,7 @@ where // the actual number of operation groups was not a power of two for group_idx in group_idx..num_batch_groups { self.decoder.execute_user_op(Operation::Noop, 0); - self.execute_op(Operation::Noop)?; + self.execute_op(Operation::Noop, host)?; // if we are not at the last group yet, set up the decoder for decoding the next // operation groups. the groups were are processing are just NOOPs - so, the op group @@ -589,14 +579,18 @@ where } /// Executes the specified decorator - fn execute_decorator(&mut self, decorator: &Decorator) -> Result<(), ExecutionError> { + fn execute_decorator( + &mut self, + decorator: &Decorator, + host: &mut impl Host, + ) -> Result<(), ExecutionError> { match decorator { Decorator::Advice(injector) => { - self.host.borrow_mut().set_advice(self, *injector)?; + host.set_advice(self.into(), *injector)?; }, Decorator::Debug(options) => { if self.decoder.in_debug_mode() { - self.host.borrow_mut().on_debug(self, options)?; + host.on_debug(self.into(), options)?; } }, Decorator::AsmOp(assembly_op) => { @@ -606,7 +600,7 @@ where }, Decorator::Trace(id) => { if self.enable_tracing { - self.host.borrow_mut().on_trace(self, *id)?; + host.on_trace(self.into(), *id)?; } }, } @@ -614,40 +608,47 @@ where } // PUBLIC ACCESSORS - // -------------------------------------------------------------------------------------------- + // ================================================================================================ pub const fn kernel(&self) -> &Kernel { self.chiplets.kernel() } - pub fn into_parts(self) -> (System, Decoder, Stack, RangeChecker, Chiplets, H) { - ( - self.system, - self.decoder, - self.stack, - self.range, - self.chiplets, - self.host.into_inner(), - ) + pub fn into_parts(self) -> (System, Decoder, Stack, RangeChecker, Chiplets) { + (self.system, self.decoder, self.stack, self.range, self.chiplets) } } // PROCESS STATE // ================================================================================================ -/// A trait that defines a set of methods which allow access to the state of the process. -pub trait ProcessState { +#[derive(Debug, Clone, Copy)] +pub struct ProcessState<'a> { + system: &'a System, + stack: &'a Stack, + chiplets: &'a Chiplets, +} + +impl ProcessState<'_> { /// Returns the current clock cycle of a process. - fn clk(&self) -> RowIndex; + pub fn clk(&self) -> RowIndex { + self.system.clk() + } /// Returns the current execution context ID. - fn ctx(&self) -> ContextId; + pub fn ctx(&self) -> ContextId { + self.system.ctx() + } /// Returns the current value of the free memory pointer. - fn fmp(&self) -> u64; + pub fn fmp(&self) -> u64 { + self.system.fmp().as_int() + } /// Returns the value located at the specified position on the stack at the current clock cycle. - fn get_stack_item(&self, pos: usize) -> Felt; + pub fn get_stack_item(&self, pos: usize) -> Felt { + self.stack.get(pos) + } /// Returns a word located at the specified word index on the stack. /// @@ -659,54 +660,48 @@ pub trait ProcessState { /// stack will be at the last position in the word. /// /// Creating a word does not change the state of the stack. - fn get_stack_word(&self, word_idx: usize) -> Word; + pub fn get_stack_word(&self, word_idx: usize) -> Word { + self.stack.get_word(word_idx) + } /// Returns stack state at the current clock cycle. This includes the top 16 items of the /// stack + overflow entries. - fn get_stack_state(&self) -> Vec; + pub fn get_stack_state(&self) -> Vec { + self.stack.get_state_at(self.system.clk()) + } /// Returns a word located at the specified context/address, or None if the address hasn't /// been accessed previously. - fn get_mem_value(&self, ctx: ContextId, addr: u32) -> Option; + pub fn get_mem_value(&self, ctx: ContextId, addr: u32) -> Option { + self.chiplets.get_mem_value(ctx, addr) + } /// Returns the entire memory state for the specified execution context at the current clock /// cycle. /// /// The state is returned as a vector of (address, value) tuples, and includes addresses which /// have been accessed at least once. - fn get_mem_state(&self, ctx: ContextId) -> Vec<(u64, Word)>; -} - -impl ProcessState for Process { - fn clk(&self) -> RowIndex { - self.system.clk() - } - - fn ctx(&self) -> ContextId { - self.system.ctx() - } - - fn fmp(&self) -> u64 { - self.system.fmp().as_int() - } - - fn get_stack_item(&self, pos: usize) -> Felt { - self.stack.get(pos) - } - - fn get_stack_word(&self, word_idx: usize) -> Word { - self.stack.get_word(word_idx) - } - - fn get_stack_state(&self) -> Vec { - self.stack.get_state_at(self.system.clk()) + pub fn get_mem_state(&self, ctx: ContextId) -> Vec<(u64, Word)> { + self.chiplets.get_mem_state_at(ctx, self.system.clk()) } +} - fn get_mem_value(&self, ctx: ContextId, addr: u32) -> Option { - self.chiplets.get_mem_value(ctx, addr) +impl<'a> From<&'a Process> for ProcessState<'a> { + fn from(process: &'a Process) -> Self { + Self { + system: &process.system, + stack: &process.stack, + chiplets: &process.chiplets, + } } +} - fn get_mem_state(&self, ctx: ContextId) -> Vec<(u64, Word)> { - self.chiplets.get_mem_state_at(ctx, self.system.clk()) +impl<'a> From<&'a mut Process> for ProcessState<'a> { + fn from(process: &'a mut Process) -> Self { + Self { + system: &process.system, + stack: &process.stack, + chiplets: &process.chiplets, + } } } diff --git a/processor/src/operations/comb_ops.rs b/processor/src/operations/comb_ops.rs index f1ab1f8d4..03181d37a 100644 --- a/processor/src/operations/comb_ops.rs +++ b/processor/src/operations/comb_ops.rs @@ -1,14 +1,11 @@ use vm_core::{Felt, Operation, ONE, ZERO}; -use crate::{ExecutionError, Host, Process, QuadFelt}; +use crate::{ExecutionError, Process, QuadFelt}; // RANDOM LINEAR COMBINATION OPERATIONS // ================================================================================================ -impl Process -where - H: Host, -{ +impl Process { // COMBINE VALUES USING RANDOMNESS // -------------------------------------------------------------------------------------------- /// Performs a single step in the computation of the random linear combination: @@ -177,7 +174,7 @@ mod tests { use test_utils::{build_test, rand::rand_array, TRUNCATE_STACK_PROC}; use vm_core::{Felt, FieldElement, Operation, StackInputs, ONE, ZERO}; - use crate::{ContextId, Process, QuadFelt}; + use crate::{ContextId, DefaultHost, Process, QuadFelt}; #[test] fn rcombine_main() { @@ -197,6 +194,7 @@ mod tests { inputs.reverse(); // --- setup the operand stack ------------------------------------------------------------ + let mut host = DefaultHost::default(); let stack_inputs = StackInputs::new(inputs.to_vec()).expect("inputs lenght too long"); let mut process = Process::new_dummy_with_decoder_helpers(stack_inputs); @@ -221,10 +219,10 @@ mod tests { a, ) .unwrap(); - process.execute_op(Operation::Noop).unwrap(); + process.execute_op(Operation::Noop, &mut host).unwrap(); // --- execute RCOMB1 operation ----------------------------------------------------------- - process.execute_op(Operation::RCombBase).unwrap(); + process.execute_op(Operation::RCombBase, &mut host).unwrap(); // --- check that the top 8 stack elements are correctly rotated -------------------------- let stack_state = process.stack.trace_state(); diff --git a/processor/src/operations/crypto_ops.rs b/processor/src/operations/crypto_ops.rs index ef58cee8f..5a3049961 100644 --- a/processor/src/operations/crypto_ops.rs +++ b/processor/src/operations/crypto_ops.rs @@ -1,15 +1,12 @@ use vm_core::AdviceInjector; -use super::{ExecutionError, Host, Operation, Process}; -use crate::crypto::MerklePath; +use super::{ExecutionError, Operation, Process}; +use crate::{crypto::MerklePath, Host}; // CRYPTOGRAPHIC OPERATIONS // ================================================================================================ -impl Process -where - H: Host, -{ +impl Process { // HASHING OPERATIONS // -------------------------------------------------------------------------------------------- /// Performs a Rescue Prime Optimized permutation to the top 12 elements of the operand stack, @@ -68,7 +65,11 @@ where /// /// # Panics /// Panics if the computed root does not match the root provided via the stack. - pub(super) fn op_mpverify(&mut self, err_code: u32) -> Result<(), ExecutionError> { + pub(super) fn op_mpverify( + &mut self, + err_code: u32, + host: &mut impl Host, + ) -> Result<(), ExecutionError> { // read node value, depth, index and root value from the stack let node = [self.stack.get(3), self.stack.get(2), self.stack.get(1), self.stack.get(0)]; let index = self.stack.get(5); @@ -76,7 +77,7 @@ where // get a Merkle path from the advice provider for the specified root and node index. // the path is expected to be of the specified depth. - let path = self.host.borrow_mut().get_adv_merkle_path(self)?; + let path = host.get_adv_merkle_path(self.into())?; // use hasher to compute the Merkle root of the path let (addr, computed_root) = self.chiplets.build_merkle_root(node, &path, index); @@ -134,7 +135,7 @@ where /// /// # Panics /// Panics if the computed old root does not match the input root provided via the stack. - pub(super) fn op_mrupdate(&mut self) -> Result<(), ExecutionError> { + pub(super) fn op_mrupdate(&mut self, host: &mut impl Host) -> Result<(), ExecutionError> { // read old node value, depth, index, tree root and new node values from the stack let old_node = [self.stack.get(3), self.stack.get(2), self.stack.get(1), self.stack.get(0)]; let depth = self.stack.get(4); @@ -147,11 +148,8 @@ where // get a Merkle path to it. the length of the returned path is expected to match the // specified depth. if the new node is the root of a tree, this instruction will append the // whole sub-tree to this node. - let path: MerklePath = self - .host - .borrow_mut() - .set_advice(self, AdviceInjector::UpdateMerkleNode)? - .into(); + let path: MerklePath = + host.set_advice(self.into(), AdviceInjector::UpdateMerkleNode)?.into(); assert_eq!(path.len(), depth.as_int() as usize); @@ -194,7 +192,7 @@ mod tests { super::{Felt, Operation}, Process, }; - use crate::{AdviceInputs, StackInputs, Word, ZERO}; + use crate::{AdviceInputs, DefaultHost, StackInputs, Word, ZERO}; #[test] fn op_hperm() { @@ -207,9 +205,10 @@ mod tests { ]; let stack = StackInputs::try_from_ints(inputs).unwrap(); let mut process = Process::new_dummy_with_decoder_helpers(stack); + let mut host = DefaultHost::default(); let expected: [Felt; STATE_WIDTH] = build_expected_perm(&inputs); - process.execute_op(Operation::HPerm).unwrap(); + process.execute_op(Operation::HPerm, &mut host).unwrap(); assert_eq!(expected, &process.stack.trace_state()[0..12]); // --- test hashing 8 random values ------------------------------------------------------- @@ -221,7 +220,7 @@ mod tests { // add the capacity to prepare the input vector let expected: [Felt; STATE_WIDTH] = build_expected_perm(&inputs); - process.execute_op(Operation::HPerm).unwrap(); + process.execute_op(Operation::HPerm, &mut host).unwrap(); assert_eq!(expected, &process.stack.trace_state()[0..12]); // --- test that the rest of the stack isn't affected ------------------------------------- @@ -232,7 +231,7 @@ mod tests { let stack = StackInputs::try_from_ints(inputs).unwrap(); let mut process = Process::new_dummy_with_decoder_helpers(stack); - process.execute_op(Operation::HPerm).unwrap(); + process.execute_op(Operation::HPerm, &mut host).unwrap(); assert_eq!(expected, &process.stack.trace_state()[12..16]); } @@ -265,10 +264,10 @@ mod tests { let advice_inputs = AdviceInputs::default().with_merkle_store(store); let stack_inputs = StackInputs::try_from_ints(stack_inputs).unwrap(); - let mut process = + let (mut process, mut host) = Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs); - process.execute_op(Operation::MpVerify(0)).unwrap(); + process.execute_op(Operation::MpVerify(0), &mut host).unwrap(); let expected_stack = build_expected(&[ node[3], node[2], node[1], node[0], depth, index, root[3], root[2], root[1], root[0], ]); @@ -307,11 +306,11 @@ mod tests { let store = MerkleStore::from(&tree); let advice_inputs = AdviceInputs::default().with_merkle_store(store); let stack_inputs = StackInputs::try_from_ints(stack_inputs).unwrap(); - let mut process = + let (mut process, mut host) = Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs); // update the Merkle tree but keep the old copy - process.execute_op(Operation::MrUpdate).unwrap(); + process.execute_op(Operation::MrUpdate, &mut host).unwrap(); let expected_stack = build_expected(&[ new_tree.root()[3], new_tree.root()[2], @@ -331,8 +330,8 @@ mod tests { assert_eq!(expected_stack, process.stack.trace_state()); // make sure both Merkle trees are still in the advice provider - assert!(process.host.borrow().advice_provider().has_merkle_root(tree.root())); - assert!(process.host.borrow().advice_provider().has_merkle_root(new_tree.root())); + assert!(host.advice_provider().has_merkle_root(tree.root())); + assert!(host.advice_provider().has_merkle_root(new_tree.root())); } #[test] @@ -385,14 +384,14 @@ mod tests { replaced_node[3].as_int(), ]; let stack_inputs = StackInputs::try_from_ints(stack_inputs).unwrap(); - let mut process = + let (mut process, mut host) = Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs); // assert the expected root doesn't exist before the merge operation - assert!(!process.host.borrow().advice_provider().has_merkle_root(expected_root)); + assert!(!host.advice_provider().has_merkle_root(expected_root)); // update the previous root - process.execute_op(Operation::MrUpdate).unwrap(); + process.execute_op(Operation::MrUpdate, &mut host).unwrap(); let expected_stack = build_expected(&[ expected_root[3], expected_root[2], @@ -412,7 +411,7 @@ mod tests { assert_eq!(expected_stack, process.stack.trace_state()); // assert the expected root now exists in the advice provider - assert!(process.host.borrow().advice_provider().has_merkle_root(expected_root)); + assert!(host.advice_provider().has_merkle_root(expected_root)); } // HELPER FUNCTIONS diff --git a/processor/src/operations/ext2_ops.rs b/processor/src/operations/ext2_ops.rs index e10d80f4b..731766037 100644 --- a/processor/src/operations/ext2_ops.rs +++ b/processor/src/operations/ext2_ops.rs @@ -1,14 +1,11 @@ -use super::{ExecutionError, Felt, Host, Process}; +use super::{ExecutionError, Felt, Process}; // EXTENSION FIELD OPERATIONS // ================================================================================================ const TWO: Felt = Felt::new(2); -impl Process -where - H: Host, -{ +impl Process { // ARITHMETIC OPERATIONS // -------------------------------------------------------------------------------------------- /// Gets the top four values from the stack [b1, b0, a1, a0], where a = (a1, a0) and @@ -40,7 +37,7 @@ mod tests { super::{Felt, Operation, MIN_STACK_DEPTH}, Process, }; - use crate::{StackInputs, ZERO}; + use crate::{DefaultHost, StackInputs, ZERO}; // ARITHMETIC OPERATIONS // -------------------------------------------------------------------------------------------- @@ -51,10 +48,11 @@ mod tests { let [a0, a1, b0, b1] = [rand_value(); 4]; let stack = StackInputs::new(vec![a0, a1, b0, b1]).expect("inputs lenght too long"); + let mut host = DefaultHost::default(); let mut process = Process::new_dummy(stack); // multiply the top two values - process.execute_op(Operation::Ext2Mul).unwrap(); + process.execute_op(Operation::Ext2Mul, &mut host).unwrap(); let a = QuadFelt::new(a0, a1); let b = QuadFelt::new(b0, b1); let c = (b * a).to_base_elements(); @@ -67,7 +65,7 @@ mod tests { // calling ext2mul with a stack of minimum depth is ok let stack = StackInputs::new(vec![]).expect("inputs lenght too long"); let mut process = Process::new_dummy(stack); - assert!(process.execute_op(Operation::Ext2Mul).is_ok()); + assert!(process.execute_op(Operation::Ext2Mul, &mut host).is_ok()); } // HELPER FUNCTIONS diff --git a/processor/src/operations/field_ops.rs b/processor/src/operations/field_ops.rs index 2fa799ed5..f874da6bc 100644 --- a/processor/src/operations/field_ops.rs +++ b/processor/src/operations/field_ops.rs @@ -1,14 +1,11 @@ use vm_core::{Operation, ONE, ZERO}; -use super::{utils::assert_binary, ExecutionError, Felt, FieldElement, Host, Process}; +use super::{utils::assert_binary, ExecutionError, Felt, FieldElement, Process}; // FIELD OPERATIONS // ================================================================================================ -impl Process -where - H: Host, -{ +impl Process { // ARITHMETIC OPERATIONS // -------------------------------------------------------------------------------------------- /// Pops two elements off the stack, adds them together, and pushes the result back onto the @@ -230,7 +227,7 @@ mod tests { super::{Felt, FieldElement, Operation, MIN_STACK_DEPTH}, Process, }; - use crate::{AdviceInputs, StackInputs}; + use crate::{AdviceInputs, DefaultHost, StackInputs}; // ARITHMETIC OPERATIONS // -------------------------------------------------------------------------------------------- @@ -241,9 +238,10 @@ mod tests { let (a, b, c) = get_rand_values(); let stack = StackInputs::try_from_ints([c.as_int(), b.as_int(), a.as_int()]).unwrap(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); // add the top two values - process.execute_op(Operation::Add).unwrap(); + process.execute_op(Operation::Add, &mut host).unwrap(); let expected = build_expected(&[a + b, c]); assert_eq!(MIN_STACK_DEPTH, process.stack.depth()); @@ -252,7 +250,7 @@ mod tests { // calling add with a stack of minimum depth is ok let mut process = Process::new_dummy_with_empty_stack(); - assert!(process.execute_op(Operation::Add).is_ok()); + assert!(process.execute_op(Operation::Add, &mut host).is_ok()); } #[test] @@ -261,9 +259,10 @@ mod tests { let (a, b, c) = get_rand_values(); let stack = StackInputs::try_from_ints([c.as_int(), b.as_int(), a.as_int()]).unwrap(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); // negate the top value - process.execute_op(Operation::Neg).unwrap(); + process.execute_op(Operation::Neg, &mut host).unwrap(); let expected = build_expected(&[-a, b, c]); assert_eq!(expected, process.stack.trace_state()); @@ -277,9 +276,10 @@ mod tests { let (a, b, c) = get_rand_values(); let stack = StackInputs::try_from_ints([c.as_int(), b.as_int(), a.as_int()]).unwrap(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); // add the top two values - process.execute_op(Operation::Mul).unwrap(); + process.execute_op(Operation::Mul, &mut host).unwrap(); let expected = build_expected(&[a * b, c]); assert_eq!(MIN_STACK_DEPTH, process.stack.depth()); @@ -288,7 +288,7 @@ mod tests { // calling mul with a stack of minimum depth is ok let mut process = Process::new_dummy_with_empty_stack(); - assert!(process.execute_op(Operation::Mul).is_ok()); + assert!(process.execute_op(Operation::Mul, &mut host).is_ok()); } #[test] @@ -297,10 +297,11 @@ mod tests { let (a, b, c) = get_rand_values(); let stack = StackInputs::try_from_ints([c.as_int(), b.as_int(), a.as_int()]).unwrap(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); // invert the top value if b != ZERO { - process.execute_op(Operation::Inv).unwrap(); + process.execute_op(Operation::Inv, &mut host).unwrap(); let expected = build_expected(&[a.inv(), b, c]); assert_eq!(MIN_STACK_DEPTH, process.stack.depth()); @@ -309,8 +310,8 @@ mod tests { } // inverting zero should be an error - process.execute_op(Operation::Pad).unwrap(); - assert!(process.execute_op(Operation::Inv).is_err()); + process.execute_op(Operation::Pad, &mut host).unwrap(); + assert!(process.execute_op(Operation::Inv, &mut host).is_err()); } #[test] @@ -319,9 +320,10 @@ mod tests { let (a, b, c) = get_rand_values(); let stack = StackInputs::try_from_ints([c.as_int(), b.as_int(), a.as_int()]).unwrap(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); // negate the top value - process.execute_op(Operation::Incr).unwrap(); + process.execute_op(Operation::Incr, &mut host).unwrap(); let expected = build_expected(&[a + ONE, b, c]); assert_eq!(MIN_STACK_DEPTH, process.stack.depth()); @@ -334,11 +336,12 @@ mod tests { #[test] fn op_and() { + let mut host = DefaultHost::default(); // --- test 0 AND 0 --------------------------------------------------- let stack = StackInputs::try_from_ints([2, 0, 0]).unwrap(); let mut process = Process::new_dummy(stack); - process.execute_op(Operation::And).unwrap(); + process.execute_op(Operation::And, &mut host).unwrap(); let expected = build_expected(&[ZERO, Felt::new(2)]); assert_eq!(expected, process.stack.trace_state()); @@ -346,7 +349,7 @@ mod tests { let stack = StackInputs::try_from_ints([2, 0, 1]).unwrap(); let mut process = Process::new_dummy(stack); - process.execute_op(Operation::And).unwrap(); + process.execute_op(Operation::And, &mut host).unwrap(); let expected = build_expected(&[ZERO, Felt::new(2)]); assert_eq!(expected, process.stack.trace_state()); @@ -354,7 +357,7 @@ mod tests { let stack = StackInputs::try_from_ints([2, 1, 0]).unwrap(); let mut process = Process::new_dummy(stack); - process.execute_op(Operation::And).unwrap(); + process.execute_op(Operation::And, &mut host).unwrap(); let expected = build_expected(&[ZERO, Felt::new(2)]); assert_eq!(expected, process.stack.trace_state()); @@ -362,32 +365,33 @@ mod tests { let stack = StackInputs::try_from_ints([2, 1, 1]).unwrap(); let mut process = Process::new_dummy(stack); - process.execute_op(Operation::And).unwrap(); + process.execute_op(Operation::And, &mut host).unwrap(); let expected = build_expected(&[ONE, Felt::new(2)]); assert_eq!(expected, process.stack.trace_state()); // --- first operand is not binary ------------------------------------ let stack = StackInputs::try_from_ints([2, 1, 2]).unwrap(); let mut process = Process::new_dummy(stack); - assert!(process.execute_op(Operation::And).is_err()); + assert!(process.execute_op(Operation::And, &mut host).is_err()); // --- second operand is not binary ----------------------------------- let stack = StackInputs::try_from_ints([2, 2, 1]).unwrap(); let mut process = Process::new_dummy(stack); - assert!(process.execute_op(Operation::And).is_err()); + assert!(process.execute_op(Operation::And, &mut host).is_err()); // --- calling AND with a stack of minimum depth is ok ---------------- let mut process = Process::new_dummy_with_empty_stack(); - assert!(process.execute_op(Operation::And).is_ok()); + assert!(process.execute_op(Operation::And, &mut host).is_ok()); } #[test] fn op_or() { + let mut host = DefaultHost::default(); // --- test 0 OR 0 --------------------------------------------------- let stack = StackInputs::try_from_ints([2, 0, 0]).unwrap(); let mut process = Process::new_dummy(stack); - process.execute_op(Operation::Or).unwrap(); + process.execute_op(Operation::Or, &mut host).unwrap(); let expected = build_expected(&[ZERO, Felt::new(2)]); assert_eq!(expected, process.stack.trace_state()); @@ -395,7 +399,7 @@ mod tests { let stack = StackInputs::try_from_ints([2, 0, 1]).unwrap(); let mut process = Process::new_dummy(stack); - process.execute_op(Operation::Or).unwrap(); + process.execute_op(Operation::Or, &mut host).unwrap(); let expected = build_expected(&[ONE, Felt::new(2)]); assert_eq!(expected, process.stack.trace_state()); @@ -403,7 +407,7 @@ mod tests { let stack = StackInputs::try_from_ints([2, 1, 0]).unwrap(); let mut process = Process::new_dummy(stack); - process.execute_op(Operation::Or).unwrap(); + process.execute_op(Operation::Or, &mut host).unwrap(); let expected = build_expected(&[ONE, Felt::new(2)]); assert_eq!(expected, process.stack.trace_state()); @@ -411,45 +415,46 @@ mod tests { let stack = StackInputs::try_from_ints([2, 1, 1]).unwrap(); let mut process = Process::new_dummy(stack); - process.execute_op(Operation::Or).unwrap(); + process.execute_op(Operation::Or, &mut host).unwrap(); let expected = build_expected(&[ONE, Felt::new(2)]); assert_eq!(expected, process.stack.trace_state()); // --- first operand is not binary ------------------------------------ let stack = StackInputs::try_from_ints([2, 1, 2]).unwrap(); let mut process = Process::new_dummy(stack); - assert!(process.execute_op(Operation::Or).is_err()); + assert!(process.execute_op(Operation::Or, &mut host).is_err()); // --- second operand is not binary ----------------------------------- let stack = StackInputs::try_from_ints([2, 2, 1]).unwrap(); let mut process = Process::new_dummy(stack); - assert!(process.execute_op(Operation::Or).is_err()); + assert!(process.execute_op(Operation::Or, &mut host).is_err()); // --- calling OR with a stack of minimum depth is a ok ---------------- let mut process = Process::new_dummy_with_empty_stack(); - assert!(process.execute_op(Operation::Or).is_ok()); + assert!(process.execute_op(Operation::Or, &mut host).is_ok()); } #[test] fn op_not() { + let mut host = DefaultHost::default(); // --- test NOT 0 ----------------------------------------------------- let stack = StackInputs::try_from_ints([2, 0]).unwrap(); let mut process = Process::new_dummy(stack); - process.execute_op(Operation::Not).unwrap(); + process.execute_op(Operation::Not, &mut host).unwrap(); let expected = build_expected(&[ONE, Felt::new(2)]); assert_eq!(expected, process.stack.trace_state()); // --- test NOT 1 ---------------------------------------------------- let stack = StackInputs::try_from_ints([2, 1]).unwrap(); let mut process = Process::new_dummy(stack); - process.execute_op(Operation::Not).unwrap(); + process.execute_op(Operation::Not, &mut host).unwrap(); let expected = build_expected(&[ZERO, Felt::new(2)]); assert_eq!(expected, process.stack.trace_state()); // --- operand is not binary ------------------------------------------ let stack = StackInputs::try_from_ints([2, 2]).unwrap(); let mut process = Process::new_dummy(stack); - assert!(process.execute_op(Operation::Not).is_err()); + assert!(process.execute_op(Operation::Not, &mut host).is_err()); } // COMPARISON OPERATIONS @@ -460,29 +465,29 @@ mod tests { // --- test when top two values are equal ----------------------------- let advice_inputs = AdviceInputs::default(); let stack_inputs = StackInputs::try_from_ints([3, 7, 7]).unwrap(); - let mut process = + let (mut process, mut host) = Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs); - process.execute_op(Operation::Eq).unwrap(); + process.execute_op(Operation::Eq, &mut host).unwrap(); let expected = build_expected(&[ONE, Felt::new(3)]); assert_eq!(expected, process.stack.trace_state()); // --- test when top two values are not equal ------------------------- let advice_inputs = AdviceInputs::default(); let stack_inputs = StackInputs::try_from_ints([3, 5, 7]).unwrap(); - let mut process = + let (mut process, mut host) = Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs); - process.execute_op(Operation::Eq).unwrap(); + process.execute_op(Operation::Eq, &mut host).unwrap(); let expected = build_expected(&[ZERO, Felt::new(3)]); assert_eq!(expected, process.stack.trace_state()); // --- calling EQ with a stack of minimum depth is a ok --------------- let advice_inputs = AdviceInputs::default(); let stack_inputs = StackInputs::default(); - let mut process = + let (mut process, mut host) = Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs); - assert!(process.execute_op(Operation::Eq).is_ok()); + assert!(process.execute_op(Operation::Eq, &mut host).is_ok()); } #[test] @@ -490,20 +495,20 @@ mod tests { // --- test when top is zero ------------------------------------------ let advice_inputs = AdviceInputs::default(); let stack_inputs = StackInputs::try_from_ints([3, 0]).unwrap(); - let mut process = + let (mut process, mut host) = Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs); - process.execute_op(Operation::Eqz).unwrap(); + process.execute_op(Operation::Eqz, &mut host).unwrap(); let expected = build_expected(&[ONE, Felt::new(3)]); assert_eq!(expected, process.stack.trace_state()); // --- test when top is not zero -------------------------------------- let advice_inputs = AdviceInputs::default(); let stack_inputs = StackInputs::try_from_ints([3, 4]).unwrap(); - let mut process = + let (mut process, mut host) = Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs); - process.execute_op(Operation::Eqz).unwrap(); + process.execute_op(Operation::Eqz, &mut host).unwrap(); let expected = build_expected(&[ZERO, Felt::new(3)]); assert_eq!(expected, process.stack.trace_state()); } @@ -521,10 +526,10 @@ mod tests { let advice_inputs = AdviceInputs::default(); let stack_inputs = StackInputs::try_from_ints([a, b, c, 0]).unwrap(); - let mut process = + let (mut process, mut host) = Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs); - process.execute_op(Operation::Expacc).unwrap(); + process.execute_op(Operation::Expacc, &mut host).unwrap(); let expected = build_expected(&[ZERO, Felt::new(16), Felt::new(32), Felt::new(a >> 1)]); assert_eq!(expected, process.stack.trace_state()); @@ -536,10 +541,10 @@ mod tests { let advice_inputs = AdviceInputs::default(); let stack_inputs = StackInputs::try_from_ints([a, b, c, 0]).unwrap(); - let mut process = + let (mut process, mut host) = Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs); - process.execute_op(Operation::Expacc).unwrap(); + process.execute_op(Operation::Expacc, &mut host).unwrap(); let expected = build_expected(&[ONE, Felt::new(256), Felt::new(16), Felt::new(a >> 1)]); assert_eq!(expected, process.stack.trace_state()); @@ -552,10 +557,10 @@ mod tests { let advice_inputs = AdviceInputs::default(); let stack_inputs = StackInputs::try_from_ints([a, b, c, 0]).unwrap(); - let mut process = + let (mut process, mut host) = Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs); - process.execute_op(Operation::Expacc).unwrap(); + process.execute_op(Operation::Expacc, &mut host).unwrap(); let expected = build_expected(&[ONE, Felt::new(390625), Felt::new(3125), Felt::new(a >> 1)]); assert_eq!(expected, process.stack.trace_state()); diff --git a/processor/src/operations/fri_ops.rs b/processor/src/operations/fri_ops.rs index 01189c2d2..cf67ef21c 100644 --- a/processor/src/operations/fri_ops.rs +++ b/processor/src/operations/fri_ops.rs @@ -1,6 +1,6 @@ use vm_core::{ExtensionOf, FieldElement, StarkField, ONE, ZERO}; -use super::{super::QuadFelt, ExecutionError, Felt, Host, Operation, Process}; +use super::{super::QuadFelt, ExecutionError, Felt, Operation, Process}; // CONSTANTS // ================================================================================================ @@ -20,10 +20,7 @@ const TAU3_INV: Felt = Felt::new(281474976710656); // tau^{-3} // FRI OPERATIONS // ================================================================================================ -impl Process -where - H: Host, -{ +impl Process { // FRI FOLDING OPERATION // -------------------------------------------------------------------------------------------- /// Performs FRI layer folding by a factor of 4 for FRI protocol executed in a degree 2 @@ -253,6 +250,7 @@ mod tests { use super::{ ExtensionOf, Felt, FieldElement, Operation, Process, QuadFelt, StarkField, TWO, TWO_INV, }; + use crate::DefaultHost; #[test] fn fold4() { @@ -331,8 +329,9 @@ mod tests { let stack_inputs = StackInputs::new(inputs[0..16].to_vec()).expect("inputs lenght too long"); let mut process = Process::new_dummy_with_decoder_helpers(stack_inputs); - process.execute_op(Operation::Push(inputs[16])).unwrap(); - process.execute_op(Operation::FriE2F4).unwrap(); + let mut host = DefaultHost::default(); + process.execute_op(Operation::Push(inputs[16]), &mut host).unwrap(); + process.execute_op(Operation::FriE2F4, &mut host).unwrap(); // --- check the stack state------------------------------------------- let stack_state = process.stack.trace_state(); diff --git a/processor/src/operations/io_ops.rs b/processor/src/operations/io_ops.rs index b3c9d863b..ec9e3dddc 100644 --- a/processor/src/operations/io_ops.rs +++ b/processor/src/operations/io_ops.rs @@ -1,13 +1,10 @@ -use super::{ExecutionError, Felt, Host, Operation, Process}; -use crate::Word; +use super::{ExecutionError, Felt, Operation, Process}; +use crate::{Host, Word}; // INPUT / OUTPUT OPERATIONS // ================================================================================================ -impl Process -where - H: Host, -{ +impl Process { // CONSTANT INPUTS // -------------------------------------------------------------------------------------------- @@ -183,13 +180,13 @@ where /// - These words replace the top 8 elements of the stack (element-wise, in stack order). /// - Memory address (in position 12) is incremented by 2. /// - All other stack elements remain the same. - pub(super) fn op_pipe(&mut self) -> Result<(), ExecutionError> { + pub(super) fn op_pipe(&mut self, host: &mut impl Host) -> Result<(), ExecutionError> { // get the address from position 12 on the stack let ctx = self.system.ctx(); let addr = Self::get_valid_address(self.stack.get(12))?; // pop two words from the advice stack - let words = self.host.borrow_mut().pop_adv_stack_dword(self)?; + let words = host.pop_adv_stack_dword(self.into())?; // write the words memory self.chiplets.write_mem_double(ctx, addr, words)?; @@ -221,8 +218,8 @@ where /// /// # Errors /// Returns an error if the advice stack is empty. - pub(super) fn op_advpop(&mut self) -> Result<(), ExecutionError> { - let value = self.host.borrow_mut().pop_adv_stack(self)?; + pub(super) fn op_advpop(&mut self, host: &mut impl Host) -> Result<(), ExecutionError> { + let value = host.pop_adv_stack(self.into())?; self.stack.set(0, value); self.stack.shift_right(0); Ok(()) @@ -233,8 +230,8 @@ where /// /// # Errors /// Returns an error if the advice stack contains fewer than four elements. - pub(super) fn op_advpopw(&mut self) -> Result<(), ExecutionError> { - let word: Word = self.host.borrow_mut().pop_adv_stack_word(self)?; + pub(super) fn op_advpopw(&mut self, host: &mut impl Host) -> Result<(), ExecutionError> { + let word: Word = host.pop_adv_stack_word(self.into())?; self.stack.set(0, word[3]); self.stack.set(1, word[2]); @@ -281,10 +278,11 @@ mod tests { super::{super::AdviceProvider, Operation, MIN_STACK_DEPTH}, Felt, Host, Process, }; - use crate::{AdviceSource, ContextId}; + use crate::{AdviceSource, ContextId, DefaultHost}; #[test] fn op_push() { + let mut host = DefaultHost::default(); let mut process = Process::new_dummy_with_empty_stack(); assert_eq!(MIN_STACK_DEPTH, process.stack.depth()); assert_eq!(1, process.stack.current_clk()); @@ -292,7 +290,7 @@ mod tests { // push one item onto the stack let op = Operation::Push(ONE); - process.execute_op(op).unwrap(); + process.execute_op(op, &mut host).unwrap(); let mut expected = [ZERO; 16]; expected[0] = ONE; @@ -302,7 +300,7 @@ mod tests { // push another item onto the stack let op = Operation::Push(Felt::new(3)); - process.execute_op(op).unwrap(); + process.execute_op(op, &mut host).unwrap(); let mut expected = [ZERO; 16]; expected[0] = Felt::new(3); expected[1] = ONE; @@ -316,21 +314,22 @@ mod tests { // -------------------------------------------------------------------------------------------- #[test] fn op_mloadw() { + let mut host = DefaultHost::default(); let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack(); assert_eq!(0, process.chiplets.get_mem_size()); // push a word onto the stack and save it at address 1 let word = [1, 3, 5, 7].to_elements().try_into().unwrap(); - store_value(&mut process, 1, word); + store_value(&mut process, 1, word, &mut host); // push four zeros onto the stack for _ in 0..4 { - process.execute_op(Operation::Pad).unwrap(); + process.execute_op(Operation::Pad, &mut host).unwrap(); } // push the address onto the stack and load the word - process.execute_op(Operation::Push(ONE)).unwrap(); - process.execute_op(Operation::MLoadW).unwrap(); + process.execute_op(Operation::Push(ONE), &mut host).unwrap(); + process.execute_op(Operation::MLoadW, &mut host).unwrap(); let expected_stack = build_expected_stack(&[7, 5, 3, 1, 7, 5, 3, 1]); assert_eq!(expected_stack, process.stack.trace_state()); @@ -340,26 +339,27 @@ mod tests { assert_eq!(word, process.chiplets.get_mem_value(ContextId::root(), 1).unwrap()); // --- calling MLOADW with address greater than u32::MAX leads to an error ---------------- - process.execute_op(Operation::Push(Felt::new(u64::MAX / 2))).unwrap(); - assert!(process.execute_op(Operation::MLoadW).is_err()); + process.execute_op(Operation::Push(Felt::new(u64::MAX / 2)), &mut host).unwrap(); + assert!(process.execute_op(Operation::MLoadW, &mut host).is_err()); // --- calling MLOADW with a stack of minimum depth is ok ---------------- let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack(); - assert!(process.execute_op(Operation::MLoadW).is_ok()); + assert!(process.execute_op(Operation::MLoadW, &mut host).is_ok()); } #[test] fn op_mload() { + let mut host = DefaultHost::default(); let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack(); assert_eq!(0, process.chiplets.get_mem_size()); // push a word onto the stack and save it at address 2 let word = [1, 3, 5, 7].to_elements().try_into().unwrap(); - store_value(&mut process, 2, word); + store_value(&mut process, 2, word, &mut host); // push the address onto the stack and load the element - process.execute_op(Operation::Push(Felt::new(2))).unwrap(); - process.execute_op(Operation::MLoad).unwrap(); + process.execute_op(Operation::Push(Felt::new(2)), &mut host).unwrap(); + process.execute_op(Operation::MLoad, &mut host).unwrap(); let expected_stack = build_expected_stack(&[1, 7, 5, 3, 1]); assert_eq!(expected_stack, process.stack.trace_state()); @@ -369,16 +369,17 @@ mod tests { assert_eq!(word, process.chiplets.get_mem_value(ContextId::root(), 2).unwrap()); // --- calling MLOAD with address greater than u32::MAX leads to an error ----------------- - process.execute_op(Operation::Push(Felt::new(u64::MAX / 2))).unwrap(); - assert!(process.execute_op(Operation::MLoad).is_err()); + process.execute_op(Operation::Push(Felt::new(u64::MAX / 2)), &mut host).unwrap(); + assert!(process.execute_op(Operation::MLoad, &mut host).is_err()); // --- calling MLOAD with a stack of minimum depth is ok ---------------- let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack(); - assert!(process.execute_op(Operation::MLoad).is_ok()); + assert!(process.execute_op(Operation::MLoad, &mut host).is_ok()); } #[test] fn op_mstream() { + let mut host = DefaultHost::default(); let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack(); // save two words into memory addresses 1 and 2 @@ -386,8 +387,8 @@ mod tests { let word2 = [26, 25, 24, 23]; let word1_felts: Word = word1.to_elements().try_into().unwrap(); let word2_felts: Word = word2.to_elements().try_into().unwrap(); - store_value(&mut process, 1, word1_felts); - store_value(&mut process, 2, word2_felts); + store_value(&mut process, 1, word1_felts, &mut host); + store_value(&mut process, 2, word2_felts, &mut host); // check memory state assert_eq!(2, process.chiplets.get_mem_size()); @@ -396,7 +397,7 @@ mod tests { // clear the stack for _ in 0..8 { - process.execute_op(Operation::Drop).unwrap(); + process.execute_op(Operation::Drop, &mut host).unwrap(); } // arrange the stack such that: @@ -404,14 +405,14 @@ mod tests { // - 1 (the address) is at position 12 // - values 1 - 12 are at positions 0 - 11. Adding the first 8 of these values to the values // stored in memory should result in 35. - process.execute_op(Operation::Push(Felt::new(101))).unwrap(); - process.execute_op(Operation::Push(ONE)).unwrap(); + process.execute_op(Operation::Push(Felt::new(101)), &mut host).unwrap(); + process.execute_op(Operation::Push(ONE), &mut host).unwrap(); for i in 1..13 { - process.execute_op(Operation::Push(Felt::new(i))).unwrap(); + process.execute_op(Operation::Push(Felt::new(i)), &mut host).unwrap(); } // execute the MSTREAM operation - process.execute_op(Operation::MStream).unwrap(); + process.execute_op(Operation::MStream, &mut host).unwrap(); // the first 8 values should contain the values from memory. the next 4 values should remain // unchanged, and the address should be incremented by 2 (i.e., 1 -> 3). @@ -425,12 +426,13 @@ mod tests { #[test] fn op_mstorew() { + let mut host = DefaultHost::default(); let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack(); assert_eq!(0, process.chiplets.get_mem_size()); // push the first word onto the stack and save it at address 0 let word1 = [1, 3, 5, 7].to_elements().try_into().unwrap(); - store_value(&mut process, 0, word1); + store_value(&mut process, 0, word1, &mut host); // check stack state let expected_stack = build_expected_stack(&[7, 5, 3, 1]); @@ -442,7 +444,7 @@ mod tests { // push the second word onto the stack and save it at address 3 let word2 = [2, 4, 6, 8].to_elements().try_into().unwrap(); - store_value(&mut process, 3, word2); + store_value(&mut process, 3, word2, &mut host); // check stack state let expected_stack = build_expected_stack(&[8, 6, 4, 2, 7, 5, 3, 1]); @@ -454,23 +456,24 @@ mod tests { assert_eq!(word2, process.chiplets.get_mem_value(ContextId::root(), 3).unwrap()); // --- calling MSTOREW with address greater than u32::MAX leads to an error ---------------- - process.execute_op(Operation::Push(Felt::new(u64::MAX / 2))).unwrap(); - assert!(process.execute_op(Operation::MStoreW).is_err()); + process.execute_op(Operation::Push(Felt::new(u64::MAX / 2)), &mut host).unwrap(); + assert!(process.execute_op(Operation::MStoreW, &mut host).is_err()); // --- calling STOREW with a stack of minimum depth is ok ---------------- let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack(); - assert!(process.execute_op(Operation::MStoreW).is_ok()); + assert!(process.execute_op(Operation::MStoreW, &mut host).is_ok()); } #[test] fn op_mstore() { + let mut host = DefaultHost::default(); let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack(); assert_eq!(0, process.chiplets.get_mem_size()); // push new element onto the stack and save it as first element of the word on // uninitialized memory at address 0 let element = Felt::new(10); - store_element(&mut process, 0, element); + store_element(&mut process, 0, element, &mut host); // check stack state let expected_stack = build_expected_stack(&[10]); @@ -483,11 +486,11 @@ mod tests { // push the word onto the stack and save it at address 2 let word_2 = [1, 3, 5, 7].to_elements().try_into().unwrap(); - store_value(&mut process, 2, word_2); + store_value(&mut process, 2, word_2, &mut host); // push new element onto the stack and save it as first element of the word at address 2 let element = Felt::new(12); - store_element(&mut process, 2, element); + store_element(&mut process, 2, element, &mut host); // check stack state let expected_stack = build_expected_stack(&[12, 7, 5, 3, 1, 10]); @@ -499,16 +502,17 @@ mod tests { assert_eq!(mem_2, process.chiplets.get_mem_value(ContextId::root(), 2).unwrap()); // --- calling MSTORE with address greater than u32::MAX leads to an error ---------------- - process.execute_op(Operation::Push(Felt::new(u64::MAX / 2))).unwrap(); - assert!(process.execute_op(Operation::MStore).is_err()); + process.execute_op(Operation::Push(Felt::new(u64::MAX / 2)), &mut host).unwrap(); + assert!(process.execute_op(Operation::MStore, &mut host).is_err()); // --- calling MSTORE with a stack of minimum depth is ok ---------------- let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack(); - assert!(process.execute_op(Operation::MStore).is_ok()); + assert!(process.execute_op(Operation::MStore, &mut host).is_ok()); } #[test] fn op_pipe() { + let mut host = DefaultHost::default(); let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack(); // push words onto the advice stack @@ -518,12 +522,7 @@ mod tests { let word2_felts: Word = word2.to_elements().try_into().unwrap(); for element in word2_felts.iter().rev().chain(word1_felts.iter().rev()).copied() { // reverse the word order, since elements are pushed onto the advice stack. - process - .host - .borrow_mut() - .advice_provider_mut() - .push_stack(AdviceSource::Value(element)) - .unwrap(); + host.advice_provider_mut().push_stack(AdviceSource::Value(element)).unwrap(); } // arrange the stack such that: @@ -532,14 +531,14 @@ mod tests { // - values 1 - 12 are at positions 0 - 11. Replacing the first 8 of these values with the // values from the advice stack should result in 30 through 23 in stack order (with 23 at // stack[0]). - process.execute_op(Operation::Push(Felt::new(101))).unwrap(); - process.execute_op(Operation::Push(ONE)).unwrap(); + process.execute_op(Operation::Push(Felt::new(101)), &mut host).unwrap(); + process.execute_op(Operation::Push(ONE), &mut host).unwrap(); for i in 1..13 { - process.execute_op(Operation::Push(Felt::new(i))).unwrap(); + process.execute_op(Operation::Push(Felt::new(i)), &mut host).unwrap(); } // execute the PIPE operation - process.execute_op(Operation::Pipe).unwrap(); + process.execute_op(Operation::Pipe, &mut host).unwrap(); // check memory state contains the words from the advice stack assert_eq!(2, process.chiplets.get_mem_size()); @@ -562,27 +561,27 @@ mod tests { #[test] fn op_advpop() { // popping from the advice stack should push the value onto the operand stack - let mut process = Process::new_dummy_with_advice_stack(&[3]); - process.execute_op(Operation::Push(ONE)).unwrap(); - process.execute_op(Operation::AdvPop).unwrap(); + let (mut process, mut host) = Process::new_dummy_with_advice_stack(&[3]); + process.execute_op(Operation::Push(ONE), &mut host).unwrap(); + process.execute_op(Operation::AdvPop, &mut host).unwrap(); let expected = build_expected_stack(&[3, 1]); assert_eq!(expected, process.stack.trace_state()); // popping again should result in an error because advice stack is empty - assert!(process.execute_op(Operation::AdvPop).is_err()); + assert!(process.execute_op(Operation::AdvPop, &mut host).is_err()); } #[test] fn op_advpopw() { // popping a word from the advice stack should overwrite top 4 elements of the operand // stack - let mut process = Process::new_dummy_with_advice_stack(&[3, 4, 5, 6]); - process.execute_op(Operation::Push(ONE)).unwrap(); - process.execute_op(Operation::Pad).unwrap(); - process.execute_op(Operation::Pad).unwrap(); - process.execute_op(Operation::Pad).unwrap(); - process.execute_op(Operation::Pad).unwrap(); - process.execute_op(Operation::AdvPopW).unwrap(); + let (mut process, mut host) = Process::new_dummy_with_advice_stack(&[3, 4, 5, 6]); + process.execute_op(Operation::Push(ONE), &mut host).unwrap(); + process.execute_op(Operation::Pad, &mut host).unwrap(); + process.execute_op(Operation::Pad, &mut host).unwrap(); + process.execute_op(Operation::Pad, &mut host).unwrap(); + process.execute_op(Operation::Pad, &mut host).unwrap(); + process.execute_op(Operation::AdvPopW, &mut host).unwrap(); let expected = build_expected_stack(&[6, 5, 4, 3, 1]); assert_eq!(expected, process.stack.trace_state()); } @@ -590,26 +589,26 @@ mod tests { // HELPER METHODS // -------------------------------------------------------------------------------------------- - fn store_value(process: &mut Process, addr: u64, value: [Felt; 4]) + fn store_value(process: &mut Process, addr: u64, value: [Felt; 4], host: &mut H) where H: Host, { for &value in value.iter() { - process.execute_op(Operation::Push(value)).unwrap(); + process.execute_op(Operation::Push(value), host).unwrap(); } let addr = Felt::new(addr); - process.execute_op(Operation::Push(addr)).unwrap(); - process.execute_op(Operation::MStoreW).unwrap(); + process.execute_op(Operation::Push(addr), host).unwrap(); + process.execute_op(Operation::MStoreW, host).unwrap(); } - fn store_element(process: &mut Process, addr: u64, value: Felt) + fn store_element(process: &mut Process, addr: u64, value: Felt, host: &mut H) where H: Host, { - process.execute_op(Operation::Push(value)).unwrap(); + process.execute_op(Operation::Push(value), host).unwrap(); let addr = Felt::new(addr); - process.execute_op(Operation::Push(addr)).unwrap(); - process.execute_op(Operation::MStore).unwrap(); + process.execute_op(Operation::Push(addr), host).unwrap(); + process.execute_op(Operation::MStore, host).unwrap(); } fn build_expected_stack(values: &[u64]) -> [Felt; 16] { diff --git a/processor/src/operations/mod.rs b/processor/src/operations/mod.rs index 58216b7e0..cf97cb596 100644 --- a/processor/src/operations/mod.rs +++ b/processor/src/operations/mod.rs @@ -19,12 +19,13 @@ use super::Kernel; // OPERATION DISPATCHER // ================================================================================================ -impl Process -where - H: Host, -{ +impl Process { /// Executes the specified operation. - pub(super) fn execute_op(&mut self, op: Operation) -> Result<(), ExecutionError> { + pub(super) fn execute_op( + &mut self, + op: Operation, + host: &mut impl Host, + ) -> Result<(), ExecutionError> { // make sure there is enough memory allocated to hold the execution trace self.ensure_trace_capacity(); @@ -32,7 +33,7 @@ where match op { // ----- system operations ------------------------------------------------------------ Operation::Noop => self.stack.copy_state(0), - Operation::Assert(err_code) => self.op_assert(err_code)?, + Operation::Assert(err_code) => self.op_assert(err_code, host)?, Operation::FmpAdd => self.op_fmpadd()?, Operation::FmpUpdate => self.op_fmpupdate()?, @@ -41,7 +42,7 @@ where Operation::Caller => self.op_caller()?, Operation::Clk => self.op_clk()?, - Operation::Emit(event_id) => self.op_emit(event_id)?, + Operation::Emit(event_id) => self.op_emit(event_id, host)?, // ----- flow control operations ------------------------------------------------------ // control flow operations are never executed directly @@ -135,8 +136,8 @@ where // ----- input / output --------------------------------------------------------------- Operation::Push(value) => self.op_push(value)?, - Operation::AdvPop => self.op_advpop()?, - Operation::AdvPopW => self.op_advpopw()?, + Operation::AdvPop => self.op_advpop(host)?, + Operation::AdvPopW => self.op_advpopw(host)?, Operation::MLoadW => self.op_mloadw()?, Operation::MStoreW => self.op_mstorew()?, @@ -145,12 +146,12 @@ where Operation::MStore => self.op_mstore()?, Operation::MStream => self.op_mstream()?, - Operation::Pipe => self.op_pipe()?, + Operation::Pipe => self.op_pipe(host)?, // ----- cryptographic operations ----------------------------------------------------- Operation::HPerm => self.op_hperm()?, - Operation::MpVerify(err_code) => self.op_mpverify(err_code)?, - Operation::MrUpdate => self.op_mrupdate()?, + Operation::MpVerify(err_code) => self.op_mpverify(err_code, host)?, + Operation::MrUpdate => self.op_mrupdate(host)?, Operation::FriE2F4 => self.op_fri_ext2fold4()?, Operation::RCombBase => self.op_rcomb_base()?, } @@ -183,14 +184,14 @@ pub mod testing { use super::*; use crate::{AdviceInputs, DefaultHost, MemAdviceProvider}; - impl Process> { + impl Process { /// Instantiates a new blank process for testing purposes. The stack in the process is /// initialized with the provided values. pub fn new_dummy(stack_inputs: StackInputs) -> Self { - let host = DefaultHost::default(); + let mut host = DefaultHost::default(); let mut process = - Self::new(Kernel::default(), stack_inputs, host, ExecutionOptions::default()); - process.execute_op(Operation::Noop).unwrap(); + Self::new(Kernel::default(), stack_inputs, ExecutionOptions::default()); + process.execute_op(Operation::Noop, &mut host).unwrap(); process } @@ -201,16 +202,19 @@ pub mod testing { } /// Instantiates a new process with an advice stack for testing purposes. - pub fn new_dummy_with_advice_stack(advice_stack: &[u64]) -> Self { + pub fn new_dummy_with_advice_stack( + advice_stack: &[u64], + ) -> (Self, DefaultHost) { let stack_inputs = StackInputs::default(); let advice_inputs = AdviceInputs::default().with_stack_values(advice_stack.iter().copied()).unwrap(); let advice_provider = MemAdviceProvider::from(advice_inputs); - let host = DefaultHost::new(advice_provider); + let mut host = DefaultHost::new(advice_provider); let mut process = - Self::new(Kernel::default(), stack_inputs, host, ExecutionOptions::default()); - process.execute_op(Operation::Noop).unwrap(); - process + Self::new(Kernel::default(), stack_inputs, ExecutionOptions::default()); + process.execute_op(Operation::Noop, &mut host).unwrap(); + + (process, host) } /// Instantiates a new blank process with one decoder trace row for testing purposes. This @@ -226,7 +230,9 @@ pub mod testing { /// The stack in the process is initialized with the provided values. pub fn new_dummy_with_decoder_helpers(stack_inputs: StackInputs) -> Self { let advice_inputs = AdviceInputs::default(); - Self::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs) + let (process, _) = + Self::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs); + process } /// Instantiates a new process having Program inputs along with one decoder trace row @@ -234,14 +240,15 @@ pub mod testing { pub fn new_dummy_with_inputs_and_decoder_helpers( stack_inputs: StackInputs, advice_inputs: AdviceInputs, - ) -> Self { + ) -> (Self, DefaultHost) { let advice_provider = MemAdviceProvider::from(advice_inputs); - let host = DefaultHost::new(advice_provider); + let mut host = DefaultHost::new(advice_provider); let mut process = - Self::new(Kernel::default(), stack_inputs, host, ExecutionOptions::default()); + Self::new(Kernel::default(), stack_inputs, ExecutionOptions::default()); process.decoder.add_dummy_trace_row(); - process.execute_op(Operation::Noop).unwrap(); - process + process.execute_op(Operation::Noop, &mut host).unwrap(); + + (process, host) } } } diff --git a/processor/src/operations/stack_ops.rs b/processor/src/operations/stack_ops.rs index 401294272..95c1fdc28 100644 --- a/processor/src/operations/stack_ops.rs +++ b/processor/src/operations/stack_ops.rs @@ -1,10 +1,7 @@ -use super::{ExecutionError, Host, Process, MIN_STACK_DEPTH}; +use super::{ExecutionError, Process, MIN_STACK_DEPTH}; use crate::ZERO; -impl Process -where - H: Host, -{ +impl Process { // STACK MANIPULATION // -------------------------------------------------------------------------------------------- /// Pushes a ZERO onto the stack. @@ -306,20 +303,21 @@ mod tests { super::{Operation, Process}, MIN_STACK_DEPTH, }; - use crate::{Felt, StackInputs, ONE, ZERO}; + use crate::{DefaultHost, Felt, StackInputs, ONE, ZERO}; #[test] fn op_pad() { let stack = StackInputs::default(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); // push one item onto the stack - process.execute_op(Operation::Push(ONE)).unwrap(); + process.execute_op(Operation::Push(ONE), &mut host).unwrap(); let expected = build_expected(&[1]); assert_eq!(expected, process.stack.trace_state()); // pad the stack - process.execute_op(Operation::Pad).unwrap(); + process.execute_op(Operation::Pad, &mut host).unwrap(); let expected = build_expected(&[0, 1]); assert_eq!(MIN_STACK_DEPTH + 2, process.stack.depth()); @@ -327,7 +325,7 @@ mod tests { assert_eq!(expected, process.stack.trace_state()); // pad the stack again - process.execute_op(Operation::Pad).unwrap(); + process.execute_op(Operation::Pad, &mut host).unwrap(); let expected = build_expected(&[0, 0, 1]); assert_eq!(MIN_STACK_DEPTH + 3, process.stack.depth()); @@ -340,69 +338,71 @@ mod tests { // push a few items onto the stack let stack = StackInputs::default(); let mut process = Process::new_dummy(stack); - process.execute_op(Operation::Push(ONE)).unwrap(); - process.execute_op(Operation::Push(Felt::new(2))).unwrap(); + let mut host = DefaultHost::default(); + process.execute_op(Operation::Push(ONE), &mut host).unwrap(); + process.execute_op(Operation::Push(Felt::new(2)), &mut host).unwrap(); // drop the first value - process.execute_op(Operation::Drop).unwrap(); + process.execute_op(Operation::Drop, &mut host).unwrap(); let expected = build_expected(&[1]); assert_eq!(expected, process.stack.trace_state()); assert_eq!(MIN_STACK_DEPTH + 1, process.stack.depth()); // drop the next value - process.execute_op(Operation::Drop).unwrap(); + process.execute_op(Operation::Drop, &mut host).unwrap(); let expected = build_expected(&[]); assert_eq!(expected, process.stack.trace_state()); assert_eq!(MIN_STACK_DEPTH, process.stack.depth()); // calling drop with a minimum stack depth should be ok - assert!(process.execute_op(Operation::Drop).is_ok()); + assert!(process.execute_op(Operation::Drop, &mut host).is_ok()); } #[test] fn op_dup() { let stack = StackInputs::default(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); // push one item onto the stack - process.execute_op(Operation::Push(ONE)).unwrap(); + process.execute_op(Operation::Push(ONE), &mut host).unwrap(); let expected = build_expected(&[1]); assert_eq!(expected, process.stack.trace_state()); // duplicate it - process.execute_op(Operation::Dup0).unwrap(); + process.execute_op(Operation::Dup0, &mut host).unwrap(); let expected = build_expected(&[1, 1]); assert_eq!(expected, process.stack.trace_state()); // duplicating non-existent item from the min stack range should be ok - assert!(process.execute_op(Operation::Dup2).is_ok()); + assert!(process.execute_op(Operation::Dup2, &mut host).is_ok()); // drop it again before continuing the tests and stack comparison - process.execute_op(Operation::Drop).unwrap(); + process.execute_op(Operation::Drop, &mut host).unwrap(); // put 15 more items onto the stack let mut expected = [ONE; 16]; for i in 2..17 { - process.execute_op(Operation::Push(Felt::new(i))).unwrap(); + process.execute_op(Operation::Push(Felt::new(i)), &mut host).unwrap(); expected[16 - i as usize] = Felt::new(i); } assert_eq!(expected, process.stack.trace_state()); // duplicate last stack item - process.execute_op(Operation::Dup15).unwrap(); + process.execute_op(Operation::Dup15, &mut host).unwrap(); assert_eq!(ONE, process.stack.trace_state()[0]); assert_eq!(&expected[..15], &process.stack.trace_state()[1..]); // duplicate 8th stack item - process.execute_op(Operation::Dup7).unwrap(); + process.execute_op(Operation::Dup7, &mut host).unwrap(); assert_eq!(Felt::new(10), process.stack.trace_state()[0]); assert_eq!(ONE, process.stack.trace_state()[1]); assert_eq!(&expected[..14], &process.stack.trace_state()[2..]); // remove 4 items off the stack - process.execute_op(Operation::Drop).unwrap(); - process.execute_op(Operation::Drop).unwrap(); - process.execute_op(Operation::Drop).unwrap(); - process.execute_op(Operation::Drop).unwrap(); + process.execute_op(Operation::Drop, &mut host).unwrap(); + process.execute_op(Operation::Drop, &mut host).unwrap(); + process.execute_op(Operation::Drop, &mut host).unwrap(); + process.execute_op(Operation::Drop, &mut host).unwrap(); assert_eq!(MIN_STACK_DEPTH + 15, process.stack.depth()); @@ -416,15 +416,16 @@ mod tests { // push a few items onto the stack let stack = StackInputs::try_from_ints([1, 2, 3]).unwrap(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); - process.execute_op(Operation::Swap).unwrap(); + process.execute_op(Operation::Swap, &mut host).unwrap(); let expected = build_expected(&[2, 3, 1]); assert_eq!(expected, process.stack.trace_state()); // swapping with a minimum stack should be ok let stack = StackInputs::default(); let mut process = Process::new_dummy(stack); - assert!(process.execute_op(Operation::Swap).is_ok()); + assert!(process.execute_op(Operation::Swap, &mut host).is_ok()); } #[test] @@ -432,15 +433,16 @@ mod tests { // push a few items onto the stack let stack = StackInputs::try_from_ints([1, 2, 3, 4, 5, 6, 7, 8, 9]).unwrap(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); - process.execute_op(Operation::SwapW).unwrap(); + process.execute_op(Operation::SwapW, &mut host).unwrap(); let expected = build_expected(&[5, 4, 3, 2, 9, 8, 7, 6, 1]); assert_eq!(expected, process.stack.trace_state()); // swapping with a minimum stack should be ok let stack = StackInputs::default(); let mut process = Process::new_dummy(stack); - assert!(process.execute_op(Operation::SwapW).is_ok()); + assert!(process.execute_op(Operation::SwapW, &mut host).is_ok()); } #[test] @@ -449,15 +451,16 @@ mod tests { let stack = StackInputs::try_from_ints([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]).unwrap(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); - process.execute_op(Operation::SwapW2).unwrap(); + process.execute_op(Operation::SwapW2, &mut host).unwrap(); let expected = build_expected(&[5, 4, 3, 2, 9, 8, 7, 6, 13, 12, 11, 10, 1]); assert_eq!(expected, process.stack.trace_state()); // swapping with a minimum stack should be ok let stack = StackInputs::default(); let mut process = Process::new_dummy(stack); - assert!(process.execute_op(Operation::SwapW2).is_ok()); + assert!(process.execute_op(Operation::SwapW2, &mut host).is_ok()); } #[test] @@ -467,14 +470,15 @@ mod tests { StackInputs::try_from_ints([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) .unwrap(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); - process.execute_op(Operation::SwapW3).unwrap(); + process.execute_op(Operation::SwapW3, &mut host).unwrap(); let expected = build_expected(&[4, 3, 2, 1, 12, 11, 10, 9, 8, 7, 6, 5, 16, 15, 14, 13]); assert_eq!(expected, process.stack.trace_state()); // swapping with a minimum stack should be ok let mut process = Process::new_dummy_with_empty_stack(); - assert!(process.execute_op(Operation::SwapW3).is_ok()); + assert!(process.execute_op(Operation::SwapW3, &mut host).is_ok()); } #[test] @@ -484,30 +488,31 @@ mod tests { StackInputs::try_from_ints([16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]) .unwrap(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); // movup2 - process.execute_op(Operation::MovUp2).unwrap(); + process.execute_op(Operation::MovUp2, &mut host).unwrap(); let expected = build_expected(&[3, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); assert_eq!(expected, process.stack.trace_state()); // movup3 - process.execute_op(Operation::MovUp3).unwrap(); + process.execute_op(Operation::MovUp3, &mut host).unwrap(); let expected = build_expected(&[4, 3, 1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); assert_eq!(expected, process.stack.trace_state()); // movup7 - process.execute_op(Operation::MovUp7).unwrap(); + process.execute_op(Operation::MovUp7, &mut host).unwrap(); let expected = build_expected(&[8, 4, 3, 1, 2, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16]); assert_eq!(expected, process.stack.trace_state()); // movup8 - process.execute_op(Operation::MovUp8).unwrap(); + process.execute_op(Operation::MovUp8, &mut host).unwrap(); let expected = build_expected(&[9, 8, 4, 3, 1, 2, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16]); assert_eq!(expected, process.stack.trace_state()); // executing movup with a minimum stack depth should be ok let mut process = Process::new_dummy_with_empty_stack(); - assert!(process.execute_op(Operation::MovUp2).is_ok()); + assert!(process.execute_op(Operation::MovUp2, &mut host).is_ok()); } #[test] @@ -517,30 +522,31 @@ mod tests { StackInputs::try_from_ints([16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]) .unwrap(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); // movdn2 - process.execute_op(Operation::MovDn2).unwrap(); + process.execute_op(Operation::MovDn2, &mut host).unwrap(); let expected = build_expected(&[2, 3, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); assert_eq!(expected, process.stack.trace_state()); // movdn3 - process.execute_op(Operation::MovDn3).unwrap(); + process.execute_op(Operation::MovDn3, &mut host).unwrap(); let expected = build_expected(&[3, 1, 4, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); assert_eq!(expected, process.stack.trace_state()); // movdn7 - process.execute_op(Operation::MovDn7).unwrap(); + process.execute_op(Operation::MovDn7, &mut host).unwrap(); let expected = build_expected(&[1, 4, 2, 5, 6, 7, 8, 3, 9, 10, 11, 12, 13, 14, 15, 16]); assert_eq!(expected, process.stack.trace_state()); // movdn15 - process.execute_op(Operation::MovDn8).unwrap(); + process.execute_op(Operation::MovDn8, &mut host).unwrap(); let expected = build_expected(&[4, 2, 5, 6, 7, 8, 3, 9, 1, 10, 11, 12, 13, 14, 15, 16]); assert_eq!(expected, process.stack.trace_state()); // executing movdn with a minimum stack depth should be ok let mut process = Process::new_dummy_with_empty_stack(); - assert!(process.execute_op(Operation::MovDn2).is_ok()); + assert!(process.execute_op(Operation::MovDn2, &mut host).is_ok()); } #[test] @@ -548,23 +554,24 @@ mod tests { // push a few items onto the stack let stack = StackInputs::try_from_ints([4, 3, 2, 1, 0]).unwrap(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); // no swap (top of the stack is 0) - process.execute_op(Operation::CSwap).unwrap(); + process.execute_op(Operation::CSwap, &mut host).unwrap(); let expected = build_expected(&[1, 2, 3, 4]); assert_eq!(expected, process.stack.trace_state()); // swap (top of the stack is 1) - process.execute_op(Operation::CSwap).unwrap(); + process.execute_op(Operation::CSwap, &mut host).unwrap(); let expected = build_expected(&[3, 2, 4]); assert_eq!(expected, process.stack.trace_state()); // error: top of the stack is not binary - assert!(process.execute_op(Operation::CSwap).is_err()); + assert!(process.execute_op(Operation::CSwap, &mut host).is_err()); // executing conditional swap with a minimum stack depth should be ok let mut process = Process::new_dummy_with_empty_stack(); - assert!(process.execute_op(Operation::CSwap).is_ok()); + assert!(process.execute_op(Operation::CSwap, &mut host).is_ok()); } #[test] @@ -572,23 +579,24 @@ mod tests { // push a few items onto the stack let stack = StackInputs::try_from_ints([11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]).unwrap(); let mut process = Process::new_dummy(stack); + let mut host = DefaultHost::default(); // no swap (top of the stack is 0) - process.execute_op(Operation::CSwapW).unwrap(); + process.execute_op(Operation::CSwapW, &mut host).unwrap(); let expected = build_expected(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); assert_eq!(expected, process.stack.trace_state()); // swap (top of the stack is 1) - process.execute_op(Operation::CSwapW).unwrap(); + process.execute_op(Operation::CSwapW, &mut host).unwrap(); let expected = build_expected(&[6, 7, 8, 9, 2, 3, 4, 5, 10, 11]); assert_eq!(expected, process.stack.trace_state()); // error: top of the stack is not binary - assert!(process.execute_op(Operation::CSwapW).is_err()); + assert!(process.execute_op(Operation::CSwapW, &mut host).is_err()); // executing conditional swap with a minimum stack depth should be ok let mut process = Process::new_dummy_with_empty_stack(); - assert!(process.execute_op(Operation::CSwapW).is_ok()); + assert!(process.execute_op(Operation::CSwapW, &mut host).is_ok()); } // HELPER FUNCTIONS diff --git a/processor/src/operations/sys_ops.rs b/processor/src/operations/sys_ops.rs index ea211020f..1a198da3b 100644 --- a/processor/src/operations/sys_ops.rs +++ b/processor/src/operations/sys_ops.rs @@ -1,27 +1,28 @@ -use vm_core::Operation; +use vm_core::{Felt, Operation}; use super::{ super::{ system::{FMP_MAX, FMP_MIN}, ONE, }, - ExecutionError, Felt, Host, Process, + ExecutionError, Process, }; +use crate::Host; // SYSTEM OPERATIONS // ================================================================================================ -impl Process -where - H: Host, -{ +impl Process { /// Pops a value off the stack and asserts that it is equal to ONE. /// /// # Errors /// Returns an error if the popped value is not ONE. - pub(super) fn op_assert(&mut self, err_code: u32) -> Result<(), ExecutionError> { + pub(super) fn op_assert(&mut self, err_code: u32, host: &mut H) -> Result<(), ExecutionError> + where + H: Host, + { if self.stack.get(0) != ONE { - return Err(self.host.borrow_mut().on_assert_failed(self, err_code)); + return Err(host.on_assert_failed(self.into(), err_code)); } self.stack.shift_left(1); Ok(()) @@ -115,10 +116,13 @@ where // -------------------------------------------------------------------------------------------- /// Forwards the emitted event id to the host. - pub(super) fn op_emit(&mut self, event_id: u32) -> Result<(), ExecutionError> { + pub(super) fn op_emit(&mut self, event_id: u32, host: &mut H) -> Result<(), ExecutionError> + where + H: Host, + { self.stack.copy_state(0); self.decoder.set_user_op_helpers(Operation::Emit(event_id), &[event_id.into()]); - self.host.borrow_mut().on_event(self, event_id)?; + host.on_event(self.into(), event_id)?; Ok(()) } @@ -133,89 +137,92 @@ mod tests { super::{Operation, MIN_STACK_DEPTH}, Felt, Process, FMP_MAX, FMP_MIN, }; - use crate::{StackInputs, ONE, ZERO}; + use crate::{DefaultHost, StackInputs, ONE, ZERO}; const MAX_PROC_LOCALS: u64 = 2_u64.pow(31) - 1; #[test] fn op_assert() { + let mut host = DefaultHost::default(); // calling assert with a minimum stack should be an ok, as long as the top value is ONE let mut process = Process::new_dummy_with_empty_stack(); - process.execute_op(Operation::Push(ONE)).unwrap(); - process.execute_op(Operation::Swap).unwrap(); - process.execute_op(Operation::Drop).unwrap(); + process.execute_op(Operation::Push(ONE), &mut host).unwrap(); + process.execute_op(Operation::Swap, &mut host).unwrap(); + process.execute_op(Operation::Drop, &mut host).unwrap(); - assert!(process.execute_op(Operation::Assert(0)).is_ok()); + assert!(process.execute_op(Operation::Assert(0), &mut host).is_ok()); } #[test] fn op_fmpupdate() { + let mut host = DefaultHost::default(); let mut process = Process::new_dummy_with_empty_stack(); // initial value of fmp register should be 2^30 assert_eq!(Felt::new(2_u64.pow(30)), process.system.fmp()); // increment fmp register - process.execute_op(Operation::Push(Felt::new(2))).unwrap(); - process.execute_op(Operation::FmpUpdate).unwrap(); + process.execute_op(Operation::Push(Felt::new(2)), &mut host).unwrap(); + process.execute_op(Operation::FmpUpdate, &mut host).unwrap(); assert_eq!(Felt::new(FMP_MIN + 2), process.system.fmp()); // increment fmp register again - process.execute_op(Operation::Push(Felt::new(3))).unwrap(); - process.execute_op(Operation::FmpUpdate).unwrap(); + process.execute_op(Operation::Push(Felt::new(3)), &mut host).unwrap(); + process.execute_op(Operation::FmpUpdate, &mut host).unwrap(); assert_eq!(Felt::new(FMP_MIN + 5), process.system.fmp()); // decrement fmp register - process.execute_op(Operation::Push(-Felt::new(3))).unwrap(); - process.execute_op(Operation::FmpUpdate).unwrap(); + process.execute_op(Operation::Push(-Felt::new(3)), &mut host).unwrap(); + process.execute_op(Operation::FmpUpdate, &mut host).unwrap(); assert_eq!(Felt::new(FMP_MIN + 2), process.system.fmp()); // decrementing beyond the minimum fmp value should be an error - process.execute_op(Operation::Push(-Felt::new(3))).unwrap(); - assert!(process.execute_op(Operation::FmpUpdate).is_err()); + process.execute_op(Operation::Push(-Felt::new(3)), &mut host).unwrap(); + assert!(process.execute_op(Operation::FmpUpdate, &mut host).is_err()); // going up to the max fmp value should be OK let stack = StackInputs::try_from_ints([MAX_PROC_LOCALS]).unwrap(); let mut process = Process::new_dummy(stack); - process.execute_op(Operation::FmpUpdate).unwrap(); + process.execute_op(Operation::FmpUpdate, &mut host).unwrap(); assert_eq!(Felt::new(FMP_MAX), process.system.fmp()); // but going beyond that should be an error let stack = StackInputs::try_from_ints([MAX_PROC_LOCALS + 1]).unwrap(); let mut process = Process::new_dummy(stack); - assert!(process.execute_op(Operation::FmpUpdate).is_err()); + assert!(process.execute_op(Operation::FmpUpdate, &mut host).is_err()); // should not affect the rest of the stack state let stack = StackInputs::try_from_ints([2, 3]).unwrap(); let mut process = Process::new_dummy(stack); - process.execute_op(Operation::FmpUpdate).unwrap(); + process.execute_op(Operation::FmpUpdate, &mut host).unwrap(); let expected = build_expected_stack(&[2]); assert_eq!(expected, process.stack.trace_state()); // calling fmpupdate with a minimum stack should be ok let mut process = Process::new_dummy_with_empty_stack(); - assert!(process.execute_op(Operation::FmpUpdate).is_ok()); + assert!(process.execute_op(Operation::FmpUpdate, &mut host).is_ok()); } #[test] fn op_fmpadd() { + let mut host = DefaultHost::default(); let mut process = Process::new_dummy_with_empty_stack(); // set value of fmp register - process.execute_op(Operation::Push(Felt::new(2))).unwrap(); - process.execute_op(Operation::FmpUpdate).unwrap(); + process.execute_op(Operation::Push(Felt::new(2)), &mut host).unwrap(); + process.execute_op(Operation::FmpUpdate, &mut host).unwrap(); // compute address of the first local - process.execute_op(Operation::Push(-ONE)).unwrap(); - process.execute_op(Operation::FmpAdd).unwrap(); + process.execute_op(Operation::Push(-ONE), &mut host).unwrap(); + process.execute_op(Operation::FmpAdd, &mut host).unwrap(); let expected = build_expected_stack(&[FMP_MIN + 1]); assert_eq!(expected, process.stack.trace_state()); // compute address of second local (also make sure that rest of stack is not affected) - process.execute_op(Operation::Push(-Felt::new(2))).unwrap(); - process.execute_op(Operation::FmpAdd).unwrap(); + process.execute_op(Operation::Push(-Felt::new(2)), &mut host).unwrap(); + process.execute_op(Operation::FmpAdd, &mut host).unwrap(); let expected = build_expected_stack(&[FMP_MIN, FMP_MIN + 1]); assert_eq!(expected, process.stack.trace_state()); @@ -223,22 +230,23 @@ mod tests { #[test] fn op_sdepth() { + let mut host = DefaultHost::default(); // stack is empty let mut process = Process::new_dummy_with_empty_stack(); - process.execute_op(Operation::SDepth).unwrap(); + process.execute_op(Operation::SDepth, &mut host).unwrap(); let expected = build_expected_stack(&[MIN_STACK_DEPTH as u64]); assert_eq!(expected, process.stack.trace_state()); assert_eq!(MIN_STACK_DEPTH + 1, process.stack.depth()); // stack has one item - process.execute_op(Operation::SDepth).unwrap(); + process.execute_op(Operation::SDepth, &mut host).unwrap(); let expected = build_expected_stack(&[MIN_STACK_DEPTH as u64 + 1, MIN_STACK_DEPTH as u64]); assert_eq!(expected, process.stack.trace_state()); assert_eq!(MIN_STACK_DEPTH + 2, process.stack.depth()); // stack has 3 items - process.execute_op(Operation::Pad).unwrap(); - process.execute_op(Operation::SDepth).unwrap(); + process.execute_op(Operation::Pad, &mut host).unwrap(); + process.execute_op(Operation::SDepth, &mut host).unwrap(); let expected = build_expected_stack(&[ MIN_STACK_DEPTH as u64 + 3, 0, @@ -251,22 +259,23 @@ mod tests { #[test] fn op_clk() { + let mut host = DefaultHost::default(); let mut process = Process::new_dummy_with_empty_stack(); // initial value of clk register should be 1. - process.execute_op(Operation::Clk).unwrap(); + process.execute_op(Operation::Clk, &mut host).unwrap(); let expected = build_expected_stack(&[1]); assert_eq!(expected, process.stack.trace_state()); // increment clk register. - process.execute_op(Operation::Push(Felt::new(2))).unwrap(); - process.execute_op(Operation::Clk).unwrap(); + process.execute_op(Operation::Push(Felt::new(2)), &mut host).unwrap(); + process.execute_op(Operation::Clk, &mut host).unwrap(); let expected = build_expected_stack(&[3, 2, 1]); assert_eq!(expected, process.stack.trace_state()); // increment clk register again. - process.execute_op(Operation::Push(Felt::new(3))).unwrap(); - process.execute_op(Operation::Clk).unwrap(); + process.execute_op(Operation::Push(Felt::new(3)), &mut host).unwrap(); + process.execute_op(Operation::Clk, &mut host).unwrap(); let expected = build_expected_stack(&[5, 3, 3, 2, 1]); assert_eq!(expected, process.stack.trace_state()); } diff --git a/processor/src/operations/u32_ops.rs b/processor/src/operations/u32_ops.rs index 180002904..a7dd1b70f 100644 --- a/processor/src/operations/u32_ops.rs +++ b/processor/src/operations/u32_ops.rs @@ -1,6 +1,6 @@ use super::{ super::utils::{split_element, split_u32_into_u16}, - ExecutionError, Felt, FieldElement, Host, Operation, Process, + ExecutionError, Felt, FieldElement, Operation, Process, }; use crate::ZERO; @@ -20,10 +20,7 @@ macro_rules! require_u32_operand { }}; } -impl Process -where - H: Host, -{ +impl Process { // CASTING OPERATIONS // -------------------------------------------------------------------------------------------- @@ -249,7 +246,7 @@ mod tests { super::{Felt, Operation}, split_u32_into_u16, Process, }; - use crate::{StackInputs, ZERO}; + use crate::{DefaultHost, StackInputs, ZERO}; // CASTING OPERATIONS // -------------------------------------------------------------------------------------------- @@ -257,13 +254,14 @@ mod tests { #[test] fn op_u32split() { // --- test a random value --------------------------------------------- + let mut host = DefaultHost::default(); let a: u64 = rand_value(); let stack = StackInputs::try_from_ints([a]).unwrap(); let mut process = Process::new_dummy_with_decoder_helpers(stack); let hi = a >> 32; let lo = (a as u32) as u64; - process.execute_op(Operation::U32split).unwrap(); + process.execute_op(Operation::U32split, &mut host).unwrap(); let mut expected = [ZERO; 16]; expected[0] = Felt::new(hi); expected[1] = Felt::new(lo); @@ -276,7 +274,7 @@ mod tests { let hi = b >> 32; let lo = (b as u32) as u64; - process.execute_op(Operation::U32split).unwrap(); + process.execute_op(Operation::U32split, &mut host).unwrap(); let mut expected = [ZERO; 16]; expected[0] = Felt::new(hi); expected[1] = Felt::new(lo); @@ -287,11 +285,12 @@ mod tests { #[test] fn op_u32assert2() { // --- test random values ensuring other elements are still values are still intact ------- + let mut host = DefaultHost::default(); let (a, b, c, d) = get_rand_values(); let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap(); let mut process = Process::new_dummy_with_decoder_helpers(stack); - process.execute_op(Operation::U32assert2(0)).unwrap(); + process.execute_op(Operation::U32assert2(0), &mut host).unwrap(); let expected = build_expected(&[a, b, c, d]); assert_eq!(expected, process.stack.trace_state()); } @@ -302,12 +301,13 @@ mod tests { #[test] fn op_u32add() { // --- test random values --------------------------------------------- + let mut host = DefaultHost::default(); let (a, b, c, d) = get_rand_values(); let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap(); let mut process = Process::new_dummy_with_decoder_helpers(stack); let (result, over) = a.overflowing_add(b); - process.execute_op(Operation::U32add).unwrap(); + process.execute_op(Operation::U32add, &mut host).unwrap(); let expected = build_expected(&[over as u32, result, c, d]); assert_eq!(expected, process.stack.trace_state()); @@ -320,7 +320,7 @@ mod tests { let (result, over) = a.overflowing_add(b); let (b1, b0) = split_u32_into_u16(result.into()); - process.execute_op(Operation::U32add).unwrap(); + process.execute_op(Operation::U32add, &mut host).unwrap(); let expected = build_expected(&[over as u32, result]); assert_eq!(expected, process.stack.trace_state()); @@ -331,6 +331,7 @@ mod tests { #[test] fn op_u32add3() { + let mut host = DefaultHost::default(); let a = rand_value::() as u64; let b = rand_value::() as u64; let c = rand_value::() as u64; @@ -344,24 +345,25 @@ mod tests { let lo = result as u32; assert!(hi <= 2); - process.execute_op(Operation::U32add3).unwrap(); + process.execute_op(Operation::U32add3, &mut host).unwrap(); let expected = build_expected(&[hi, lo, d as u32]); assert_eq!(expected, process.stack.trace_state()); // --- test with minimum stack depth ---------------------------------- let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack(); - assert!(process.execute_op(Operation::U32add3).is_ok()); + assert!(process.execute_op(Operation::U32add3, &mut host).is_ok()); } #[test] fn op_u32sub() { // --- test random values --------------------------------------------- + let mut host = DefaultHost::default(); let (a, b, c, d) = get_rand_values(); let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap(); let mut process = Process::new_dummy_with_decoder_helpers(stack); let (result, under) = b.overflowing_sub(a); - process.execute_op(Operation::U32sub).unwrap(); + process.execute_op(Operation::U32sub, &mut host).unwrap(); let expected = build_expected(&[under as u32, result, c, d]); assert_eq!(expected, process.stack.trace_state()); @@ -373,13 +375,14 @@ mod tests { let mut process = Process::new_dummy_with_decoder_helpers(stack); let (result, under) = a.overflowing_sub(b); - process.execute_op(Operation::U32sub).unwrap(); + process.execute_op(Operation::U32sub, &mut host).unwrap(); let expected = build_expected(&[under as u32, result]); assert_eq!(expected, process.stack.trace_state()); } #[test] fn op_u32mul() { + let mut host = DefaultHost::default(); let (a, b, c, d) = get_rand_values(); let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap(); let mut process = Process::new_dummy_with_decoder_helpers(stack); @@ -387,13 +390,14 @@ mod tests { let hi = (result >> 32) as u32; let lo = result as u32; - process.execute_op(Operation::U32mul).unwrap(); + process.execute_op(Operation::U32mul, &mut host).unwrap(); let expected = build_expected(&[hi, lo, c, d]); assert_eq!(expected, process.stack.trace_state()); } #[test] fn op_u32madd() { + let mut host = DefaultHost::default(); let (a, b, c, d) = get_rand_values(); let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap(); let mut process = Process::new_dummy_with_decoder_helpers(stack); @@ -401,24 +405,25 @@ mod tests { let hi = (result >> 32) as u32; let lo = result as u32; - process.execute_op(Operation::U32madd).unwrap(); + process.execute_op(Operation::U32madd, &mut host).unwrap(); let expected = build_expected(&[hi, lo, d]); assert_eq!(expected, process.stack.trace_state()); // --- test with minimum stack depth ---------------------------------- let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack(); - assert!(process.execute_op(Operation::U32madd).is_ok()); + assert!(process.execute_op(Operation::U32madd, &mut host).is_ok()); } #[test] fn op_u32div() { + let mut host = DefaultHost::default(); let (a, b, c, d) = get_rand_values(); let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap(); let mut process = Process::new_dummy_with_decoder_helpers(stack); let q = b / a; let r = b % a; - process.execute_op(Operation::U32div).unwrap(); + process.execute_op(Operation::U32div, &mut host).unwrap(); let expected = build_expected(&[r, q, c, d]); assert_eq!(expected, process.stack.trace_state()); } @@ -428,32 +433,34 @@ mod tests { #[test] fn op_u32and() { + let mut host = DefaultHost::default(); let (a, b, c, d) = get_rand_values(); let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap(); let mut process = Process::new_dummy_with_decoder_helpers(stack); - process.execute_op(Operation::U32and).unwrap(); + process.execute_op(Operation::U32and, &mut host).unwrap(); let expected = build_expected(&[a & b, c, d]); assert_eq!(expected, process.stack.trace_state()); // --- test with minimum stack depth ---------------------------------- let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack(); - assert!(process.execute_op(Operation::U32and).is_ok()); + assert!(process.execute_op(Operation::U32and, &mut host).is_ok()); } #[test] fn op_u32xor() { + let mut host = DefaultHost::default(); let (a, b, c, d) = get_rand_values(); let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap(); let mut process = Process::new_dummy_with_decoder_helpers(stack); - process.execute_op(Operation::U32xor).unwrap(); + process.execute_op(Operation::U32xor, &mut host).unwrap(); let expected = build_expected(&[a ^ b, c, d]); assert_eq!(expected, process.stack.trace_state()); // --- test with minimum stack depth ---------------------------------- let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack(); - assert!(process.execute_op(Operation::U32xor).is_ok()); + assert!(process.execute_op(Operation::U32xor, &mut host).is_ok()); } // HELPER FUNCTIONS diff --git a/processor/src/stack/mod.rs b/processor/src/stack/mod.rs index 6708840b0..ad133e48c 100644 --- a/processor/src/stack/mod.rs +++ b/processor/src/stack/mod.rs @@ -55,6 +55,7 @@ const MAX_TOP_IDX: usize = MIN_STACK_DEPTH - 1; /// - Helper column h0 is used to ensure that stack depth does not drop below 16. Values in this /// column are set by the prover non-deterministically to 1 / (b0−16) when b0 != 16, and to any /// other value otherwise. +#[derive(Debug)] pub struct Stack { clk: RowIndex, trace: StackTrace, diff --git a/processor/src/stack/overflow.rs b/processor/src/stack/overflow.rs index bd5e5a314..fafbeee8f 100644 --- a/processor/src/stack/overflow.rs +++ b/processor/src/stack/overflow.rs @@ -11,6 +11,7 @@ use super::{Felt, FieldElement, ZERO}; /// /// When `trace_enabled` is set to true, we also record all changes to the table so that we can /// reconstruct the overflow table at any clock cycle. This can be used for debugging purposes. +#[derive(Debug)] pub struct OverflowTable { /// A list of all rows that were added to and then removed from the overflow table. all_rows: Vec, diff --git a/processor/src/stack/trace.rs b/processor/src/stack/trace.rs index f1dcc7210..d5102c5fc 100644 --- a/processor/src/stack/trace.rs +++ b/processor/src/stack/trace.rs @@ -17,6 +17,7 @@ use crate::utils::math::batch_inversion; /// The trace consists of 19 columns grouped logically as follows: /// - 16 stack columns holding the top of the stack. /// - 3 columns for bookkeeping and helper values that manage left and right shifts. +#[derive(Debug)] pub struct StackTrace { stack: [Vec; MIN_STACK_DEPTH], helpers: [Vec; NUM_STACK_HELPER_COLS], diff --git a/processor/src/system/mod.rs b/processor/src/system/mod.rs index 016560b54..d69bcbc99 100644 --- a/processor/src/system/mod.rs +++ b/processor/src/system/mod.rs @@ -40,6 +40,7 @@ pub const FMP_MAX: u64 = 3 * 2_u64.pow(30) - 1; /// - in_syscall flag which indicates whether the execution is currently in a SYSCALL block. /// - hash of the function which initiated the current execution context. if the context was /// initiated from the root context, this will be set to ZEROs. +#[derive(Debug)] pub struct System { clk: RowIndex, ctx: ContextId, diff --git a/processor/src/system/tests.rs b/processor/src/system/tests.rs index e59598b0d..ade4e1266 100644 --- a/processor/src/system/tests.rs +++ b/processor/src/system/tests.rs @@ -4,15 +4,14 @@ use crate::{DefaultHost, ExecutionOptions, Kernel, Operation, Process, StackInpu #[test] fn cycles_num_exceeded() { let stack = StackInputs::default(); - let host = DefaultHost::default(); + let mut host = DefaultHost::default(); let mut process = Process::new( Kernel::default(), stack, - host, ExecutionOptions::new(Some(64), 64, false, false).unwrap(), ); for _ in 0..64 { - process.execute_op(Operation::Noop).unwrap(); + process.execute_op(Operation::Noop, &mut host).unwrap(); } - assert!(process.execute_op(Operation::Noop).is_err()); + assert!(process.execute_op(Operation::Noop, &mut host).is_err()); } diff --git a/processor/src/trace/mod.rs b/processor/src/trace/mod.rs index df1e2c4af..5ad22d001 100644 --- a/processor/src/trace/mod.rs +++ b/processor/src/trace/mod.rs @@ -13,8 +13,7 @@ use super::{ chiplets::AuxTraceBuilder as ChipletsAuxTraceBuilder, crypto::RpoRandomCoin, decoder::AuxTraceBuilder as DecoderAuxTraceBuilder, range::AuxTraceBuilder as RangeCheckerAuxTraceBuilder, - stack::AuxTraceBuilder as StackAuxTraceBuilder, ColMatrix, Digest, Felt, FieldElement, Host, - Process, + stack::AuxTraceBuilder as StackAuxTraceBuilder, ColMatrix, Digest, Felt, FieldElement, Process, }; mod utils; @@ -68,10 +67,7 @@ impl ExecutionTrace { // CONSTRUCTOR // -------------------------------------------------------------------------------------------- /// Builds an execution trace for the provided process. - pub fn new(process: Process, stack_outputs: StackOutputs) -> Self - where - H: Host, - { + pub fn new(process: Process, stack_outputs: StackOutputs) -> Self { // use program hash to initialize random element generator; this generator will be used // to inject random values at the end of the trace; using program hash here is OK because // we are using random values only to stabilize constraint degrees, and not to achieve @@ -185,12 +181,7 @@ impl ExecutionTrace { } #[cfg(test)] - pub fn test_finalize_trace( - process: Process, - ) -> (MainTrace, AuxTraceBuilders, TraceLenSummary) - where - H: Host, - { + pub fn test_finalize_trace(process: Process) -> (MainTrace, AuxTraceBuilders, TraceLenSummary) { let rng = RpoRandomCoin::new(EMPTY_WORD); finalize_trace(process, rng) } @@ -275,14 +266,11 @@ impl Trace for ExecutionTrace { /// - Inserting random values in the last row of all columns. This helps ensure that there are no /// repeating patterns in each column and each column contains a least two distinct values. This, /// in turn, ensures that polynomial degrees of all columns are stable. -fn finalize_trace( - process: Process, +fn finalize_trace( + process: Process, mut rng: RpoRandomCoin, -) -> (MainTrace, AuxTraceBuilders, TraceLenSummary) -where - H: Host, -{ - let (system, decoder, stack, mut range, chiplets, _) = process.into_parts(); +) -> (MainTrace, AuxTraceBuilders, TraceLenSummary) { + let (system, decoder, stack, mut range, chiplets) = process.into_parts(); let clk = system.clk(); diff --git a/processor/src/trace/tests/mod.rs b/processor/src/trace/tests/mod.rs index 42524d68f..e6da40263 100644 --- a/processor/src/trace/tests/mod.rs +++ b/processor/src/trace/tests/mod.rs @@ -21,10 +21,9 @@ mod stack; /// Builds a sample trace by executing the provided code block against the provided stack inputs. pub fn build_trace_from_program(program: &Program, stack_inputs: &[u64]) -> ExecutionTrace { let stack_inputs = StackInputs::try_from_ints(stack_inputs.iter().copied()).unwrap(); - let host = DefaultHost::default(); - let mut process = - Process::new(Kernel::default(), stack_inputs, host, ExecutionOptions::default()); - process.execute(program).unwrap(); + let mut host = DefaultHost::default(); + let mut process = Process::new(Kernel::default(), stack_inputs, ExecutionOptions::default()); + process.execute(program, &mut host).unwrap(); ExecutionTrace::new(process, StackOutputs::default()) } @@ -50,9 +49,8 @@ pub fn build_trace_from_ops_with_inputs( advice_inputs: AdviceInputs, ) -> ExecutionTrace { let advice_provider = MemAdviceProvider::from(advice_inputs); - let host = DefaultHost::new(advice_provider); - let mut process = - Process::new(Kernel::default(), stack_inputs, host, ExecutionOptions::default()); + let mut host = DefaultHost::new(advice_provider); + let mut process = Process::new(Kernel::default(), stack_inputs, ExecutionOptions::default()); let mut mast_forest = MastForest::new(); let basic_block_id = mast_forest.add_block(operations, None).unwrap(); @@ -60,6 +58,6 @@ pub fn build_trace_from_ops_with_inputs( let program = Program::new(mast_forest.into(), basic_block_id); - process.execute(&program).unwrap(); + process.execute(&program, &mut host).unwrap(); ExecutionTrace::new(process, StackOutputs::default()) } diff --git a/prover/src/lib.rs b/prover/src/lib.rs index 2ba063bc2..09ab1de7e 100644 --- a/prover/src/lib.rs +++ b/prover/src/lib.rs @@ -55,15 +55,12 @@ pub use winter_prover::{crypto::MerkleTree as MerkleTreeVC, Proof}; /// Returns an error if program execution or STARK proof generation fails for any reason. #[instrument("prove_program", skip_all)] #[maybe_async] -pub fn prove( +pub fn prove( program: &Program, stack_inputs: StackInputs, - host: H, + host: &mut impl Host, options: ProvingOptions, -) -> Result<(StackOutputs, ExecutionProof), ExecutionError> -where - H: Host, -{ +) -> Result<(StackOutputs, ExecutionProof), ExecutionError> { // execute the program to create an execution trace #[cfg(feature = "std")] let now = Instant::now(); diff --git a/stdlib/tests/collections/mmr.rs b/stdlib/tests/collections/mmr.rs index 36fe1c548..5d9156c3d 100644 --- a/stdlib/tests/collections/mmr.rs +++ b/stdlib/tests/collections/mmr.rs @@ -522,9 +522,8 @@ fn test_mmr_pack() { expect_data.extend_from_slice(&[Felt::new(3), ZERO, ZERO, ZERO]); // num_leaves expect_data.extend_from_slice(&hash_data); - let process = build_test!(source).execute_process().unwrap(); + let (_, host) = build_test!(source).execute_process().unwrap(); - let host = process.host.borrow_mut(); let advice_data = host.advice_provider().map().get(&hash_u8).unwrap(); assert_eq!(advice_data, &expect_data); } diff --git a/stdlib/tests/crypto/falcon.rs b/stdlib/tests/crypto/falcon.rs index 260136a46..eb2796234 100644 --- a/stdlib/tests/crypto/falcon.rs +++ b/stdlib/tests/crypto/falcon.rs @@ -208,11 +208,12 @@ fn falcon_prove_verify() { let stack_inputs = StackInputs::try_from_ints(op_stack).expect("failed to create stack inputs"); let advice_inputs = AdviceInputs::default().with_map(advice_map); let advice_provider = MemAdviceProvider::from(advice_inputs); - let host = DefaultHost::new(advice_provider); + let mut host = DefaultHost::new(advice_provider); let options = ProvingOptions::with_96_bit_security(false); - let (stack_outputs, proof) = test_utils::prove(&program, stack_inputs.clone(), host, options) - .expect("failed to generate proof"); + let (stack_outputs, proof) = + test_utils::prove(&program, stack_inputs.clone(), &mut host, options) + .expect("failed to generate proof"); let program_info = ProgramInfo::from(program); let result = test_utils::verify(program_info, stack_inputs, stack_outputs, proof); diff --git a/stdlib/tests/crypto/stark/mod.rs b/stdlib/tests/crypto/stark/mod.rs index 6cf9226a2..b81a6f4b2 100644 --- a/stdlib/tests/crypto/stark/mod.rs +++ b/stdlib/tests/crypto/stark/mod.rs @@ -50,12 +50,12 @@ pub fn generate_recursive_verifier_data( let stack_inputs = StackInputs::try_from_ints(stack_inputs).unwrap(); let advice_inputs = AdviceInputs::default(); let advice_provider = MemAdviceProvider::from(advice_inputs); - let host = DefaultHost::new(advice_provider); + let mut host = DefaultHost::new(advice_provider); let options = ProvingOptions::new(43, 8, 12, FieldExtension::Quadratic, 4, 7, HashFunction::Rpo256); - let (stack_outputs, proof) = prove(&program, stack_inputs.clone(), host, options).unwrap(); + let (stack_outputs, proof) = prove(&program, stack_inputs.clone(), &mut host, options).unwrap(); let program_info = ProgramInfo::from(program); diff --git a/stdlib/tests/mem/mod.rs b/stdlib/tests/mem/mod.rs index 61c3836f9..f400e994c 100644 --- a/stdlib/tests/mem/mod.rs +++ b/stdlib/tests/mem/mod.rs @@ -1,4 +1,4 @@ -use processor::{ContextId, DefaultHost, ProcessState, Program}; +use processor::{ContextId, DefaultHost, Program}; use test_utils::{ build_expected_hash, build_expected_perm, felt_slice_to_ints, ExecutionOptions, Process, StackInputs, ONE, ZERO, @@ -33,62 +33,58 @@ fn test_memcopy() { let mut host = DefaultHost::default(); host.load_mast_forest(stdlib.mast_forest().clone()); - let mut process = Process::new( - program.kernel().clone(), - StackInputs::default(), - host, - ExecutionOptions::default(), - ); - process.execute(&program).unwrap(); + let mut process = + Process::new(program.kernel().clone(), StackInputs::default(), ExecutionOptions::default()); + process.execute(&program, &mut host).unwrap(); assert_eq!( - process.get_mem_value(ContextId::root(), 1000), + process.chiplets.get_mem_value(ContextId::root(), 1000), Some([ZERO, ZERO, ZERO, ONE]), "Address 1000" ); assert_eq!( - process.get_mem_value(ContextId::root(), 1001), + process.chiplets.get_mem_value(ContextId::root(), 1001), Some([ZERO, ZERO, ONE, ZERO]), "Address 1001" ); assert_eq!( - process.get_mem_value(ContextId::root(), 1002), + process.chiplets.get_mem_value(ContextId::root(), 1002), Some([ZERO, ZERO, ONE, ONE]), "Address 1002" ); assert_eq!( - process.get_mem_value(ContextId::root(), 1003), + process.chiplets.get_mem_value(ContextId::root(), 1003), Some([ZERO, ONE, ZERO, ZERO]), "Address 1003" ); assert_eq!( - process.get_mem_value(ContextId::root(), 1004), + process.chiplets.get_mem_value(ContextId::root(), 1004), Some([ZERO, ONE, ZERO, ONE]), "Address 1004" ); assert_eq!( - process.get_mem_value(ContextId::root(), 2000), + process.chiplets.get_mem_value(ContextId::root(), 2000), Some([ZERO, ZERO, ZERO, ONE]), "Address 2000" ); assert_eq!( - process.get_mem_value(ContextId::root(), 2001), + process.chiplets.get_mem_value(ContextId::root(), 2001), Some([ZERO, ZERO, ONE, ZERO]), "Address 2001" ); assert_eq!( - process.get_mem_value(ContextId::root(), 2002), + process.chiplets.get_mem_value(ContextId::root(), 2002), Some([ZERO, ZERO, ONE, ONE]), "Address 2002" ); assert_eq!( - process.get_mem_value(ContextId::root(), 2003), + process.chiplets.get_mem_value(ContextId::root(), 2003), Some([ZERO, ONE, ZERO, ZERO]), "Address 2003" ); assert_eq!( - process.get_mem_value(ContextId::root(), 2004), + process.chiplets.get_mem_value(ContextId::root(), 2004), Some([ZERO, ONE, ZERO, ONE]), "Address 2004" ); diff --git a/test-utils/src/lib.rs b/test-utils/src/lib.rs index c2515702d..71b8c9a63 100644 --- a/test-utils/src/lib.rs +++ b/test-utils/src/lib.rs @@ -250,17 +250,18 @@ impl Test { let mut process = Process::new( program.kernel().clone(), self.stack_inputs.clone(), - host, ExecutionOptions::default(), ); - process.execute(&program).unwrap(); + process.execute(&program, &mut host).unwrap(); // validate the memory state for data in expected_mem.chunks(WORD_SIZE) { // Main memory is zeroed by default, use zeros as a fallback when unwrap to make testing // easier - let mem_state = - process.get_mem_value(ContextId::root(), mem_start_addr).unwrap_or(EMPTY_WORD); + let mem_state = process + .chiplets + .get_mem_value(ContextId::root(), mem_start_addr) + .unwrap_or(EMPTY_WORD); let mem_state = felt_slice_to_ints(&mem_state); assert_eq!( @@ -343,14 +344,19 @@ impl Test { for library in &self.libraries { host.load_mast_forest(library.mast_forest().clone()); } - processor::execute(&program, self.stack_inputs.clone(), host, ExecutionOptions::default()) + processor::execute( + &program, + self.stack_inputs.clone(), + &mut host, + ExecutionOptions::default(), + ) } /// Compiles the test's source to a Program and executes it with the tests inputs. Returns the /// process once execution is finished. pub fn execute_process( &self, - ) -> Result>, ExecutionError> { + ) -> Result<(Process, DefaultHost), ExecutionError> { let (program, kernel) = self.compile().expect("Failed to compile test source."); let mut host = DefaultHost::new(MemAdviceProvider::from(self.advice_inputs.clone())); if let Some(kernel) = kernel { @@ -363,11 +369,10 @@ impl Test { let mut process = Process::new( program.kernel().clone(), self.stack_inputs.clone(), - host, ExecutionOptions::default(), ); - process.execute(&program)?; - Ok(process) + process.execute(&program, &mut host)?; + Ok((process, host)) } /// Compiles the test's code into a program, then generates and verifies a proof of execution @@ -384,7 +389,8 @@ impl Test { host.load_mast_forest(library.mast_forest().clone()); } let (mut stack_outputs, proof) = - prover::prove(&program, stack_inputs.clone(), host, ProvingOptions::default()).unwrap(); + prover::prove(&program, stack_inputs.clone(), &mut host, ProvingOptions::default()) + .unwrap(); let program_info = ProgramInfo::from(program); if test_fail { @@ -408,7 +414,7 @@ impl Test { for library in &self.libraries { host.load_mast_forest(library.mast_forest().clone()); } - processor::execute_iter(&program, self.stack_inputs.clone(), host) + processor::execute_iter(&program, self.stack_inputs.clone(), &mut host) } /// Returns the last state of the stack after executing a test.