#include "quorum-internal.h"

bool
_sigsum_quorum_eval (const struct sigsum_quorum *quorum,
		     size_t num_witnesses, const bool *witnesses,
		     uint8_t *stack)
{
  size_t stack_size = 0;
  size_t prefix = 0;

  for (size_t i = 0; i < quorum->bytecode_size; i++)
    {
      uint8_t instr = quorum->bytecode[i];
      size_t imm = quorum_bytecode_imm (prefix, instr);
      prefix = 0;

      switch (quorum_bytecode_op (instr))
	{
	case BYTECODE_OP_MISC:
	  /* In this case, imm is assigned the low instruction bits,
	     or an invalid larger value if prefix was non-zero. */
	  switch (imm)
	    {
	    case BYTECODE_INSTR_ADD:
	      if (stack_size < 2)
		return false;

	      uint8_t top = stack[--stack_size];
	      stack[stack_size - 1] += top;
	      if (stack[stack_size - 1] < top)
		/* Overflow */
		return false;
	      break;

	    case BYTECODE_INSTR_TRUE:
	      if (stack_size >= quorum->stack_alloc)
		return false;

	      stack[stack_size++] = 1;
	      break;

	    default:
	      return false;
	    }
	  break;

	case BYTECODE_OP_X_P:
	  if (stack_size >= quorum->stack_alloc)
	    return false;

	  if (imm >= num_witnesses)
	    return false;
	  stack[stack_size++] = witnesses[imm];
	  break;

	case BYTECODE_OP_GE_K:
	  if (!stack_size)
	    return false;

	  stack[stack_size - 1] = stack[stack_size - 1] >= imm;
	  break;

	case BYTECODE_OP_PREFIX:
	  if (!imm)
	    /* Redundant zero prefix not allowed. */
	    return false;
	  if (imm > (((size_t) -1) >> 6))
	    /* Prefix would overflow when applied. */
	    return false;

	  prefix = imm;
	  break;
	}
    }
  return prefix == 0 && stack_size == 1 && *stack == 1;
}
