Skip to content

Commit

Permalink
3791 - Add unit tests for bytecode parsing and execution
Browse files Browse the repository at this point in the history
  • Loading branch information
jeanmon committed Jan 25, 2024
1 parent aacc5b8 commit eb01dbd
Show file tree
Hide file tree
Showing 8 changed files with 347 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp"
#include "barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp"
#include <cstdint>

using Flavor = bb::honk::flavor::AvmMiniFlavor;
using FF = Flavor::FF;
Expand All @@ -12,6 +13,9 @@ namespace avm_trace {
// Number of rows
static const size_t AVM_TRACE_SIZE = 256;
enum class IntermRegister : uint32_t { IA = 0, IB = 1, IC = 2 };

// Keep following enum in sync with MAX_NEM_TAG below
enum class AvmMemoryTag : uint32_t { U0 = 0, U8 = 1, U16 = 2, U32 = 3, U64 = 4, U128 = 5, FF = 6 };
static const uint32_t MAX_MEM_TAG = 6;

} // namespace avm_trace
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,11 @@ std::vector<Instruction> Execution::parse(std::vector<uint8_t> const& bytecode)
auto in_tag_u8 = static_cast<uint8_t>(AvmMemoryTag::U0);

if (Bytecode::has_in_tag(opcode)) {
if (pos + AVM_IN_TAG_BYTE_LENGTH > length) {
throw std::runtime_error("Instruction tag missing at position " + std::to_string(pos));
}
in_tag_u8 = bytecode.at(pos);
if (in_tag_u8 == static_cast<uint8_t>(AvmMemoryTag::U0) || in_tag_u8 == 7) {
if (in_tag_u8 == static_cast<uint8_t>(AvmMemoryTag::U0) || in_tag_u8 > MAX_MEM_TAG) {
throw std::runtime_error("Instruction tag is invalid at position " + std::to_string(pos) +
" value: " + std::to_string(in_tag_u8));
}
Expand Down Expand Up @@ -109,8 +112,7 @@ std::vector<Instruction> Execution::parse(std::vector<uint8_t> const& bytecode)
}

if (pos + operands_size > length) {
throw std::runtime_error("Bytecode does not contain enough bytes for operands at position " +
std::to_string(pos));
throw std::runtime_error("Operand is missing at position " + std::to_string(pos));
}

if (opcode == OpCode::SET && in_tag == AvmMemoryTag::U8) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@ namespace avm_trace {
class Execution {
public:
Execution() = default;
static plonk::proof run_and_prove(std::vector<uint8_t> const& bytecode, std::vector<FF> const& calldata);

static size_t const AVM_OPERAND_BYTE_LENGTH = 4; // Keep in sync with TS code
static size_t const AVM_OPCODE_BYTE_LENGTH = 1; // Keep in sync with TS code
static size_t const AVM_IN_TAG_BYTE_LENGTH = 1; // Keep in sync with TS code

private:
AvmMiniTraceBuilder trace_builder{};
static std::vector<Instruction> parse(std::vector<uint8_t> const& bytecode);
static std::vector<Row> gen_trace(std::vector<Instruction> const& instructions, std::vector<FF> const& calldata);
static plonk::proof run_and_prove(std::vector<uint8_t> const& bytecode, std::vector<FF> const& calldata);
};

} // namespace avm_trace
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,11 @@ void AvmMiniTraceBuilder::call_data_copy(uint32_t cd_offset,
*/
std::vector<FF> AvmMiniTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_size)
{
if (ret_size == 0) {
halt();
return std::vector<FF>{};
}

// We parallelize loading memory operations in chunk of 3, i.e., 1 per intermediate register.
// The variable pos is an index pointing to the first storing operation (pertaining to intermediate
// register Ia) relative to ret_offset:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
#include "barretenberg/numeric/uint128/uint128.hpp"

using namespace numeric;
using namespace tests_avm;
namespace {
using namespace tests_avm;

void common_validate_arithmetic_op(Row const& main_row,
Row const& alu_row,
Expand Down Expand Up @@ -35,7 +35,7 @@ void common_validate_arithmetic_op(Row const& main_row,
// Check the instruction tag
EXPECT_EQ(main_row.avmMini_in_tag, FF(static_cast<uint32_t>(tag)));

// Check that intermediate rgiesters are correctly copied in Alu trace
// Check that intermediate registers are correctly copied in Alu trace
EXPECT_EQ(alu_row.aluChip_alu_ia, a);
EXPECT_EQ(alu_row.aluChip_alu_ib, b);
EXPECT_EQ(alu_row.aluChip_alu_ic, c);
Expand Down Expand Up @@ -184,7 +184,9 @@ std::vector<Row> gen_mutated_trace_mul(FF const& a, FF const& b, FF const& c_mut

} // anonymous namespace

namespace tests_avm {
using namespace avm_trace;

class AvmMiniArithmeticTests : public ::testing::Test {
public:
AvmMiniTraceBuilder trace_builder;
Expand Down Expand Up @@ -1675,4 +1677,6 @@ TEST_F(AvmMiniArithmeticNegativeTestsU128, multiplication)
FF{ uint256_t::from_uint128(c) },
AvmMemoryTag::U128);
EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "ALU_MULTIPLICATION_OUT_U128");
}
}

} // namespace tests_avm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "AvmMini_common.test.hpp"

namespace tests_avm {
using namespace avm_trace;
using namespace tests_avm;

class AvmMiniControlFlowTests : public ::testing::Test {
public:
Expand Down Expand Up @@ -285,3 +285,4 @@ TEST_F(AvmMiniControlFlowTests, multipleCallsAndReturns)

validate_trace_proof(std::move(trace));
}
} // namespace tests_avm
Loading

0 comments on commit eb01dbd

Please sign in to comment.