From f3803676974ff2fcea2431a878d5fe5910f5778d Mon Sep 17 00:00:00 2001 From: Jan Ferdinand Sauer Date: Thu, 2 Nov 2023 18:02:44 +0100 Subject: [PATCH] refactor(op_stack): simplify recording of op stack underflow I/O calls --- triton-vm/src/op_stack.rs | 73 ++++++----- triton-vm/src/vm.rs | 267 +++++++++++++++----------------------- 2 files changed, 141 insertions(+), 199 deletions(-) diff --git a/triton-vm/src/op_stack.rs b/triton-vm/src/op_stack.rs index 87481c41..6d7fbe35 100644 --- a/triton-vm/src/op_stack.rs +++ b/triton-vm/src/op_stack.rs @@ -17,7 +17,6 @@ use twenty_first::shared_math::b_field_element::BFieldElement; use twenty_first::shared_math::digest::Digest; use twenty_first::shared_math::tip5::DIGEST_LENGTH; use twenty_first::shared_math::x_field_element::XFieldElement; -use twenty_first::shared_math::x_field_element::EXTENSION_DEGREE; use crate::error::InstructionError::*; use crate::op_stack::OpStackElement::*; @@ -38,6 +37,7 @@ pub const NUM_OP_STACK_REGISTERS: usize = OpStackElement::COUNT; #[derive(Debug, Clone)] pub struct OpStack { pub stack: Vec, + underflow_io_sequence: Vec, } impl OpStack { @@ -47,61 +47,64 @@ impl OpStack { let reverse_digest = program_digest.reversed().values(); stack[..DIGEST_LENGTH].copy_from_slice(&reverse_digest); - Self { stack } + Self { + stack, + underflow_io_sequence: vec![], + } } - pub(crate) fn push(&mut self, element: BFieldElement) -> UnderflowIO { + pub(crate) fn push(&mut self, element: BFieldElement) { self.stack.push(element); - UnderflowIO::Write(self.first_underflow_element()) + self.record_underflow_io(UnderflowIO::Write); } - pub(crate) fn push_extension_field_element( - &mut self, - element: XFieldElement, - ) -> [UnderflowIO; EXTENSION_DEGREE] { - let mut underflow_io = vec![]; - for coefficient in element.coefficients.into_iter().rev() { - let underflow_write = self.push(coefficient); - underflow_io.push(underflow_write); - } - underflow_io.try_into().unwrap() + pub(crate) fn pop(&mut self) -> Result { + self.record_underflow_io(UnderflowIO::Read); + let element = self.stack.pop().ok_or_else(|| anyhow!(OpStackTooShallow))?; + Ok(element) } - pub(crate) fn pop(&mut self) -> Result<(BFieldElement, UnderflowIO)> { - let underflow_io = UnderflowIO::Read(self.first_underflow_element()); - let element = self.stack.pop().ok_or_else(|| anyhow!(OpStackTooShallow))?; - Ok((element, underflow_io)) + fn record_underflow_io(&mut self, io_type: fn(BFieldElement) -> UnderflowIO) { + let underflow_io = io_type(self.first_underflow_element()); + self.underflow_io_sequence.push(underflow_io); + } + + pub(crate) fn start_recording_underflow_io_sequence(&mut self) { + self.underflow_io_sequence.clear(); + } + + pub(crate) fn stop_recording_underflow_io_sequence(&mut self) -> Vec { + self.underflow_io_sequence.drain(..).collect() + } + + pub(crate) fn push_extension_field_element(&mut self, element: XFieldElement) { + for coefficient in element.coefficients.into_iter().rev() { + self.push(coefficient); + } } - pub(crate) fn pop_extension_field_element( - &mut self, - ) -> Result<(XFieldElement, [UnderflowIO; EXTENSION_DEGREE])> { - let (coefficients, underflow_io) = self.pop_multiple()?; + pub(crate) fn pop_extension_field_element(&mut self) -> Result { + let coefficients = self.pop_multiple()?; let element = XFieldElement::new(coefficients); - Ok((element, underflow_io)) + Ok(element) } - pub(crate) fn pop_u32(&mut self) -> Result<(u32, UnderflowIO)> { - let (element, underflow_io) = self.pop()?; + pub(crate) fn pop_u32(&mut self) -> Result { + let element = self.pop()?; let element = element .try_into() .map_err(|_| anyhow!(FailedU32Conversion(element)))?; - Ok((element, underflow_io)) + Ok(element) } - pub(crate) fn pop_multiple( - &mut self, - ) -> Result<([BFieldElement; N], [UnderflowIO; N])> { + pub(crate) fn pop_multiple(&mut self) -> Result<[BFieldElement; N]> { let mut elements = vec![]; - let mut underflow_io = vec![]; for _ in 0..N { - let (element, underflow_read) = self.pop()?; + let element = self.pop()?; elements.push(element); - underflow_io.push(underflow_read); } let elements = elements.try_into().unwrap(); - let underflow_io = underflow_io.try_into().unwrap(); - Ok((elements, underflow_io)) + Ok(elements) } pub(crate) fn peek_at(&self, stack_element: OpStackElement) -> BFieldElement { @@ -420,7 +423,7 @@ mod tests { // push elements 1 thru 17 for i in 1..=17 { - let _ = op_stack.push(BFieldElement::new(i as u64)); + op_stack.push(BFieldElement::new(i as u64)); } // verify height diff --git a/triton-vm/src/vm.rs b/triton-vm/src/vm.rs index 09b9e645..7a3578c7 100644 --- a/triton-vm/src/vm.rs +++ b/triton-vm/src/vm.rs @@ -199,7 +199,8 @@ impl<'pgm> VMState<'pgm> { self.previous_instruction = Some(instruction); } - let co_processor_calls = match self.current_instruction()? { + self.start_recording_op_stack_calls(); + let mut co_processor_calls = match self.current_instruction()? { Pop(n) => self.pop(n)?, Push(field_element) => self.push(field_element), Divine(n) => self.divine(n)?, @@ -239,15 +240,27 @@ impl<'pgm> VMState<'pgm> { WriteIo => self.write_io()?, ReadIo => self.read_io()?, }; + let op_stack_calls = self.stop_recording_op_stack_calls(); + co_processor_calls.extend(op_stack_calls); if self.op_stack.is_too_shallow() { bail!(OpStackTooShallow); } self.cycle_count += 1; + Ok(co_processor_calls) } + fn start_recording_op_stack_calls(&mut self) { + self.op_stack.start_recording_underflow_io_sequence(); + } + + fn stop_recording_op_stack_calls(&mut self) -> Vec { + let sequence = self.op_stack.stop_recording_underflow_io_sequence(); + self.underflow_io_sequence_to_co_processor_calls(sequence) + } + fn underflow_io_sequence_to_co_processor_calls( &self, underflow_io_sequence: Vec, @@ -268,25 +281,19 @@ impl<'pgm> VMState<'pgm> { bail!(IllegalPop(n.into())); } - let mut all_underflow_io = vec![]; for _ in 0..n.into() { - let (_, underflow_io) = self.op_stack.pop()?; - all_underflow_io.push(underflow_io); + self.op_stack.pop()?; } - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(all_underflow_io); - self.instruction_pointer += 2; - Ok(op_stack_calls) + Ok(vec![]) } fn push(&mut self, element: BFieldElement) -> Vec { - let underflow_io = self.op_stack.push(element); - - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(vec![underflow_io]); + self.op_stack.push(element); self.instruction_pointer += 2; - op_stack_calls + vec![] } fn divine(&mut self, n: OpStackElement) -> Result> { @@ -294,30 +301,23 @@ impl<'pgm> VMState<'pgm> { bail!(IllegalDivine(n.into())); } - let mut all_underflow_io = vec![]; for i in 0..n.into() { - let maybe_element = self.secret_individual_tokens.pop_front(); - let element = maybe_element.ok_or(anyhow!( + let element = self.secret_individual_tokens.pop_front().ok_or(anyhow!( "Instruction `divine {n}`: secret input buffer is empty after {i}." ))?; - let underflow_io = self.op_stack.push(element); - all_underflow_io.push(underflow_io); + self.op_stack.push(element); } - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(all_underflow_io); - self.instruction_pointer += 2; - Ok(op_stack_calls) + Ok(vec![]) } fn dup(&mut self, stack_register: OpStackElement) -> Vec { let element = self.op_stack.peek_at(stack_register); - let underflow_io = self.op_stack.push(element); - - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(vec![underflow_io]); + self.op_stack.push(element); self.instruction_pointer += 2; - op_stack_calls + vec![] } fn swap(&mut self, stack_register: OpStackElement) -> Result> { @@ -335,15 +335,12 @@ impl<'pgm> VMState<'pgm> { } fn skiz(&mut self) -> Result> { - let (top_of_stack, underflow_io) = self.op_stack.pop()?; - - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(vec![underflow_io]); - + let top_of_stack = self.op_stack.pop()?; self.instruction_pointer += match top_of_stack.is_zero() { true => 1 + self.next_instruction()?.size(), false => 1, }; - Ok(op_stack_calls) + Ok(vec![]) } fn call(&mut self, call_destination: BFieldElement) -> Vec { @@ -369,9 +366,7 @@ impl<'pgm> VMState<'pgm> { } fn assert(&mut self) -> Result> { - let (top_of_stack, underflow_io) = self.op_stack.pop()?; - - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(vec![underflow_io]); + let top_of_stack = self.op_stack.pop()?; if !top_of_stack.is_one() { let assertion_failed = @@ -380,7 +375,7 @@ impl<'pgm> VMState<'pgm> { } self.instruction_pointer += 1; - Ok(op_stack_calls) + Ok(vec![]) } fn halt(&mut self) -> Vec { @@ -394,29 +389,24 @@ impl<'pgm> VMState<'pgm> { self.ram_pointer = ram_pointer.value(); let ram_value = self.memory_get(&ram_pointer); - let underflow_io = self.op_stack.push(ram_value); - - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(vec![underflow_io]); + self.op_stack.push(ram_value); self.instruction_pointer += 1; - op_stack_calls + vec![] } fn write_mem(&mut self) -> Result> { let ram_pointer = self.op_stack.peek_at(ST1); - let (ram_value, underflow_io) = self.op_stack.pop()?; + let ram_value = self.op_stack.pop()?; self.ram_pointer = ram_pointer.value(); self.ram.insert(ram_pointer, ram_value); - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(vec![underflow_io]); - self.instruction_pointer += 1; - Ok(op_stack_calls) + Ok(vec![]) } fn hash(&mut self) -> Result> { - let (to_hash, underflow_io) = self.op_stack.pop_multiple::<{ tip5::RATE }>()?; - let mut all_underflow_io = underflow_io.to_vec(); + let to_hash = self.op_stack.pop_multiple::<{ tip5::RATE }>()?; let mut hash_input = Tip5State::new(Domain::FixedLength); hash_input.state[..tip5::RATE].copy_from_slice(&to_hash); @@ -424,13 +414,10 @@ impl<'pgm> VMState<'pgm> { let hash_output = &tip5_trace[tip5_trace.len() - 1][0..DIGEST_LENGTH]; for i in (0..DIGEST_LENGTH).rev() { - let underflow_io = self.op_stack.push(hash_output[i]); - all_underflow_io.push(underflow_io); + self.op_stack.push(hash_output[i]); } - let mut co_processor_calls = - self.underflow_io_sequence_to_co_processor_calls(all_underflow_io); - co_processor_calls.push(Tip5Trace(Hash, Box::new(tip5_trace))); + let co_processor_calls = vec![Tip5Trace(Hash, Box::new(tip5_trace))]; self.instruction_pointer += 1; Ok(co_processor_calls) @@ -444,11 +431,9 @@ impl<'pgm> VMState<'pgm> { fn sponge_absorb(&mut self) -> Result> { // fetch top elements but don't alter the stack - let (to_absorb, underflow_io) = self.op_stack.pop_multiple::<{ tip5::RATE }>()?; - let mut all_underflow_io = underflow_io.to_vec(); + let to_absorb = self.op_stack.pop_multiple::<{ tip5::RATE }>()?; for i in (0..tip5::RATE).rev() { - let underflow_io = self.op_stack.push(to_absorb[i]); - all_underflow_io.push(underflow_io); + self.op_stack.push(to_absorb[i]); } self.sponge_state[..tip5::RATE].copy_from_slice(&to_absorb); @@ -457,57 +442,48 @@ impl<'pgm> VMState<'pgm> { }); self.sponge_state = tip5_trace.last().unwrap().to_owned(); - let mut co_processor_calls = - self.underflow_io_sequence_to_co_processor_calls(all_underflow_io); - co_processor_calls.push(Tip5Trace(SpongeAbsorb, Box::new(tip5_trace))); + let co_processor_calls = vec![Tip5Trace(SpongeAbsorb, Box::new(tip5_trace))]; self.instruction_pointer += 1; Ok(co_processor_calls) } fn sponge_squeeze(&mut self) -> Result> { - let (_, underflow_io) = self.op_stack.pop_multiple::<{ tip5::RATE }>()?; - let mut all_underflow_io = underflow_io.to_vec(); + let _ = self.op_stack.pop_multiple::<{ tip5::RATE }>()?; for i in (0..tip5::RATE).rev() { - let underflow_io = self.op_stack.push(self.sponge_state[i]); - all_underflow_io.push(underflow_io); + self.op_stack.push(self.sponge_state[i]); } let tip5_trace = Tip5::trace(&mut Tip5State { state: self.sponge_state, }); self.sponge_state = tip5_trace.last().unwrap().to_owned(); - let mut co_processor_calls = - self.underflow_io_sequence_to_co_processor_calls(all_underflow_io); - co_processor_calls.push(Tip5Trace(SpongeSqueeze, Box::new(tip5_trace))); + let co_processor_calls = vec![Tip5Trace(SpongeSqueeze, Box::new(tip5_trace))]; self.instruction_pointer += 1; Ok(co_processor_calls) } fn divine_sibling(&mut self) -> Result> { - let (known_digest, _) = self.op_stack.pop_multiple()?; - let (node_index, _) = self.op_stack.pop_u32()?; + let known_digest = self.op_stack.pop_multiple()?; + let node_index = self.op_stack.pop_u32()?; let parent_node_index = node_index / 2; - let _ = self.op_stack.push(parent_node_index.into()); + self.op_stack.push(parent_node_index.into()); let sibling_digest = self.pop_secret_digest()?; let (left_digest, right_digest) = Self::put_known_digest_on_correct_side(node_index, known_digest, sibling_digest); for &digest_element in right_digest.iter().rev() { - let _ = self.op_stack.push(digest_element); + self.op_stack.push(digest_element); } - let mut all_underflow_io = vec![]; for &digest_element in left_digest.iter().rev() { - let underflow_io = self.op_stack.push(digest_element); - all_underflow_io.push(underflow_io); + self.op_stack.push(digest_element); } - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(all_underflow_io); self.instruction_pointer += 1; - Ok(op_stack_calls) + Ok(vec![]) } fn assert_vector(&mut self) -> Result> { @@ -535,172 +511,139 @@ impl<'pgm> VMState<'pgm> { } fn add(&mut self) -> Result> { - let (lhs, underflow_io_lhs) = self.op_stack.pop()?; - let (rhs, underflow_io_rhs) = self.op_stack.pop()?; - let underflow_io_result = self.op_stack.push(lhs + rhs); - - let underflow_io = vec![underflow_io_lhs, underflow_io_rhs, underflow_io_result]; - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(underflow_io); + let lhs = self.op_stack.pop()?; + let rhs = self.op_stack.pop()?; + self.op_stack.push(lhs + rhs); self.instruction_pointer += 1; - Ok(op_stack_calls) + Ok(vec![]) } fn mul(&mut self) -> Result> { - let (lhs, underflow_io_lhs) = self.op_stack.pop()?; - let (rhs, underflow_io_rhs) = self.op_stack.pop()?; - let underflow_io_result = self.op_stack.push(lhs * rhs); - - let underflow_io = vec![underflow_io_lhs, underflow_io_rhs, underflow_io_result]; - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(underflow_io); + let lhs = self.op_stack.pop()?; + let rhs = self.op_stack.pop()?; + self.op_stack.push(lhs * rhs); self.instruction_pointer += 1; - Ok(op_stack_calls) + Ok(vec![]) } fn invert(&mut self) -> Result> { - let (top_of_stack, _) = self.op_stack.pop()?; + let top_of_stack = self.op_stack.pop()?; if top_of_stack.is_zero() { bail!(InverseOfZero); } - let _ = self.op_stack.push(top_of_stack.inverse()); + self.op_stack.push(top_of_stack.inverse()); self.instruction_pointer += 1; Ok(vec![]) } fn eq(&mut self) -> Result> { - let (lhs, underflow_io_lhs) = self.op_stack.pop()?; - let (rhs, underflow_io_rhs) = self.op_stack.pop()?; + let lhs = self.op_stack.pop()?; + let rhs = self.op_stack.pop()?; let eq: u32 = (lhs == rhs).into(); - let underflow_io_eq = self.op_stack.push(eq.into()); - - let underflow_io = vec![underflow_io_lhs, underflow_io_rhs, underflow_io_eq]; - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(underflow_io); + self.op_stack.push(eq.into()); self.instruction_pointer += 1; - Ok(op_stack_calls) + Ok(vec![]) } fn split(&mut self) -> Result> { - let (top_of_stack, underflow_io_top) = self.op_stack.pop()?; + let top_of_stack = self.op_stack.pop()?; let lo = BFieldElement::new(top_of_stack.value() & 0xffff_ffff); let hi = BFieldElement::new(top_of_stack.value() >> 32); - let underflow_io_hi = self.op_stack.push(hi); - let underflow_io_lo = self.op_stack.push(lo); - - let underflow_io = vec![underflow_io_top, underflow_io_hi, underflow_io_lo]; - let mut co_processor_calls = self.underflow_io_sequence_to_co_processor_calls(underflow_io); + self.op_stack.push(hi); + self.op_stack.push(lo); let u32_table_entry = U32TableEntry::new_from_base_field_element(Split, lo, hi); - let u32_call = U32Call(u32_table_entry); - co_processor_calls.push(u32_call); + let co_processor_calls = vec![U32Call(u32_table_entry)]; self.instruction_pointer += 1; Ok(co_processor_calls) } fn lt(&mut self) -> Result> { - let (lhs, underflow_io_lhs) = self.op_stack.pop_u32()?; - let (rhs, underflow_io_rhs) = self.op_stack.pop_u32()?; + let lhs = self.op_stack.pop_u32()?; + let rhs = self.op_stack.pop_u32()?; let lt: u32 = (lhs < rhs).into(); - let underflow_io_result = self.op_stack.push(lt.into()); - - let underflow_io = vec![underflow_io_lhs, underflow_io_rhs, underflow_io_result]; - let mut co_processor_calls = self.underflow_io_sequence_to_co_processor_calls(underflow_io); + self.op_stack.push(lt.into()); let u32_table_entry = U32TableEntry::new(Lt, lhs, rhs); - let u32_call = U32Call(u32_table_entry); - co_processor_calls.push(u32_call); + let co_processor_calls = vec![U32Call(u32_table_entry)]; self.instruction_pointer += 1; Ok(co_processor_calls) } fn and(&mut self) -> Result> { - let (lhs, underflow_io_lhs) = self.op_stack.pop_u32()?; - let (rhs, underflow_io_rhs) = self.op_stack.pop_u32()?; + let lhs = self.op_stack.pop_u32()?; + let rhs = self.op_stack.pop_u32()?; let and = lhs & rhs; - let underflow_io_and = self.op_stack.push(and.into()); - - let underflow_io = vec![underflow_io_lhs, underflow_io_rhs, underflow_io_and]; - let mut co_processor_calls = self.underflow_io_sequence_to_co_processor_calls(underflow_io); + self.op_stack.push(and.into()); let u32_table_entry = U32TableEntry::new(And, lhs, rhs); - let u32_call = U32Call(u32_table_entry); - co_processor_calls.push(u32_call); + let co_processor_calls = vec![U32Call(u32_table_entry)]; self.instruction_pointer += 1; Ok(co_processor_calls) } fn xor(&mut self) -> Result> { - let (lhs, underflow_io_lhs) = self.op_stack.pop_u32()?; - let (rhs, underflow_io_rhs) = self.op_stack.pop_u32()?; + let lhs = self.op_stack.pop_u32()?; + let rhs = self.op_stack.pop_u32()?; let xor = lhs ^ rhs; - let underflow_io_xor = self.op_stack.push(xor.into()); - - let underflow_io = vec![underflow_io_lhs, underflow_io_rhs, underflow_io_xor]; - let mut co_processor_calls = self.underflow_io_sequence_to_co_processor_calls(underflow_io); + self.op_stack.push(xor.into()); // Triton VM uses the following equality to compute the results of both the `and` // and `xor` instruction using the u32 coprocessor's `and` capability: // a ^ b = a + b - 2 ยท (a & b) let u32_table_entry = U32TableEntry::new(And, lhs, rhs); - let u32_call = U32Call(u32_table_entry); - co_processor_calls.push(u32_call); + let co_processor_calls = vec![U32Call(u32_table_entry)]; self.instruction_pointer += 1; Ok(co_processor_calls) } fn log_2_floor(&mut self) -> Result> { - let (top_of_stack, underflow_io_top) = self.op_stack.pop_u32()?; + let top_of_stack = self.op_stack.pop_u32()?; if top_of_stack.is_zero() { bail!(LogarithmOfZero); } let log_2_floor = top_of_stack.ilog2(); - let underflow_io_result = self.op_stack.push(log_2_floor.into()); - - let underflow_io = vec![underflow_io_top, underflow_io_result]; - let mut co_processor_calls = self.underflow_io_sequence_to_co_processor_calls(underflow_io); + self.op_stack.push(log_2_floor.into()); let u32_table_entry = U32TableEntry::new(Log2Floor, top_of_stack, 0); - let u32_call = U32Call(u32_table_entry); - co_processor_calls.push(u32_call); + let co_processor_calls = vec![U32Call(u32_table_entry)]; self.instruction_pointer += 1; Ok(co_processor_calls) } fn pow(&mut self) -> Result> { - let (base, underflow_io_base) = self.op_stack.pop()?; - let (exponent, underflow_io_exp) = self.op_stack.pop_u32()?; + let base = self.op_stack.pop()?; + let exponent = self.op_stack.pop_u32()?; let base_pow_exponent = base.mod_pow(exponent.into()); - let underflow_io_result = self.op_stack.push(base_pow_exponent); - - let underflow_io = vec![underflow_io_base, underflow_io_exp, underflow_io_result]; - let mut co_processor_calls = self.underflow_io_sequence_to_co_processor_calls(underflow_io); + self.op_stack.push(base_pow_exponent); let u32_table_entry = U32TableEntry::new_from_base_field_element(Pow, base, exponent.into()); - let u32_call = U32Call(u32_table_entry); - co_processor_calls.push(u32_call); + let co_processor_calls = vec![U32Call(u32_table_entry)]; self.instruction_pointer += 1; Ok(co_processor_calls) } fn div_mod(&mut self) -> Result> { - let (numerator, _) = self.op_stack.pop_u32()?; - let (denominator, _) = self.op_stack.pop_u32()?; + let numerator = self.op_stack.pop_u32()?; + let denominator = self.op_stack.pop_u32()?; if denominator.is_zero() { bail!(DivisionByZero); } let quotient = numerator / denominator; let remainder = numerator % denominator; - let _ = self.op_stack.push(quotient.into()); - let _ = self.op_stack.push(remainder.into()); + self.op_stack.push(quotient.into()); + self.op_stack.push(remainder.into()); let remainder_is_less_than_denominator = U32TableEntry::new(Lt, remainder, denominator); let numerator_and_quotient_range_check = U32TableEntry::new(Split, numerator, quotient); @@ -714,9 +657,9 @@ impl<'pgm> VMState<'pgm> { } fn pop_count(&mut self) -> Result> { - let (top_of_stack, _) = self.op_stack.pop_u32()?; + let top_of_stack = self.op_stack.pop_u32()?; let pop_count = top_of_stack.count_ones(); - let _ = self.op_stack.push(pop_count.into()); + self.op_stack.push(pop_count.into()); let u32_table_entry = U32TableEntry::new(PopCount, top_of_stack, 0); let co_processor_calls = vec![U32Call(u32_table_entry)]; @@ -726,61 +669,57 @@ impl<'pgm> VMState<'pgm> { } fn xx_add(&mut self) -> Result> { - let (lhs, _) = self.op_stack.pop_extension_field_element()?; + let lhs = self.op_stack.pop_extension_field_element()?; let rhs = self.op_stack.peek_at_top_extension_field_element(); - let _ = self.op_stack.push_extension_field_element(lhs + rhs); + self.op_stack.push_extension_field_element(lhs + rhs); self.instruction_pointer += 1; Ok(vec![]) } fn xx_mul(&mut self) -> Result> { - let (lhs, _) = self.op_stack.pop_extension_field_element()?; + let lhs = self.op_stack.pop_extension_field_element()?; let rhs = self.op_stack.peek_at_top_extension_field_element(); - let _ = self.op_stack.push_extension_field_element(lhs * rhs); + self.op_stack.push_extension_field_element(lhs * rhs); self.instruction_pointer += 1; Ok(vec![]) } fn x_invert(&mut self) -> Result> { - let (top_of_stack, _) = self.op_stack.pop_extension_field_element()?; + let top_of_stack = self.op_stack.pop_extension_field_element()?; if top_of_stack.is_zero() { bail!(InverseOfZero); } let inverse = top_of_stack.inverse(); - let _ = self.op_stack.push_extension_field_element(inverse); + self.op_stack.push_extension_field_element(inverse); self.instruction_pointer += 1; Ok(vec![]) } fn xb_mul(&mut self) -> Result> { - let (lhs, underflow_io) = self.op_stack.pop()?; - let (rhs, _) = self.op_stack.pop_extension_field_element()?; - let _ = self.op_stack.push_extension_field_element(lhs.lift() * rhs); - - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(vec![underflow_io]); + let lhs = self.op_stack.pop()?; + let rhs = self.op_stack.pop_extension_field_element()?; + self.op_stack.push_extension_field_element(lhs.lift() * rhs); self.instruction_pointer += 1; - Ok(op_stack_calls) + Ok(vec![]) } fn write_io(&mut self) -> Result> { - let (top_of_stack, underflow_io) = self.op_stack.pop()?; + let top_of_stack = self.op_stack.pop()?; self.public_output.push(top_of_stack); - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(vec![underflow_io]); self.instruction_pointer += 1; - Ok(op_stack_calls) + Ok(vec![]) } fn read_io(&mut self) -> Result> { let read_element = self.public_input.pop_front().ok_or(anyhow!( "Instruction `read_io`: public input buffer is empty." ))?; - let underflow_io = self.op_stack.push(read_element); + self.op_stack.push(read_element); - let op_stack_calls = self.underflow_io_sequence_to_co_processor_calls(vec![underflow_io]); self.instruction_pointer += 1; - Ok(op_stack_calls) + Ok(vec![]) } pub fn to_processor_row(&self) -> Array1 {