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