use super::{ExecutionError, Host, Process, STACK_TOP_SIZE};
use crate::ZERO;
impl<H> Process<H>
where
H: Host,
{
pub(super) fn op_pad(&mut self) -> Result<(), ExecutionError> {
self.stack.set(0, ZERO);
self.stack.shift_right(0);
Ok(())
}
pub(super) fn op_drop(&mut self) -> Result<(), ExecutionError> {
self.stack.shift_left(1);
Ok(())
}
pub(super) fn op_dup(&mut self, n: usize) -> Result<(), ExecutionError> {
let value = self.stack.get(n);
self.stack.set(0, value);
self.stack.shift_right(0);
Ok(())
}
pub(super) fn op_swap(&mut self) -> Result<(), ExecutionError> {
let a = self.stack.get(0);
let b = self.stack.get(1);
self.stack.set(0, b);
self.stack.set(1, a);
self.stack.copy_state(2);
Ok(())
}
pub(super) fn op_swapw(&mut self) -> Result<(), ExecutionError> {
let a0 = self.stack.get(0);
let a1 = self.stack.get(1);
let a2 = self.stack.get(2);
let a3 = self.stack.get(3);
let b0 = self.stack.get(4);
let b1 = self.stack.get(5);
let b2 = self.stack.get(6);
let b3 = self.stack.get(7);
self.stack.set(0, b0);
self.stack.set(1, b1);
self.stack.set(2, b2);
self.stack.set(3, b3);
self.stack.set(4, a0);
self.stack.set(5, a1);
self.stack.set(6, a2);
self.stack.set(7, a3);
self.stack.copy_state(8);
Ok(())
}
pub(super) fn op_swapw2(&mut self) -> Result<(), ExecutionError> {
let a0 = self.stack.get(0);
let a1 = self.stack.get(1);
let a2 = self.stack.get(2);
let a3 = self.stack.get(3);
let b0 = self.stack.get(4);
let b1 = self.stack.get(5);
let b2 = self.stack.get(6);
let b3 = self.stack.get(7);
let c0 = self.stack.get(8);
let c1 = self.stack.get(9);
let c2 = self.stack.get(10);
let c3 = self.stack.get(11);
self.stack.set(0, c0);
self.stack.set(1, c1);
self.stack.set(2, c2);
self.stack.set(3, c3);
self.stack.set(4, b0);
self.stack.set(5, b1);
self.stack.set(6, b2);
self.stack.set(7, b3);
self.stack.set(8, a0);
self.stack.set(9, a1);
self.stack.set(10, a2);
self.stack.set(11, a3);
self.stack.copy_state(12);
Ok(())
}
pub(super) fn op_swapw3(&mut self) -> Result<(), ExecutionError> {
let a0 = self.stack.get(0);
let a1 = self.stack.get(1);
let a2 = self.stack.get(2);
let a3 = self.stack.get(3);
let b0 = self.stack.get(4);
let b1 = self.stack.get(5);
let b2 = self.stack.get(6);
let b3 = self.stack.get(7);
let c0 = self.stack.get(8);
let c1 = self.stack.get(9);
let c2 = self.stack.get(10);
let c3 = self.stack.get(11);
let d0 = self.stack.get(12);
let d1 = self.stack.get(13);
let d2 = self.stack.get(14);
let d3 = self.stack.get(15);
self.stack.set(0, d0);
self.stack.set(1, d1);
self.stack.set(2, d2);
self.stack.set(3, d3);
self.stack.set(4, b0);
self.stack.set(5, b1);
self.stack.set(6, b2);
self.stack.set(7, b3);
self.stack.set(8, c0);
self.stack.set(9, c1);
self.stack.set(10, c2);
self.stack.set(11, c3);
self.stack.set(12, a0);
self.stack.set(13, a1);
self.stack.set(14, a2);
self.stack.set(15, a3);
self.stack.copy_state(16);
Ok(())
}
pub(super) fn op_swapdw(&mut self) -> Result<(), ExecutionError> {
let a0 = self.stack.get(0);
let a1 = self.stack.get(1);
let a2 = self.stack.get(2);
let a3 = self.stack.get(3);
let b0 = self.stack.get(4);
let b1 = self.stack.get(5);
let b2 = self.stack.get(6);
let b3 = self.stack.get(7);
let c0 = self.stack.get(8);
let c1 = self.stack.get(9);
let c2 = self.stack.get(10);
let c3 = self.stack.get(11);
let d0 = self.stack.get(12);
let d1 = self.stack.get(13);
let d2 = self.stack.get(14);
let d3 = self.stack.get(15);
self.stack.set(0, c0);
self.stack.set(1, c1);
self.stack.set(2, c2);
self.stack.set(3, c3);
self.stack.set(4, d0);
self.stack.set(5, d1);
self.stack.set(6, d2);
self.stack.set(7, d3);
self.stack.set(8, a0);
self.stack.set(9, a1);
self.stack.set(10, a2);
self.stack.set(11, a3);
self.stack.set(12, b0);
self.stack.set(13, b1);
self.stack.set(14, b2);
self.stack.set(15, b3);
self.stack.copy_state(16);
Ok(())
}
pub(super) fn op_movup(&mut self, n: usize) -> Result<(), ExecutionError> {
debug_assert!(n < STACK_TOP_SIZE - 1, "n too large");
let value = self.stack.get(n);
self.stack.set(0, value);
for i in 0..n {
let value = self.stack.get(i);
self.stack.set(i + 1, value);
}
self.stack.copy_state(n + 1);
Ok(())
}
pub(super) fn op_movdn(&mut self, n: usize) -> Result<(), ExecutionError> {
debug_assert!(n < STACK_TOP_SIZE - 1, "n too large");
let value = self.stack.get(0);
self.stack.set(n, value);
for i in 0..n {
let value = self.stack.get(i + 1);
self.stack.set(i, value);
}
self.stack.copy_state(n + 1);
Ok(())
}
pub(super) fn op_cswap(&mut self) -> Result<(), ExecutionError> {
let c = self.stack.get(0);
let b = self.stack.get(1);
let a = self.stack.get(2);
match c.as_int() {
0 => {
self.stack.set(0, b);
self.stack.set(1, a);
}
1 => {
self.stack.set(0, a);
self.stack.set(1, b);
}
_ => return Err(ExecutionError::NotBinaryValue(c)),
}
self.stack.shift_left(3);
Ok(())
}
pub(super) fn op_cswapw(&mut self) -> Result<(), ExecutionError> {
let c = self.stack.get(0);
let b0 = self.stack.get(1);
let b1 = self.stack.get(2);
let b2 = self.stack.get(3);
let b3 = self.stack.get(4);
let a0 = self.stack.get(5);
let a1 = self.stack.get(6);
let a2 = self.stack.get(7);
let a3 = self.stack.get(8);
match c.as_int() {
0 => {
self.stack.set(0, b0);
self.stack.set(1, b1);
self.stack.set(2, b2);
self.stack.set(3, b3);
self.stack.set(4, a0);
self.stack.set(5, a1);
self.stack.set(6, a2);
self.stack.set(7, a3);
}
1 => {
self.stack.set(0, a0);
self.stack.set(1, a1);
self.stack.set(2, a2);
self.stack.set(3, a3);
self.stack.set(4, b0);
self.stack.set(5, b1);
self.stack.set(6, b2);
self.stack.set(7, b3);
}
_ => return Err(ExecutionError::NotBinaryValue(c)),
}
self.stack.shift_left(9);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::{
super::{Operation, Process},
STACK_TOP_SIZE,
};
use crate::{Felt, StackInputs, ONE, ZERO};
#[test]
fn op_pad() {
let stack = StackInputs::default();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::Push(ONE)).unwrap();
let expected = build_expected(&[1]);
assert_eq!(expected, process.stack.trace_state());
process.execute_op(Operation::Pad).unwrap();
let expected = build_expected(&[0, 1]);
assert_eq!(STACK_TOP_SIZE + 2, process.stack.depth());
assert_eq!(3, process.stack.current_clk());
assert_eq!(expected, process.stack.trace_state());
process.execute_op(Operation::Pad).unwrap();
let expected = build_expected(&[0, 0, 1]);
assert_eq!(STACK_TOP_SIZE + 3, process.stack.depth());
assert_eq!(4, process.stack.current_clk());
assert_eq!(expected, process.stack.trace_state());
}
#[test]
fn op_drop() {
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();
process.execute_op(Operation::Drop).unwrap();
let expected = build_expected(&[1]);
assert_eq!(expected, process.stack.trace_state());
assert_eq!(STACK_TOP_SIZE + 1, process.stack.depth());
process.execute_op(Operation::Drop).unwrap();
let expected = build_expected(&[]);
assert_eq!(expected, process.stack.trace_state());
assert_eq!(STACK_TOP_SIZE, process.stack.depth());
assert!(process.execute_op(Operation::Drop).is_ok());
}
#[test]
fn op_dup() {
let stack = StackInputs::default();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::Push(ONE)).unwrap();
let expected = build_expected(&[1]);
assert_eq!(expected, process.stack.trace_state());
process.execute_op(Operation::Dup0).unwrap();
let expected = build_expected(&[1, 1]);
assert_eq!(expected, process.stack.trace_state());
assert!(process.execute_op(Operation::Dup2).is_ok());
process.execute_op(Operation::Drop).unwrap();
let mut expected = [ONE; 16];
for i in 2..17 {
process.execute_op(Operation::Push(Felt::new(i))).unwrap();
expected[16 - i as usize] = Felt::new(i);
}
assert_eq!(expected, process.stack.trace_state());
process.execute_op(Operation::Dup15).unwrap();
assert_eq!(ONE, process.stack.trace_state()[0]);
assert_eq!(&expected[..15], &process.stack.trace_state()[1..]);
process.execute_op(Operation::Dup7).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..]);
process.execute_op(Operation::Drop).unwrap();
process.execute_op(Operation::Drop).unwrap();
process.execute_op(Operation::Drop).unwrap();
process.execute_op(Operation::Drop).unwrap();
assert_eq!(STACK_TOP_SIZE + 15, process.stack.depth());
assert_eq!(&expected[2..], &process.stack.trace_state()[..14]);
assert_eq!(ONE, process.stack.trace_state()[14]);
assert_eq!(ZERO, process.stack.trace_state()[15]);
}
#[test]
fn op_swap() {
let stack = StackInputs::try_from_ints([1, 2, 3]).unwrap();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::Swap).unwrap();
let expected = build_expected(&[2, 3, 1]);
assert_eq!(expected, process.stack.trace_state());
let stack = StackInputs::default();
let mut process = Process::new_dummy(stack);
assert!(process.execute_op(Operation::Swap).is_ok());
}
#[test]
fn op_swapw() {
let stack = StackInputs::try_from_ints([1, 2, 3, 4, 5, 6, 7, 8, 9]).unwrap();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::SwapW).unwrap();
let expected = build_expected(&[5, 4, 3, 2, 9, 8, 7, 6, 1]);
assert_eq!(expected, process.stack.trace_state());
let stack = StackInputs::default();
let mut process = Process::new_dummy(stack);
assert!(process.execute_op(Operation::SwapW).is_ok());
}
#[test]
fn op_swapw2() {
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);
process.execute_op(Operation::SwapW2).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());
let stack = StackInputs::default();
let mut process = Process::new_dummy(stack);
assert!(process.execute_op(Operation::SwapW2).is_ok());
}
#[test]
fn op_swapw3() {
let stack =
StackInputs::try_from_ints([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17])
.unwrap();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::SwapW3).unwrap();
let expected = build_expected(&[5, 4, 3, 2, 13, 12, 11, 10, 9, 8, 7, 6, 17, 16, 15, 14]);
assert_eq!(expected, process.stack.trace_state());
process.execute_op(Operation::Drop).unwrap();
let expected = build_expected(&[4, 3, 2, 13, 12, 11, 10, 9, 8, 7, 6, 17, 16, 15, 14, 1]);
assert_eq!(expected, process.stack.trace_state());
let mut process = Process::new_dummy_with_empty_stack();
assert!(process.execute_op(Operation::SwapW3).is_ok());
}
#[test]
fn op_movup() {
let stack =
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);
process.execute_op(Operation::MovUp2).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());
process.execute_op(Operation::MovUp3).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());
process.execute_op(Operation::MovUp7).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());
process.execute_op(Operation::MovUp8).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());
let mut process = Process::new_dummy_with_empty_stack();
assert!(process.execute_op(Operation::MovUp2).is_ok());
}
#[test]
fn op_movdn() {
let stack =
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);
process.execute_op(Operation::MovDn2).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());
process.execute_op(Operation::MovDn3).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());
process.execute_op(Operation::MovDn7).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());
process.execute_op(Operation::MovDn8).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());
let mut process = Process::new_dummy_with_empty_stack();
assert!(process.execute_op(Operation::MovDn2).is_ok());
}
#[test]
fn op_cswap() {
let stack = StackInputs::try_from_ints([4, 3, 2, 1, 0]).unwrap();
let mut process = Process::new_dummy(stack);
process.execute_op(Operation::CSwap).unwrap();
let expected = build_expected(&[1, 2, 3, 4]);
assert_eq!(expected, process.stack.trace_state());
process.execute_op(Operation::CSwap).unwrap();
let expected = build_expected(&[3, 2, 4]);
assert_eq!(expected, process.stack.trace_state());
assert!(process.execute_op(Operation::CSwap).is_err());
let mut process = Process::new_dummy_with_empty_stack();
assert!(process.execute_op(Operation::CSwap).is_ok());
}
#[test]
fn op_cswapw() {
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);
process.execute_op(Operation::CSwapW).unwrap();
let expected = build_expected(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
assert_eq!(expected, process.stack.trace_state());
process.execute_op(Operation::CSwapW).unwrap();
let expected = build_expected(&[6, 7, 8, 9, 2, 3, 4, 5, 10, 11]);
assert_eq!(expected, process.stack.trace_state());
assert!(process.execute_op(Operation::CSwapW).is_err());
let mut process = Process::new_dummy_with_empty_stack();
assert!(process.execute_op(Operation::CSwapW).is_ok());
}
fn build_expected(values: &[u64]) -> [Felt; 16] {
let mut expected = [ZERO; 16];
for (&value, result) in values.iter().zip(expected.iter_mut()) {
*result = Felt::new(value);
}
expected
}
}