use miden_core::{ONE, Operation, ZERO};
use super::{ExecutionError, Felt, FieldElement, Process, utils::assert_binary};
use crate::ErrorContext;
impl Process {
pub(super) fn op_add(&mut self) -> Result<(), ExecutionError> {
let b = self.stack.get(0);
let a = self.stack.get(1);
self.stack.set(0, a + b);
self.stack.shift_left(2);
Ok(())
}
pub(super) fn op_neg(&mut self) -> Result<(), ExecutionError> {
let a = self.stack.get(0);
self.stack.set(0, -a);
self.stack.copy_state(1);
Ok(())
}
pub(super) fn op_mul(&mut self) -> Result<(), ExecutionError> {
let b = self.stack.get(0);
let a = self.stack.get(1);
self.stack.set(0, a * b);
self.stack.shift_left(2);
Ok(())
}
pub(super) fn op_inv(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
let a = self.stack.get(0);
if a == ZERO {
return Err(ExecutionError::divide_by_zero(self.system.clk(), err_ctx));
}
self.stack.set(0, a.inv());
self.stack.copy_state(1);
Ok(())
}
pub(super) fn op_incr(&mut self) -> Result<(), ExecutionError> {
let a = self.stack.get(0);
self.stack.set(0, a + ONE);
self.stack.copy_state(1);
Ok(())
}
pub(super) fn op_and(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
let b = assert_binary(self.stack.get(0), err_ctx)?;
let a = assert_binary(self.stack.get(1), err_ctx)?;
if a == ONE && b == ONE {
self.stack.set(0, ONE);
} else {
self.stack.set(0, ZERO);
}
self.stack.shift_left(2);
Ok(())
}
pub(super) fn op_or(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
let b = assert_binary(self.stack.get(0), err_ctx)?;
let a = assert_binary(self.stack.get(1), err_ctx)?;
if a == ONE || b == ONE {
self.stack.set(0, ONE);
} else {
self.stack.set(0, ZERO);
}
self.stack.shift_left(2);
Ok(())
}
pub(super) fn op_not(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
let a = assert_binary(self.stack.get(0), err_ctx)?;
self.stack.set(0, ONE - a);
self.stack.copy_state(1);
Ok(())
}
pub(super) fn op_eq(&mut self) -> Result<(), ExecutionError> {
let b = self.stack.get(0);
let a = self.stack.get(1);
let mut h0 = ZERO;
if a == b {
self.stack.set(0, ONE);
} else {
self.stack.set(0, ZERO);
h0 = (b - a).inv();
}
self.decoder.set_user_op_helpers(Operation::Eq, &[h0]);
self.stack.shift_left(2);
Ok(())
}
pub(super) fn op_eqz(&mut self) -> Result<(), ExecutionError> {
let a = self.stack.get(0);
let mut h0 = ZERO;
if a == ZERO {
self.stack.set(0, ONE);
} else {
h0 = a.inv();
self.stack.set(0, ZERO);
}
self.decoder.set_user_op_helpers(Operation::Eq, &[h0]);
self.stack.copy_state(1);
Ok(())
}
pub(super) fn op_expacc(&mut self) -> Result<(), ExecutionError> {
let old_base_acc = self.stack.get(1);
let old_result_acc = self.stack.get(2);
let old_exp = self.stack.get(3);
let new_exp = Felt::new(old_exp.as_int() >> 1);
let exp_lsb = old_exp.as_int() & 1;
let result_acc_update = if exp_lsb == 1 { old_base_acc } else { ONE };
let new_result_acc = old_result_acc * result_acc_update;
let new_base_acc = old_base_acc * old_base_acc;
self.stack.set(0, Felt::new(exp_lsb));
self.stack.set(1, new_base_acc);
self.stack.set(2, new_result_acc);
self.stack.set(3, new_exp);
self.stack.copy_state(4);
self.decoder.set_user_op_helpers(Operation::Expacc, &[result_acc_update]);
Ok(())
}
}
#[cfg(test)]
mod tests {
use miden_core::{ONE, ZERO, mast::MastForest};
use miden_utils_testing::rand::rand_value;
use super::{
super::{Felt, FieldElement, MIN_STACK_DEPTH, Operation},
Process,
};
use crate::{AdviceInputs, DefaultHost, StackInputs};
#[test]
fn op_add() {
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();
let program = &MastForest::default();
process.execute_op(Operation::Add, program, &mut host).unwrap();
let expected = build_expected(&[a + b, c]);
assert_eq!(MIN_STACK_DEPTH, process.stack.depth());
assert_eq!(2, process.stack.current_clk());
assert_eq!(expected, process.stack.trace_state());
let mut process = Process::new_dummy_with_empty_stack();
assert!(process.execute_op(Operation::Add, program, &mut host).is_ok());
}
#[test]
fn op_neg() {
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();
let program = &MastForest::default();
process.execute_op(Operation::Neg, program, &mut host).unwrap();
let expected = build_expected(&[-a, b, c]);
assert_eq!(expected, process.stack.trace_state());
assert_eq!(MIN_STACK_DEPTH, process.stack.depth());
assert_eq!(2, process.stack.current_clk());
}
#[test]
fn op_mul() {
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();
let program = &MastForest::default();
process.execute_op(Operation::Mul, program, &mut host).unwrap();
let expected = build_expected(&[a * b, c]);
assert_eq!(MIN_STACK_DEPTH, process.stack.depth());
assert_eq!(2, process.stack.current_clk());
assert_eq!(expected, process.stack.trace_state());
let mut process = Process::new_dummy_with_empty_stack();
assert!(process.execute_op(Operation::Mul, program, &mut host).is_ok());
}
#[test]
fn op_inv() {
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();
let program = &MastForest::default();
if b != ZERO {
process.execute_op(Operation::Inv, program, &mut host).unwrap();
let expected = build_expected(&[a.inv(), b, c]);
assert_eq!(MIN_STACK_DEPTH, process.stack.depth());
assert_eq!(2, process.stack.current_clk());
assert_eq!(expected, process.stack.trace_state());
}
process.execute_op(Operation::Pad, program, &mut host).unwrap();
assert!(process.execute_op(Operation::Inv, program, &mut host).is_err());
}
#[test]
fn op_incr() {
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();
let program = &MastForest::default();
process.execute_op(Operation::Incr, program, &mut host).unwrap();
let expected = build_expected(&[a + ONE, b, c]);
assert_eq!(MIN_STACK_DEPTH, process.stack.depth());
assert_eq!(2, process.stack.current_clk());
assert_eq!(expected, process.stack.trace_state());
}
#[test]
fn op_and() {
let mut host = DefaultHost::default();
let stack = StackInputs::try_from_ints([2, 0, 0]).unwrap();
let mut process = Process::new_dummy(stack);
let program = &MastForest::default();
process.execute_op(Operation::And, program, &mut host).unwrap();
let expected = build_expected(&[ZERO, Felt::new(2)]);
assert_eq!(expected, process.stack.trace_state());
let stack = StackInputs::try_from_ints([2, 0, 1]).unwrap();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::And, program, &mut host).unwrap();
let expected = build_expected(&[ZERO, Felt::new(2)]);
assert_eq!(expected, process.stack.trace_state());
let stack = StackInputs::try_from_ints([2, 1, 0]).unwrap();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::And, program, &mut host).unwrap();
let expected = build_expected(&[ZERO, Felt::new(2)]);
assert_eq!(expected, process.stack.trace_state());
let stack = StackInputs::try_from_ints([2, 1, 1]).unwrap();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::And, program, &mut host).unwrap();
let expected = build_expected(&[ONE, Felt::new(2)]);
assert_eq!(expected, process.stack.trace_state());
let stack = StackInputs::try_from_ints([2, 1, 2]).unwrap();
let mut process = Process::new_dummy(stack);
assert!(process.execute_op(Operation::And, program, &mut host).is_err());
let stack = StackInputs::try_from_ints([2, 2, 1]).unwrap();
let mut process = Process::new_dummy(stack);
assert!(process.execute_op(Operation::And, program, &mut host).is_err());
let mut process = Process::new_dummy_with_empty_stack();
assert!(process.execute_op(Operation::And, program, &mut host).is_ok());
}
#[test]
fn op_or() {
let mut host = DefaultHost::default();
let stack = StackInputs::try_from_ints([2, 0, 0]).unwrap();
let mut process = Process::new_dummy(stack);
let program = &MastForest::default();
process.execute_op(Operation::Or, program, &mut host).unwrap();
let expected = build_expected(&[ZERO, Felt::new(2)]);
assert_eq!(expected, process.stack.trace_state());
let stack = StackInputs::try_from_ints([2, 0, 1]).unwrap();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::Or, program, &mut host).unwrap();
let expected = build_expected(&[ONE, Felt::new(2)]);
assert_eq!(expected, process.stack.trace_state());
let stack = StackInputs::try_from_ints([2, 1, 0]).unwrap();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::Or, program, &mut host).unwrap();
let expected = build_expected(&[ONE, Felt::new(2)]);
assert_eq!(expected, process.stack.trace_state());
let stack = StackInputs::try_from_ints([2, 1, 1]).unwrap();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::Or, program, &mut host).unwrap();
let expected = build_expected(&[ONE, Felt::new(2)]);
assert_eq!(expected, process.stack.trace_state());
let stack = StackInputs::try_from_ints([2, 1, 2]).unwrap();
let mut process = Process::new_dummy(stack);
assert!(process.execute_op(Operation::Or, program, &mut host).is_err());
let stack = StackInputs::try_from_ints([2, 2, 1]).unwrap();
let mut process = Process::new_dummy(stack);
assert!(process.execute_op(Operation::Or, program, &mut host).is_err());
let mut process = Process::new_dummy_with_empty_stack();
assert!(process.execute_op(Operation::Or, program, &mut host).is_ok());
}
#[test]
fn op_not() {
let mut host = DefaultHost::default();
let stack = StackInputs::try_from_ints([2, 0]).unwrap();
let mut process = Process::new_dummy(stack);
let program = &MastForest::default();
process.execute_op(Operation::Not, program, &mut host).unwrap();
let expected = build_expected(&[ONE, Felt::new(2)]);
assert_eq!(expected, process.stack.trace_state());
let stack = StackInputs::try_from_ints([2, 1]).unwrap();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::Not, program, &mut host).unwrap();
let expected = build_expected(&[ZERO, Felt::new(2)]);
assert_eq!(expected, process.stack.trace_state());
let stack = StackInputs::try_from_ints([2, 2]).unwrap();
let mut process = Process::new_dummy(stack);
assert!(process.execute_op(Operation::Not, program, &mut host).is_err());
}
#[test]
fn op_eq() {
let advice_inputs = AdviceInputs::default();
let stack_inputs = StackInputs::try_from_ints([3, 7, 7]).unwrap();
let (mut process, mut host) =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
let program = &MastForest::default();
process.execute_op(Operation::Eq, program, &mut host).unwrap();
let expected = build_expected(&[ONE, Felt::new(3)]);
assert_eq!(expected, process.stack.trace_state());
let advice_inputs = AdviceInputs::default();
let stack_inputs = StackInputs::try_from_ints([3, 5, 7]).unwrap();
let (mut process, mut host) =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
process.execute_op(Operation::Eq, program, &mut host).unwrap();
let expected = build_expected(&[ZERO, Felt::new(3)]);
assert_eq!(expected, process.stack.trace_state());
let advice_inputs = AdviceInputs::default();
let stack_inputs = StackInputs::default();
let (mut process, mut host) =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
assert!(process.execute_op(Operation::Eq, program, &mut host).is_ok());
}
#[test]
fn op_eqz() {
let advice_inputs = AdviceInputs::default();
let stack_inputs = StackInputs::try_from_ints([3, 0]).unwrap();
let (mut process, mut host) =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
let program = &MastForest::default();
process.execute_op(Operation::Eqz, program, &mut host).unwrap();
let expected = build_expected(&[ONE, Felt::new(3)]);
assert_eq!(expected, process.stack.trace_state());
let advice_inputs = AdviceInputs::default();
let stack_inputs = StackInputs::try_from_ints([3, 4]).unwrap();
let (mut process, mut host) =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
process.execute_op(Operation::Eqz, program, &mut host).unwrap();
let expected = build_expected(&[ZERO, Felt::new(3)]);
assert_eq!(expected, process.stack.trace_state());
}
#[test]
fn op_expacc() {
let old_exp = 8;
let old_acc = 1;
let old_base = 0;
let new_exp = Felt::new(4_u64);
let new_acc = Felt::new(1_u64);
let new_base = Felt::new(0_u64);
let advice_inputs = AdviceInputs::default();
let stack_inputs = StackInputs::try_from_ints([old_exp, old_acc, old_base, 0]).unwrap();
let (mut process, mut host) =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
let program = &MastForest::default();
process.execute_op(Operation::Expacc, program, &mut host).unwrap();
let expected = build_expected(&[ZERO, new_base, new_acc, new_exp]);
assert_eq!(expected, process.stack.trace_state());
let old_exp = 9;
let old_acc = 1;
let old_base = 0;
let new_exp = Felt::new(4_u64);
let new_acc = Felt::new(0_u64);
let new_base = Felt::new(0_u64);
let advice_inputs = AdviceInputs::default();
let stack_inputs = StackInputs::try_from_ints([old_exp, old_acc, old_base, 0]).unwrap();
let (mut process, mut host) =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
process.execute_op(Operation::Expacc, program, &mut host).unwrap();
let expected = build_expected(&[ONE, new_base, new_acc, new_exp]);
assert_eq!(expected, process.stack.trace_state());
let old_exp = 0;
let old_acc = 32;
let old_base = 4;
let new_exp = Felt::new(0_u64);
let new_acc = Felt::new(32_u64);
let new_base = Felt::new(16_u64);
let advice_inputs = AdviceInputs::default();
let stack_inputs = StackInputs::try_from_ints([old_exp, old_acc, old_base, 0]).unwrap();
let (mut process, mut host) =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
process.execute_op(Operation::Expacc, program, &mut host).unwrap();
let expected = build_expected(&[ZERO, new_base, new_acc, new_exp]);
assert_eq!(expected, process.stack.trace_state());
let old_exp = 3;
let old_acc = 1;
let old_base = 16;
let new_exp = Felt::new(1_u64);
let new_acc = Felt::new(16_u64);
let new_base = Felt::new(16_u64 * 16_u64);
let advice_inputs = AdviceInputs::default();
let stack_inputs = StackInputs::try_from_ints([old_exp, old_acc, old_base, 0]).unwrap();
let (mut process, mut host) =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
process.execute_op(Operation::Expacc, program, &mut host).unwrap();
let expected = build_expected(&[ONE, new_base, new_acc, new_exp]);
assert_eq!(expected, process.stack.trace_state());
let old_exp = 17;
let old_acc = 5;
let old_base = u32::MAX as u64 + 1_u64;
let new_exp = Felt::new(8_u64);
let new_acc = Felt::new(old_acc * old_base);
let new_base = Felt::new(old_base) * Felt::new(old_base);
let advice_inputs = AdviceInputs::default();
let stack_inputs = StackInputs::try_from_ints([old_exp, old_acc, old_base, 0]).unwrap();
let (mut process, mut host) =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
process.execute_op(Operation::Expacc, program, &mut host).unwrap();
let expected = build_expected(&[ONE, new_base, new_acc, new_exp]);
assert_eq!(expected, process.stack.trace_state());
}
fn get_rand_values() -> (Felt, Felt, Felt) {
let a = rand_value();
let b = rand_value();
let c = rand_value();
(Felt::new(a), Felt::new(b), Felt::new(c))
}
fn build_expected(values: &[Felt]) -> [Felt; 16] {
let mut expected = [ZERO; 16];
for (&value, result) in values.iter().zip(expected.iter_mut()) {
*result = value;
}
expected
}
}