Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
exec_op_id.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
4#include <cstdint>
5
21
22namespace bb::avm2::constraining {
23namespace {
24
25using simulation::ExecutionEvent;
26using testing::InstructionBuilder;
27using tracegen::ExecutionTraceBuilder;
28using tracegen::PrecomputedTraceBuilder;
31
32using tracegen::TestTraceContainer;
34using C = Column;
36
37constexpr std::array<WireOpCode, 23> WIRE_OPCODES = {
44};
45
46constexpr std::array<uint32_t, 23> OPERATION_IDS = {
70};
71
72constexpr std::array<C, 23> SELECTOR_COLUMNS = {
73 C::execution_sel_execute_get_env_var,
74 C::execution_sel_execute_mov,
75 C::execution_sel_execute_mov,
76 C::execution_sel_execute_jump,
77 C::execution_sel_execute_jumpi,
78 C::execution_sel_execute_call,
79 C::execution_sel_execute_internal_call,
80 C::execution_sel_execute_internal_return,
81 C::execution_sel_execute_return,
82 C::execution_sel_execute_success_copy,
83 C::execution_sel_execute_static_call,
84 C::execution_sel_execute_revert,
85 C::execution_sel_execute_revert,
86 C::execution_sel_execute_returndata_size,
87 C::execution_sel_execute_debug_log,
88 C::execution_sel_execute_sload,
89 C::execution_sel_execute_sstore,
90 C::execution_sel_execute_notehash_exists,
91 C::execution_sel_execute_emit_notehash,
92 C::execution_sel_execute_l1_to_l2_message_exists,
93 C::execution_sel_execute_nullifier_exists,
94 C::execution_sel_execute_emit_nullifier,
95 C::execution_sel_execute_send_l2_to_l1_msg,
96};
97
98// Ensure that WIRE_OPCODES contains all wire opcodes which have an execution opcode belonging
99// to the execution subtrace.
100TEST(ExecOpIdConstrainingTest, WireOpcodeListCompleteness)
101{
102 for (uint8_t opcode = 0; opcode < static_cast<uint8_t>(WireOpCode::LAST_OPCODE_SENTINEL); opcode++) {
103 const auto wire_opcode = static_cast<WireOpCode>(opcode);
104 const auto& exec_opcode = WIRE_INSTRUCTION_SPEC.at(wire_opcode).exec_opcode;
105
106 if (SUBTRACE_INFO_MAP.contains(exec_opcode)) {
107 const auto& subtrace_info = SUBTRACE_INFO_MAP.at(exec_opcode);
108 if (subtrace_info.subtrace_selector == SubtraceSel::EXECUTION) {
109 EXPECT_TRUE(std::ranges::find(WIRE_OPCODES.begin(), WIRE_OPCODES.end(), wire_opcode) !=
110 WIRE_OPCODES.end());
111 }
112 }
113 }
114}
115
116// Magic constant ensuring that for any index i, the index i + INCREMENT_FOR_NEGATIVE_TEST modulo
117// WIRE_OPCODES.size() has a different value in OPERATION_IDS and SELECTOR_COLUMNS. 6 corresponds to the
118// number of SET wire opcodes. This is the execution opcode with the largest number of wire opcodes.
119constexpr size_t INCREMENT_FOR_NEGATIVE_TEST = 6;
120
121TEST(ExecOpIdConstrainingTest, Decomposition)
122{
123 for (size_t i = 0; i < WIRE_OPCODES.size(); i++) {
124 TestTraceContainer trace({
125 {
126 { C::execution_sel_exec_dispatch_execution, 1 },
127 { C::execution_sel_should_execute_opcode, 1 },
128 { C::execution_subtrace_operation_id, OPERATION_IDS.at(i) },
129 { SELECTOR_COLUMNS.at(i), 1 },
130 },
131 });
132
133 check_relation<execution>(trace, execution::SR_EXEC_OP_ID_DECOMPOSITION);
134
135 // Negative test: untoggle the selector
136 trace.set(SELECTOR_COLUMNS.at(i), 0, 0);
138 "EXEC_OP_ID_DECOMPOSITION");
139
140 // Negative test: toggle another selector
141 trace.set(SELECTOR_COLUMNS.at((i + INCREMENT_FOR_NEGATIVE_TEST) % WIRE_OPCODES.size()), 0, 1);
143 "EXEC_OP_ID_DECOMPOSITION");
144 }
145}
146
147// Show that the precomputed trace contains the correct execution operation id
148// which maps to the correct opcode selectors.
149// Show also that execution relations are satisfied.
150TEST(ExecOpIdConstrainingTest, InteractionWithExecInstructionSpec)
151{
152 PrecomputedTraceBuilder precomputed_builder;
153
155 events.reserve(WIRE_OPCODES.size());
156 for (const auto& wire_opcode : WIRE_OPCODES) {
157 events.push_back({
158 .wire_instruction = InstructionBuilder(wire_opcode).build(),
159 });
160 }
161
162 TestTraceContainer trace;
163 ExecutionTraceBuilder exec_builder;
164 uint32_t row = 1;
165
166 for (const auto& event : events) {
167 exec_builder.process_execution_spec(event, trace, row);
168 row++;
169 }
170
171 // Check that the operation ids and relevant selectors are toggled.
172 for (size_t i = 0; i < WIRE_OPCODES.size(); i++) {
173 ASSERT_EQ(trace.get(C::execution_subtrace_operation_id, static_cast<uint32_t>(i + 1)), OPERATION_IDS.at(i));
174 ASSERT_EQ(trace.get(C::execution_subtrace_id, static_cast<uint32_t>(i + 1)), AVM_SUBTRACE_ID_EXECUTION);
175 }
176
177 // Activate the lookup selector execution_sel_instruction_fetching_success for each row.
178 // Activate the selectors should_execute_opcode, exec_dispatch_execution, and the execution opcode selector.
179 // Set the execution opcode for each row.
180 for (size_t i = 0; i < WIRE_OPCODES.size(); i++) {
181 trace.set(C::execution_sel_instruction_fetching_success, static_cast<uint32_t>(i + 1), 1);
182 trace.set(C::execution_sel_should_execute_opcode, static_cast<uint32_t>(i + 1), 1);
183 trace.set(C::execution_sel_exec_dispatch_execution, static_cast<uint32_t>(i + 1), 1);
184 trace.set(SELECTOR_COLUMNS.at(i), static_cast<uint32_t>(i + 1), 1);
185 trace.set(C::execution_ex_opcode,
186 static_cast<uint32_t>(i + 1),
187 static_cast<uint8_t>(events.at(i).wire_instruction.get_exec_opcode()));
188 }
189
191 trace, 256); // number of clk set to 256 to ensure it covers all the rows of exec instruction spec
193
194 check_relation<execution>(trace, execution::SR_EXEC_OP_ID_DECOMPOSITION);
195 check_interaction<ExecutionTraceBuilder, lookup_execution_exec_spec_read_settings>(trace);
196
197 // Negative test: copy a wrong operation id
198 for (size_t i = 0; i < WIRE_OPCODES.size(); i++) {
199 auto mutated_trace = trace;
200 mutated_trace.set(C::execution_subtrace_operation_id,
201 static_cast<uint32_t>(i + 1),
202 OPERATION_IDS.at((i + INCREMENT_FOR_NEGATIVE_TEST) % WIRE_OPCODES.size()));
204 (check_interaction<ExecutionTraceBuilder, lookup_execution_exec_spec_read_settings>(mutated_trace)),
205 "Failed.*LOOKUP_EXECUTION_EXEC_SPEC_READ.*Could not find tuple in destination.");
206 }
207}
208
209} // namespace
210} // namespace bb::avm2::constraining
#define AVM_EXEC_OP_ID_SUCCESSCOPY
#define AVM_EXEC_OP_ID_NULLIFIER_EXISTS
#define AVM_EXEC_OP_ID_SSTORE
#define AVM_EXEC_OP_ID_EMIT_NULLIFIER
#define AVM_EXEC_OP_ID_NOTEHASH_EXISTS
#define AVM_EXEC_OP_ID_SLOAD
#define AVM_EXEC_OP_ID_RETURN
#define AVM_EXEC_OP_ID_INTERNALCALL
#define AVM_EXEC_OP_ID_STATICCALL
#define AVM_EXEC_OP_ID_JUMP
#define AVM_EXEC_OP_ID_DEBUGLOG
#define AVM_EXEC_OP_ID_EMIT_NOTEHASH
#define AVM_EXEC_OP_ID_REVERT
#define AVM_EXEC_OP_ID_MOV
#define AVM_EXEC_OP_ID_SENDL2TOL1MSG
#define AVM_EXEC_OP_ID_RETURNDATASIZE
#define AVM_EXEC_OP_ID_CALL
#define AVM_EXEC_OP_ID_JUMPI
#define AVM_EXEC_OP_ID_L1_TO_L2_MESSAGE_EXISTS
#define AVM_EXEC_OP_ID_GETENVVAR
#define AVM_EXEC_OP_ID_INTERNALRETURN
#define AVM_SUBTRACE_ID_EXECUTION
static constexpr size_t SR_EXEC_OP_ID_DECOMPOSITION
Definition execution.hpp:50
void process_exec_instruction_spec(TraceContainer &trace)
void process_misc(TraceContainer &trace, const uint32_t num_rows=MAX_AVM_TRACE_SIZE)
const FF & get(Column col, uint32_t row) const
void set(Column col, uint32_t row, const FF &value)
PrecomputedTraceBuilder precomputed_builder
Definition alu.test.cpp:119
TestTraceContainer trace
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
Definition macros.hpp:7
TEST(TxExecutionConstrainingTest, WriteTreeValue)
Definition tx.test.cpp:402
const std::unordered_map< ExecutionOpCode, SubtraceInfo > SUBTRACE_INFO_MAP
const std::unordered_map< WireOpCode, WireInstructionSpec > WIRE_INSTRUCTION_SPEC
typename Flavor::FF FF
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
simulation::PublicDataTreeReadWriteEvent event
NiceMock< MockExecution > execution