Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
serialization.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
6
7namespace bb::avm2 {
8namespace {
9
13using simulation::Instruction;
15
16// Testing serialization with some u8 variants
17TEST(SerializationTest, Not8RoundTrip)
18{
19 const Instruction instr = { .opcode = WireOpCode::NOT_8,
20 .indirect = 5,
21 .operands = { Operand::from<uint8_t>(123), Operand::from<uint8_t>(45) } };
22 const auto decoded = deserialize_instruction(instr.serialize(), 0);
23 EXPECT_EQ(instr, decoded);
24}
25
26// Testing serialization with some u16 variants
27TEST(SerializationTest, Add16RoundTrip)
28{
29 const Instruction instr = {
30 .opcode = WireOpCode::ADD_16,
31 .indirect = 3,
32 .operands = { Operand::from<uint16_t>(1000), Operand::from<uint16_t>(1001), Operand::from<uint16_t>(1002) }
33 };
34 const auto decoded = deserialize_instruction(instr.serialize(), 0);
35 EXPECT_EQ(instr, decoded);
36}
37
38// Testing serialization with a u32 variant
39TEST(SerializationTest, Jumpi32RoundTrip)
40{
41 const Instruction instr = { .opcode = WireOpCode::JUMPI_32,
42 .indirect = 7,
43 .operands = { Operand::from<uint16_t>(12345), Operand::from<uint32_t>(678901234) } };
44 const auto decoded = deserialize_instruction(instr.serialize(), 0);
45 EXPECT_EQ(instr, decoded);
46}
47
48// Testing serialization with a u64 variant
49TEST(SerializationTest, Set64RoundTrip)
50{
51 const uint64_t value_64 = 0xABCDEF0123456789LLU;
52
53 const Instruction instr = { .opcode = WireOpCode::SET_64,
54 .indirect = 2,
55 .operands = { Operand::from<uint16_t>(1002),
56 Operand::from<uint8_t>(static_cast<uint8_t>(MemoryTag::U64)),
57 Operand::from<uint64_t>(value_64) } };
58 const auto decoded = deserialize_instruction(instr.serialize(), 0);
59 EXPECT_EQ(instr, decoded);
60}
61
62// Testing serialization with a u128 variant
63TEST(SerializationTest, Set128RoundTrip)
64{
65 const uint128_t value_128 = (uint128_t{ 0x123456789ABCDEF0LLU } << 64) + uint128_t{ 0xABCDEF0123456789LLU };
66
67 const Instruction instr = { .opcode = WireOpCode::SET_128,
68 .indirect = 2,
69 .operands = { Operand::from<uint16_t>(1002),
70 Operand::from<uint8_t>(static_cast<uint8_t>(MemoryTag::U128)),
71 Operand::from<uint128_t>(value_128) } };
72 const auto decoded = deserialize_instruction(instr.serialize(), 0);
73 EXPECT_EQ(instr, decoded);
74}
75
76// Testing serialization with ff variant
77TEST(SerializationTest, SetFFRoundTrip)
78{
79 const FF large_ff = FF::modulus - 981723;
80
81 const Instruction instr = { .opcode = WireOpCode::SET_FF,
82 .indirect = 2,
83 .operands = { Operand::from<uint16_t>(1002),
84 Operand::from<uint8_t>(static_cast<uint8_t>(MemoryTag::FF)),
85 Operand::from<FF>(large_ff) } };
86 const auto decoded = deserialize_instruction(instr.serialize(), 0);
87 EXPECT_EQ(instr, decoded);
88}
89
90// Testing serialization with ff variant which is larger than the modulus.
91// Round trip would not work as multiple equivalent values over 256 bits map
92// to the same FF value.
93TEST(SerializationTest, DeserializeLargeFF)
94{
95 const uint256_t value_256 = FF::modulus + 145;
96
97 // We first serialize a "dummy" instruction and then substitute the immediate value encoded as the last 32 bytes.
98 const Instruction instr = { .opcode = WireOpCode::SET_FF,
99 .indirect = 0,
100 .operands = { Operand::from<uint16_t>(1002),
101 Operand::from<uint8_t>(static_cast<uint8_t>(MemoryTag::U8)),
102 Operand::from<FF>(FF::modulus - 1) } };
103 auto serialized_instruction = instr.serialize();
104
105 const auto buf = to_buffer(value_256);
106 serialized_instruction.insert(serialized_instruction.end() - 32, buf.begin(), buf.end());
107
108 const auto decoded = deserialize_instruction(serialized_instruction, 0);
109 ASSERT_EQ(3, decoded.operands.size());
110 EXPECT_EQ(decoded.operands[2].as<FF>(), 145);
111}
112
113// Testing deserialization pc out of range error
114TEST(SerializationTest, PCOutOfRange)
115{
116 std::vector<uint8_t> bytecode;
117 bytecode.resize(35, 0);
118
119 try {
120 deserialize_instruction(bytecode, bytecode.size() + 1);
121 } catch (const InstrDeserializationError& error) {
122 EXPECT_EQ(error, InstrDeserializationError::PC_OUT_OF_RANGE);
123 }
124}
125
126// Testing deserialization wire opcode out of range error
127TEST(SerializationTest, OpcodeOutOfRange)
128{
129 std::vector<uint8_t> bytecode;
130 bytecode.push_back(static_cast<uint8_t>(WireOpCode::LAST_OPCODE_SENTINEL) + 1); // Invalid opcode
131
132 try {
133 deserialize_instruction(bytecode, 0);
134 } catch (const InstrDeserializationError& error) {
135 EXPECT_EQ(error, InstrDeserializationError::OPCODE_OUT_OF_RANGE);
136 }
137}
138
139// Testing deserialization instruction out of range error
140TEST(SerializationTest, InstructionOutOfRange)
141{
142 // Create a valid SET_16 instruction
143 Instruction instr = { .opcode = WireOpCode::SET_16,
144 .indirect = 2,
145 .operands = { Operand::from<uint16_t>(1002),
146 Operand::from<uint8_t>(static_cast<uint8_t>(MemoryTag::U16)),
147 Operand::from<uint16_t>(12345) } };
148
149 auto bytecode = instr.serialize();
150
151 // Truncate the bytecode
152 bytecode.resize(bytecode.size() - 1);
153
154 try {
155 deserialize_instruction(bytecode, 0);
156 } catch (const InstrDeserializationError& error) {
157 EXPECT_EQ(error, InstrDeserializationError::INSTRUCTION_OUT_OF_RANGE);
158 }
159}
160
161// Testing check_tag with a valid instruction for wire opcode SET_128
162TEST(SerializationTest, CheckTagValid)
163{
164 Instruction instr = { .opcode = WireOpCode::SET_128,
165 .indirect = 2,
166 .operands = { Operand::from<uint16_t>(1002),
167 Operand::from<uint8_t>(static_cast<uint8_t>(MemoryTag::U128)),
168 Operand::from<uint128_t>(12345) } };
169 EXPECT_TRUE(check_tag(instr));
170}
171
172// Testing check_tag with an invalid tag for wire opcode SET_128
173TEST(SerializationTest, CheckTagInvalid)
174{
175 Instruction instr = { .opcode = WireOpCode::SET_128,
176 .indirect = 2,
177 .operands = { Operand::from<uint16_t>(1002),
178 Operand::from<uint8_t>(static_cast<uint8_t>(MemoryTag::MAX) + 1),
179 Operand::from<uint128_t>(12345) } };
180 EXPECT_FALSE(check_tag(instr));
181}
182
183// Testing check_tag with an invalid instruction for wire opcode SET_128, not enough operands
184TEST(SerializationTest, CheckTagInvalidNotEnoughOperands)
185{
186 Instruction instr = { .opcode = WireOpCode::SET_128, .indirect = 2, .operands = { Operand::from<uint16_t>(1002) } };
187 EXPECT_FALSE(check_tag(instr));
188}
189
190// Testing check_tag with an invalid instruction for wire opcode SET_128, tag is not a byte
191TEST(SerializationTest, CheckTagInvalidTagNotByte)
192{
193 Instruction instr = { .opcode = WireOpCode::SET_128,
194 .indirect = 2,
195 .operands = { Operand::from<uint16_t>(1002),
196 Operand::from<uint16_t>(static_cast<uint8_t>(MemoryTag::U128)),
197 Operand::from<uint128_t>(12345) } };
198 EXPECT_FALSE(check_tag(instr));
199}
200
201} // namespace
202} // namespace bb::avm2
uint8_t const * buf
Definition data_store.hpp:9
bool check_tag(const Instruction &instruction)
Check whether the instruction must have a tag operand and whether the operand value is in the value t...
TEST(EmitUnencryptedLogTest, Basic)
Instruction deserialize_instruction(std::span< const uint8_t > bytecode, size_t pos)
Parsing of an instruction in the supplied bytecode at byte position pos. This checks that the WireOpC...
Instruction
Enumeration of VM instructions that can be executed.
std::vector< uint8_t > to_buffer(T const &value)
unsigned __int128 uint128_t
Definition serialize.hpp:44
static constexpr uint256_t modulus