diff --git a/CHANGELOG.md b/CHANGELOG.md index 77d4f16d4..8a4b2c850 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - Fixed the construction of the block hash table (#1506) - Fixed a bug in the block stack table (#1511) - Fixed the construction of the chiplets virtual table (#1514) +- Fixed the construction of the chiplets bus (#1516) #### Fixes diff --git a/miden/src/repl/mod.rs b/miden/src/repl/mod.rs index b0c41f4e2..692e29df5 100644 --- a/miden/src/repl/mod.rs +++ b/miden/src/repl/mod.rs @@ -6,141 +6,141 @@ use processor::ContextId; use rustyline::{error::ReadlineError, DefaultEditor}; use stdlib::StdLibrary; -/// This work is in continuation to the amazing work done by team `Scribe` -/// [here](https://github.com/ControlCplusControlV/Scribe/blob/main/transpiler/src/repl.rs#L8) -/// -/// The Miden Read–eval–print loop (REPL) is a Miden shell that allows for quick and easy debugging -/// of Miden assembly. To use the repl, simply type "miden repl" after building it with feature -/// "executable" (cargo build --release --feature executable) when in the miden home -/// crate and the repl will launch. After the REPL gets initialized, you can execute any Miden -/// instruction, undo executed instructions, check the state of the stack and memory at a given -/// point, and do many other useful things! When the REPL is exited, a `history.txt` file is saved. -/// One thing to note is that all the REPL native commands start with an `!` to differentiate them -/// from regular assembly instructions. -/// -/// Miden Instructions -/// All Miden instructions mentioned in the -/// [Miden Assembly section](https://0xpolygonmiden.github.io/miden-vm/user_docs/assembly/main.html) -/// are valid. -/// One can either input instructions one by one or multiple instructions in one input. -/// For example, the below two commands will result in the same output. -/// >> push.1 -/// >> push.2 -/// >> push.3 -/// -/// >> push.1 push.2 push.3 -/// -/// In order to execute a control flow operation, one needs to write the entire flow operation in -/// a single line with spaces between individual operations. -/// Ex. -/// ``` -/// repeat.20 -/// pow2 -/// end -/// ``` -/// should be written as -/// `repeat.20 pow2 end` -/// -/// To execute a control flow operation, one must write the entire statement in a single line with -/// spaces between individual operations. -/// ``` -/// >> repeat.20 -/// pow2 -/// end -/// ``` -/// -/// The above example should be written as follows in the REPL tool: -/// >> repeat.20 pow2 end -/// -/// `!stack` -/// The `!stack` command prints out the state of the stack at the last executed instruction. Since -/// the stack always contains at least 16 elements, 16 or more elements will be printed out (even -/// if all of them are zeros). -/// >> push.1 push.2 push.3 push.4 push.5 -/// >> exp -/// >> u32wrapping_mul -/// >> swap -/// >> eq.2 -/// >> assert -/// -/// The `!stack` command will print out the following state of the stack: -/// ``` -/// >> !stack -/// 3072 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -/// ``` -/// -/// `!undo` -/// The `!undo` command reverts to the previous state of the stack and memory by dropping off the -/// last executed assembly instruction from the program. One could use `!undo` as often as they want -/// to restore the state of a stack and memory $n$ instructions ago (provided there are $n$ -/// instructions in the program). The `!undo` command will result in an error if no remaining -/// instructions are left in the miden program. -/// ``` -/// >> push.1 push.2 push.3 -/// >> push.4 -/// >> !stack -/// 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 -/// >> push.5 -/// >> !stack -/// 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 -/// >> !undo -/// 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 -/// >> !undo -/// 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 -/// ``` -/// -///`!program` -/// The `!program` command prints out the entire miden program getting executed. E.g., in the below -/// ``` -/// scenario: >> push.1 -/// >> push.2 -/// >> push.3 -/// >> add -/// >> add -/// >> !program -/// begin -/// push.1 -/// push.2 -/// push.3 -/// add -/// add -/// end -/// ``` -/// -/// `!help` -/// The `!help` command prints out all the available commands in the REPL tool. -/// -/// `!mem` -/// The `!mem` command prints out the contents of all initialized memory locations. For each such -/// location, the address, along with its memory values, is printed. Recall that four elements are -/// stored at each memory address. -/// If the memory has at least one value that has been initialized: -/// ``` -/// >> !mem -/// 7: [1, 2, 0, 3] -/// 8: [5, 7, 3, 32] -/// 9: [9, 10, 2, 0] -/// ``` -/// -/// If the memory is not yet been initialized: -/// ``` -/// >> !mem -/// The memory has not been initialized yet -/// ``` -/// -/// `!mem[addr]` -/// The `!mem[addr]` command prints out memory contents at the address specified by `addr`. -/// If the `addr` has been initialized: -/// ``` -/// >> !mem[9] -/// 9: [9, 10, 2, 0] -/// ``` -/// -/// If the `addr` has not been initialized: -/// ``` -/// >> !mem[87] -/// Memory at address 87 is empty -/// ``` +// This work is in continuation to the amazing work done by team `Scribe` +// [here](https://github.com/ControlCplusControlV/Scribe/blob/main/transpiler/src/repl.rs#L8) +// +// The Miden Read–eval–print loop (REPL) is a Miden shell that allows for quick and easy debugging +// of Miden assembly. To use the repl, simply type "miden repl" after building it with feature +// "executable" (cargo build --release --feature executable) when in the miden home +// crate and the repl will launch. After the REPL gets initialized, you can execute any Miden +// instruction, undo executed instructions, check the state of the stack and memory at a given +// point, and do many other useful things! When the REPL is exited, a `history.txt` file is saved. +// One thing to note is that all the REPL native commands start with an `!` to differentiate them +// from regular assembly instructions. +// +// Miden Instructions +// All Miden instructions mentioned in the +// [Miden Assembly section](https://0xpolygonmiden.github.io/miden-vm/user_docs/assembly/main.html) +// are valid. +// One can either input instructions one by one or multiple instructions in one input. +// For example, the below two commands will result in the same output. +// >> push.1 +// >> push.2 +// >> push.3 +// +// >> push.1 push.2 push.3 +// +// In order to execute a control flow operation, one needs to write the entire flow operation in +// a single line with spaces between individual operations. +// Ex. +// ``` +// repeat.20 +// pow2 +// end +// ``` +// should be written as +// `repeat.20 pow2 end` +// +// To execute a control flow operation, one must write the entire statement in a single line with +// spaces between individual operations. +// ``` +// >> repeat.20 +// pow2 +// end +// ``` +// +// The above example should be written as follows in the REPL tool: +// >> repeat.20 pow2 end +// +// `!stack` +// The `!stack` command prints out the state of the stack at the last executed instruction. Since +// the stack always contains at least 16 elements, 16 or more elements will be printed out (even +// if all of them are zeros). +// >> push.1 push.2 push.3 push.4 push.5 +// >> exp +// >> u32wrapping_mul +// >> swap +// >> eq.2 +// >> assert +// +// The `!stack` command will print out the following state of the stack: +// ``` +// >> !stack +// 3072 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +// ``` +// +// `!undo` +// The `!undo` command reverts to the previous state of the stack and memory by dropping off the +// last executed assembly instruction from the program. One could use `!undo` as often as they want +// to restore the state of a stack and memory $n$ instructions ago (provided there are $n$ +// instructions in the program). The `!undo` command will result in an error if no remaining +// instructions are left in the miden program. +// ``` +// >> push.1 push.2 push.3 +// >> push.4 +// >> !stack +// 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 +// >> push.5 +// >> !stack +// 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 +// >> !undo +// 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 +// >> !undo +// 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +// ``` +// +//`!program` +// The `!program` command prints out the entire miden program getting executed. E.g., in the below +// ``` +// scenario: >> push.1 +// >> push.2 +// >> push.3 +// >> add +// >> add +// >> !program +// begin +// push.1 +// push.2 +// push.3 +// add +// add +// end +// ``` +// +// `!help` +// The `!help` command prints out all the available commands in the REPL tool. +// +// `!mem` +// The `!mem` command prints out the contents of all initialized memory locations. For each such +// location, the address, along with its memory values, is printed. Recall that four elements are +// stored at each memory address. +// If the memory has at least one value that has been initialized: +// ``` +// >> !mem +// 7: [1, 2, 0, 3] +// 8: [5, 7, 3, 32] +// 9: [9, 10, 2, 0] +// ``` +// +// If the memory is not yet been initialized: +// ``` +// >> !mem +// The memory has not been initialized yet +// ``` +// +// `!mem[addr]` +// The `!mem[addr]` command prints out memory contents at the address specified by `addr`. +// If the `addr` has been initialized: +// ``` +// >> !mem[9] +// 9: [9, 10, 2, 0] +// ``` +// +// If the `addr` has not been initialized: +// ``` +// >> !mem[87] +// Memory at address 87 is empty +// ``` /// Initiates the Miden Repl tool. pub fn start_repl(library_paths: &Vec, use_stdlib: bool) { @@ -295,8 +295,8 @@ pub fn start_repl(library_paths: &Vec, use_stdlib: bool) { .expect("Couldn't dump the program into the history file"); } -/// HELPER METHODS -/// -------------------------------------------------------------------------------------------- +// HELPER METHODS +// -------------------------------------------------------------------------------------------- /// Compiles and executes a compiled Miden program, returning the stack, memory and any Miden /// errors. The program is passed in as a String, passed to the Miden Assembler, and then passed diff --git a/processor/src/chiplets/aux_trace/mod.rs b/processor/src/chiplets/aux_trace/mod.rs index c383ffc5e..9e36bf0c7 100644 --- a/processor/src/chiplets/aux_trace/mod.rs +++ b/processor/src/chiplets/aux_trace/mod.rs @@ -19,8 +19,8 @@ use miden_air::{ use vm_core::{ Word, ONE, OPCODE_CALL, OPCODE_DYN, OPCODE_END, OPCODE_HPERM, OPCODE_JOIN, OPCODE_LOOP, OPCODE_MLOAD, OPCODE_MLOADW, OPCODE_MPVERIFY, OPCODE_MRUPDATE, OPCODE_MSTORE, OPCODE_MSTOREW, - OPCODE_MSTREAM, OPCODE_RCOMBBASE, OPCODE_RESPAN, OPCODE_SPAN, OPCODE_SPLIT, OPCODE_SYSCALL, - OPCODE_U32AND, OPCODE_U32XOR, ZERO, + OPCODE_MSTREAM, OPCODE_PIPE, OPCODE_RCOMBBASE, OPCODE_RESPAN, OPCODE_SPAN, OPCODE_SPLIT, + OPCODE_SYSCALL, OPCODE_U32AND, OPCODE_U32XOR, ZERO, }; use super::{super::trace::AuxColumnBuilder, Felt, FieldElement}; @@ -55,6 +55,7 @@ impl AuxTraceBuilder { let b_chip = bus_col_builder.build_aux_column(main_trace, rand_elements); debug_assert_eq!(*t_chip.last().unwrap(), E::ONE); + debug_assert_eq!(*b_chip.last().unwrap(), E::ONE); vec![t_chip, b_chip] } } @@ -258,6 +259,7 @@ impl> AuxColumnBuilder for BusColumnBuilder OPCODE_HPERM => build_hperm_request(main_trace, alphas, row), OPCODE_MPVERIFY => build_mpverify_request(main_trace, alphas, row), OPCODE_MRUPDATE => build_mrupdate_request(main_trace, alphas, row), + OPCODE_PIPE => build_pipe_request(main_trace, alphas, row), _ => E::ONE, } } @@ -340,7 +342,6 @@ fn build_span_block_request>( alphas[0] + alphas[1].mul_base(Felt::from(transition_label)) + alphas[2].mul_base(addr_nxt); let state = main_trace.decoder_hasher_state(row); - header + build_value(&alphas[8..16], &state) } @@ -361,10 +362,9 @@ fn build_respan_block_request>( + alphas[2].mul_base(addr_nxt - ONE) + alphas[3].mul_base(ZERO); - let state = &main_trace.chiplet_hasher_state(row - 2)[CAPACITY_LEN..]; - let state_nxt = &main_trace.chiplet_hasher_state(row - 1)[CAPACITY_LEN..]; + let state = main_trace.decoder_hasher_state(row); - header + build_value(&alphas[8..16], state_nxt) - build_value(&alphas[8..16], state) + header + build_value(&alphas[8..16], &state) } /// Builds requests made to the hasher chiplet at the end of a block. @@ -471,6 +471,33 @@ fn build_mstream_request>( factor1 * factor2 } +/// Builds `PIPE` requests made to the memory chiplet. +fn build_pipe_request>( + main_trace: &MainTrace, + alphas: &[E], + row: RowIndex, +) -> E { + let word1 = [ + main_trace.stack_element(7, row + 1), + main_trace.stack_element(6, row + 1), + main_trace.stack_element(5, row + 1), + main_trace.stack_element(4, row + 1), + ]; + let word2 = [ + main_trace.stack_element(3, row + 1), + main_trace.stack_element(2, row + 1), + main_trace.stack_element(1, row + 1), + main_trace.stack_element(0, row + 1), + ]; + let addr = main_trace.stack_element(12, row); + let op_label = MEMORY_WRITE_LABEL; + + let factor1 = compute_memory_request(main_trace, op_label, alphas, row, addr, word1); + let factor2 = compute_memory_request(main_trace, op_label, alphas, row, addr + ONE, word2); + + factor1 * factor2 +} + /// Builds `RCOMBBASE` requests made to the memory chiplet. fn build_rcomb_base_request>( main_trace: &MainTrace, @@ -827,13 +854,12 @@ where let state_nxt = main_trace.chiplet_hasher_state(row + 1); - // build the value from the difference of the hasher state's just before and right - // after the absorption of new elements. + // build the value from the hasher state's just right after the absorption of new + // elements. let next_state_value = build_value(&alphas_state[CAPACITY_LEN..], &state_nxt[CAPACITY_LEN..]); - let state_value = build_value(&alphas_state[CAPACITY_LEN..], &state[CAPACITY_LEN..]); - multiplicand = header + next_state_value - state_value; + multiplicand = header + next_state_value; } } multiplicand diff --git a/processor/src/decoder/mod.rs b/processor/src/decoder/mod.rs index 2a87d06ee..274a7d270 100644 --- a/processor/src/decoder/mod.rs +++ b/processor/src/decoder/mod.rs @@ -292,7 +292,7 @@ where // -------------------------------------------------------------------------------------------- /// Starts decoding of a DYN node. - pub(super) fn start_dyn_node(&mut self, callee_hash: Word) -> Result<(), ExecutionError> { + pub(super) fn start_dyn_node(&mut self) -> Result<(), ExecutionError> { let addr = self.chiplets.hash_control_block( EMPTY_WORD, EMPTY_WORD, @@ -300,7 +300,7 @@ where DynNode::default().digest(), ); - self.decoder.start_dyn(callee_hash, addr); + self.decoder.start_dyn(addr); self.execute_op(Operation::Noop) } @@ -534,10 +534,10 @@ impl Decoder { /// /// This pushes a block with ID=addr onto the block stack and appends execution of a DYN /// operation to the trace. - pub fn start_dyn(&mut self, dyn_hash: Word, addr: Felt) { + pub fn start_dyn(&mut self, addr: Felt) { // push DYN block info onto the block stack and append a DYN row to the execution trace let parent_addr = self.block_stack.push(addr, BlockType::Dyn, None); - self.trace.append_block_start(parent_addr, Operation::Dyn, dyn_hash, [ZERO; 4]); + self.trace.append_block_start(parent_addr, Operation::Dyn, [ZERO; 4], [ZERO; 4]); self.debug_info.append_operation(Operation::Dyn); } diff --git a/processor/src/decoder/tests.rs b/processor/src/decoder/tests.rs index 8451faecc..59eb15c6b 100644 --- a/processor/src/decoder/tests.rs +++ b/processor/src/decoder/tests.rs @@ -1277,9 +1277,9 @@ fn dyn_block() { assert_eq!(join_hash, get_hasher_state1(&trace, 8)); assert_eq!([ZERO, ZERO, ZERO, ZERO], get_hasher_state2(&trace, 8)); - // at the start of the DYN block, the hasher state is set to the hash of its child (foo span) + // at the start of the DYN block, the hasher state is set to ZERO let foo_hash: Word = foo_root_node.digest().into(); - assert_eq!(foo_hash, get_hasher_state1(&trace, 9)); + assert_eq!([ZERO, ZERO, ZERO, ZERO], get_hasher_state1(&trace, 9)); assert_eq!([ZERO, ZERO, ZERO, ZERO], get_hasher_state2(&trace, 9)); // at the end of the DYN SPAN, the hasher state is set to the hash of the foo span diff --git a/processor/src/lib.rs b/processor/src/lib.rs index c8d8ef22a..6e844593f 100644 --- a/processor/src/lib.rs +++ b/processor/src/lib.rs @@ -410,9 +410,10 @@ where /// expected to be either in the current `program` or in the host. #[inline(always)] fn execute_dyn_node(&mut self, program: &MastForest) -> Result<(), ExecutionError> { + self.start_dyn_node()?; + // get target hash from the stack let callee_hash = self.stack.get_word(0); - self.start_dyn_node(callee_hash)?; // 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 diff --git a/processor/src/trace/tests/chiplets/hasher.rs b/processor/src/trace/tests/chiplets/hasher.rs index 01d6aa4bb..813b009d3 100644 --- a/processor/src/trace/tests/chiplets/hasher.rs +++ b/processor/src/trace/tests/chiplets/hasher.rs @@ -810,9 +810,8 @@ fn build_expected( // include the entire state (words a, b, c) value += build_value(&alphas[4..16], &state); } else if label == LINEAR_HASH_LABEL { - // include the delta between the next and current rate elements (words b and c) + // include the next rate elements value += build_value(&alphas[8..16], &next_state[CAPACITY_LEN..]); - value -= build_value(&alphas[8..16], &state[CAPACITY_LEN..]); } else if label == RETURN_HASH_LABEL { // include the digest (word b) value += build_value(&alphas[8..12], &state[DIGEST_RANGE]);