use super::{utils::assert_binary, ExecutionError, Felt, FieldElement, Host, Process};
use vm_core::{Operation, ONE, ZERO};
impl<H> Process<H>
where
H: Host,
{
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) -> Result<(), ExecutionError> {
let a = self.stack.get(0);
if a == ZERO {
return Err(ExecutionError::DivideByZero(self.system.clk()));
}
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) -> Result<(), ExecutionError> {
let b = assert_binary(self.stack.get(0))?;
let a = assert_binary(self.stack.get(1))?;
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) -> Result<(), ExecutionError> {
let b = assert_binary(self.stack.get(0))?;
let a = assert_binary(self.stack.get(1))?;
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) -> Result<(), ExecutionError> {
let a = assert_binary(self.stack.get(0))?;
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 mut exp = self.stack.get(1);
let mut acc = self.stack.get(2);
let mut b = self.stack.get(3);
let bit = b.as_int() & 1;
let value = Felt::new((exp.as_int() - 1) * bit + 1);
acc *= value;
b = Felt::new(b.as_int() >> 1);
exp *= exp;
self.decoder.set_user_op_helpers(Operation::Expacc, &[value]);
self.stack.set(0, Felt::new(bit));
self.stack.set(1, exp);
self.stack.set(2, acc);
self.stack.set(3, b);
self.stack.copy_state(4);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::{
super::{Felt, FieldElement, Operation, STACK_TOP_SIZE},
Process,
};
use crate::{AdviceInputs, StackInputs};
use test_utils::rand::rand_value;
use vm_core::{ONE, ZERO};
#[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);
process.execute_op(Operation::Add).unwrap();
let expected = build_expected(&[a + b, c]);
assert_eq!(STACK_TOP_SIZE, 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).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);
process.execute_op(Operation::Neg).unwrap();
let expected = build_expected(&[-a, b, c]);
assert_eq!(expected, process.stack.trace_state());
assert_eq!(STACK_TOP_SIZE, 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);
process.execute_op(Operation::Mul).unwrap();
let expected = build_expected(&[a * b, c]);
assert_eq!(STACK_TOP_SIZE, 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).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);
if b != ZERO {
process.execute_op(Operation::Inv).unwrap();
let expected = build_expected(&[a.inv(), b, c]);
assert_eq!(STACK_TOP_SIZE, process.stack.depth());
assert_eq!(2, process.stack.current_clk());
assert_eq!(expected, process.stack.trace_state());
}
process.execute_op(Operation::Pad).unwrap();
assert!(process.execute_op(Operation::Inv).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);
process.execute_op(Operation::Incr).unwrap();
let expected = build_expected(&[a + ONE, b, c]);
assert_eq!(STACK_TOP_SIZE, process.stack.depth());
assert_eq!(2, process.stack.current_clk());
assert_eq!(expected, process.stack.trace_state());
}
#[test]
fn op_and() {
let stack = StackInputs::try_from_ints([2, 0, 0]).unwrap();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::And).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).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).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).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).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).is_err());
let mut process = Process::new_dummy_with_empty_stack();
assert!(process.execute_op(Operation::And).is_ok());
}
#[test]
fn op_or() {
let stack = StackInputs::try_from_ints([2, 0, 0]).unwrap();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::Or).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).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).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).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).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).is_err());
let mut process = Process::new_dummy_with_empty_stack();
assert!(process.execute_op(Operation::Or).is_ok());
}
#[test]
fn op_not() {
let stack = StackInputs::try_from_ints([2, 0]).unwrap();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::Not).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).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).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 =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
process.execute_op(Operation::Eq).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 =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
process.execute_op(Operation::Eq).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 =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
assert!(process.execute_op(Operation::Eq).is_ok());
}
#[test]
fn op_eqz() {
let advice_inputs = AdviceInputs::default();
let stack_inputs = StackInputs::try_from_ints([3, 0]).unwrap();
let mut process =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
process.execute_op(Operation::Eqz).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 =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
process.execute_op(Operation::Eqz).unwrap();
let expected = build_expected(&[ZERO, Felt::new(3)]);
assert_eq!(expected, process.stack.trace_state());
}
#[test]
fn op_expacc() {
let a = 0;
let b = 32;
let c = 4;
let advice_inputs = AdviceInputs::default();
let stack_inputs = StackInputs::try_from_ints([a, b, c, 0]).unwrap();
let mut process =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
process.execute_op(Operation::Expacc).unwrap();
let expected = build_expected(&[ZERO, Felt::new(16), Felt::new(32), Felt::new(a >> 1)]);
assert_eq!(expected, process.stack.trace_state());
let a = 3;
let b = 1;
let c = 16;
let advice_inputs = AdviceInputs::default();
let stack_inputs = StackInputs::try_from_ints([a, b, c, 0]).unwrap();
let mut process =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
process.execute_op(Operation::Expacc).unwrap();
let expected = build_expected(&[ONE, Felt::new(256), Felt::new(16), Felt::new(a >> 1)]);
assert_eq!(expected, process.stack.trace_state());
let a = 17;
let b = 5;
let c = 625;
let advice_inputs = AdviceInputs::default();
let stack_inputs = StackInputs::try_from_ints([a, b, c, 0]).unwrap();
let mut process =
Process::new_dummy_with_inputs_and_decoder_helpers(stack_inputs, advice_inputs);
process.execute_op(Operation::Expacc).unwrap();
let expected =
build_expected(&[ONE, Felt::new(390625), Felt::new(3125), Felt::new(a >> 1)]);
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
}
}