diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp index 2590e5e298a..9b9c4bd7b3e 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp @@ -35,6 +35,8 @@ const std::unordered_map> OPCODE_WIRE_FORMAT = { OpCode::AND, three_operand_format }, { OpCode::OR, three_operand_format }, { OpCode::XOR, three_operand_format }, + // Compute - Type Conversions + { OpCode::CAST, { OperandType::INDIRECT, OperandType::TAG, OperandType::UINT32, OperandType::UINT32 } }, // Execution Environment - Calldata { OpCode::CALLDATACOPY, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } }, // Machine State - Internal Control Flow diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp index 1e018d647d6..e25d9ad1807 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp @@ -180,6 +180,13 @@ std::vector Execution::gen_trace(std::vector const& instructio std::get(inst.operands.at(4)), std::get(inst.operands.at(1))); break; + // Compute - Type Conversions + case OpCode::CAST: + trace_builder.op_cast(std::get(inst.operands.at(0)), + std::get(inst.operands.at(2)), + std::get(inst.operands.at(3)), + std::get(inst.operands.at(1))); + break; // Execution Environment - Calldata case OpCode::CALLDATACOPY: trace_builder.calldata_copy(std::get(inst.operands.at(0)), diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp index f505eb16ce5..2639e9fb979 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp @@ -607,6 +607,47 @@ TEST_F(AvmExecutionTests, indMovOpcode) gen_proof_and_validate(bytecode, std::move(trace), {}); } +// Positive test for SET and CAST opcodes +TEST_F(AvmExecutionTests, setAndCastOpcodes) +{ + std::string bytecode_hex = to_hex(OpCode::SET) + // opcode SET + "00" // Indirect flag + "02" // U16 + "B813" // val 47123 + "00000011" // dst_offset 17 + + to_hex(OpCode::CAST) + // opcode CAST + "00" // Indirect flag + "01" // U8 + "00000011" // addr a + "00000012" // addr casted a + + to_hex(OpCode::RETURN) + // opcode RETURN + "00" // Indirect flag + "00000000" // ret offset 0 + "00000000"; // ret size 0 + + auto bytecode = hex_to_bytes(bytecode_hex); + auto instructions = Deserialization::parse(bytecode); + + ASSERT_THAT(instructions, SizeIs(3)); + + // SUB + EXPECT_THAT(instructions.at(1), + AllOf(Field(&Instruction::op_code, OpCode::CAST), + Field(&Instruction::operands, + ElementsAre(VariantWith(0), + VariantWith(AvmMemoryTag::U8), + VariantWith(17), + VariantWith(18))))); + + auto trace = Execution::gen_trace(instructions); + + // Find the first row enabling the cast selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_cast == 1; }); + EXPECT_EQ(row->avm_main_ic, 19); // 0XB813 --> 0X13 = 19 + + gen_proof_and_validate(bytecode, std::move(trace), {}); +} + // Negative test detecting an invalid opcode byte. TEST_F(AvmExecutionTests, invalidOpcode) {