Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
calldata_trace.test.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <cmath>
3#include <cstddef>
4#include <gmock/gmock.h>
5#include <gtest/gtest.h>
6
7#include <cstdint>
8#include <memory>
9#include <sys/types.h>
10#include <vector>
11
21
23using testing::SizeIs;
24
25namespace bb::avm2::tracegen {
26namespace {
27
28using C = Column;
30
31TEST(CalldataTraceGenTest, BasicHashing)
32{
33 TestTraceContainer trace;
34 CalldataTraceBuilder builder;
35
36 const auto calldata_hash = RawPoseidon2::hash({ DOM_SEP__PUBLIC_CALLDATA, 10, 20, 30 });
37
38 builder.process_hashing(
39 {
40 simulation::CalldataEvent{
41 .context_id = 1,
42 .calldata = { 10, 20, 30 },
43 .calldata_hash = calldata_hash,
44 },
45 },
46 trace);
47 const auto rows = trace.as_rows();
48
49 // One extra empty row is prepended.
50 EXPECT_THAT(rows.at(1),
51 AllOf(ROW_FIELD_EQ(calldata_hashing_sel, 1),
52 ROW_FIELD_EQ(calldata_hashing_start, 1),
53 ROW_FIELD_EQ(calldata_hashing_sel_not_start, 0),
54 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_1, 1),
55 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_2, 1),
56 ROW_FIELD_EQ(calldata_hashing_end, 0),
57 ROW_FIELD_EQ(calldata_hashing_sel_end_not_empty, 0),
58 ROW_FIELD_EQ(calldata_hashing_context_id, 1),
59 ROW_FIELD_EQ(calldata_hashing_index_0_, 0),
60 ROW_FIELD_EQ(calldata_hashing_index_1_, 1),
61 ROW_FIELD_EQ(calldata_hashing_index_2_, 2),
62 ROW_FIELD_EQ(calldata_hashing_input_0_, DOM_SEP__PUBLIC_CALLDATA),
63 ROW_FIELD_EQ(calldata_hashing_input_1_, 10),
64 ROW_FIELD_EQ(calldata_hashing_input_2_, 20),
65 ROW_FIELD_EQ(calldata_hashing_calldata_size, 3),
66 ROW_FIELD_EQ(calldata_hashing_input_len, 4),
67 ROW_FIELD_EQ(calldata_hashing_rounds_rem, 2),
68 ROW_FIELD_EQ(calldata_hashing_output_hash, calldata_hash)));
69
70 // End row
71 EXPECT_THAT(rows.at(2),
72 AllOf(ROW_FIELD_EQ(calldata_hashing_sel, 1),
73 ROW_FIELD_EQ(calldata_hashing_start, 0),
74 ROW_FIELD_EQ(calldata_hashing_sel_not_start, 1),
75 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_1, 0),
76 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_2, 0),
77 ROW_FIELD_EQ(calldata_hashing_end, 1),
78 ROW_FIELD_EQ(calldata_hashing_sel_end_not_empty, 1),
79 ROW_FIELD_EQ(calldata_hashing_context_id, 1),
80 ROW_FIELD_EQ(calldata_hashing_index_0_, 3),
81 ROW_FIELD_EQ(calldata_hashing_index_1_, 4),
82 ROW_FIELD_EQ(calldata_hashing_index_2_, 5),
83 ROW_FIELD_EQ(calldata_hashing_input_0_, 30),
84 ROW_FIELD_EQ(calldata_hashing_input_1_, 0),
85 ROW_FIELD_EQ(calldata_hashing_input_2_, 0),
86 ROW_FIELD_EQ(calldata_hashing_calldata_size, 3),
87 ROW_FIELD_EQ(calldata_hashing_input_len, 4),
88 ROW_FIELD_EQ(calldata_hashing_rounds_rem, 1),
89 ROW_FIELD_EQ(calldata_hashing_output_hash, calldata_hash)));
90}
91
92TEST(CalldataTraceGenTest, BasicRetrievalAndHashing)
93{
94 TestTraceContainer trace;
95 CalldataTraceBuilder builder;
96
97 const auto calldata_hash_1 = RawPoseidon2::hash({ DOM_SEP__PUBLIC_CALLDATA, 1, 2 });
98 const auto calldata_hash_2 = RawPoseidon2::hash({ DOM_SEP__PUBLIC_CALLDATA, 3 });
99
100 // Must be sorted by context_id in ascending order.
101 const auto events = { simulation::CalldataEvent{
102 .context_id = 1,
103 .calldata = { 1, 2 },
104 .calldata_hash = calldata_hash_1,
105 },
106 simulation::CalldataEvent{
107 .context_id = 3,
108 .calldata = { 3 },
109 .calldata_hash = calldata_hash_2,
110 } };
111
112 builder.process_retrieval(events, trace);
113 builder.process_hashing(events, trace);
114 const auto rows = trace.as_rows();
115
116 // One extra empty row is prepended.
117 EXPECT_THAT(rows.at(1),
118 AllOf(ROW_FIELD_EQ(calldata_sel, 1),
119 ROW_FIELD_EQ(calldata_end, 0),
120 ROW_FIELD_EQ(calldata_context_id, 1),
121 ROW_FIELD_EQ(calldata_index, 1),
122 ROW_FIELD_EQ(calldata_value, 1)));
123 EXPECT_THAT(rows.at(2),
124 AllOf(ROW_FIELD_EQ(calldata_sel, 1),
125 ROW_FIELD_EQ(calldata_end, 1),
126 ROW_FIELD_EQ(calldata_context_id, 1),
127 ROW_FIELD_EQ(calldata_index, 2),
128 ROW_FIELD_EQ(calldata_value, 2)));
129 EXPECT_THAT(rows.at(3),
130 AllOf(ROW_FIELD_EQ(calldata_sel, 1),
131 ROW_FIELD_EQ(calldata_end, 1),
132 ROW_FIELD_EQ(calldata_context_id, 3),
133 ROW_FIELD_EQ(calldata_index, 1),
134 ROW_FIELD_EQ(calldata_value, 3)));
135 // Hashing tracegen:
136 EXPECT_THAT(rows.at(1),
137 AllOf(ROW_FIELD_EQ(calldata_hashing_sel, 1),
138 ROW_FIELD_EQ(calldata_hashing_start, 1),
139 ROW_FIELD_EQ(calldata_hashing_sel_not_start, 0),
140 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_1, 1),
141 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_2, 1),
142 ROW_FIELD_EQ(calldata_hashing_end, 1),
143 ROW_FIELD_EQ(calldata_hashing_sel_end_not_empty, 1),
144 ROW_FIELD_EQ(calldata_hashing_context_id, 1),
145 ROW_FIELD_EQ(calldata_hashing_index_0_, 0),
146 ROW_FIELD_EQ(calldata_hashing_index_1_, 1),
147 ROW_FIELD_EQ(calldata_hashing_index_2_, 2),
148 ROW_FIELD_EQ(calldata_hashing_input_0_, DOM_SEP__PUBLIC_CALLDATA),
149 ROW_FIELD_EQ(calldata_hashing_input_1_, 1),
150 ROW_FIELD_EQ(calldata_hashing_input_2_, 2),
151 ROW_FIELD_EQ(calldata_hashing_calldata_size, 2),
152 ROW_FIELD_EQ(calldata_hashing_input_len, 3),
153 ROW_FIELD_EQ(calldata_hashing_rounds_rem, 1),
154 ROW_FIELD_EQ(calldata_hashing_output_hash, calldata_hash_1)));
155
156 EXPECT_THAT(rows.at(2),
157 AllOf(ROW_FIELD_EQ(calldata_hashing_sel, 1),
158 ROW_FIELD_EQ(calldata_hashing_start, 1),
159 ROW_FIELD_EQ(calldata_hashing_sel_not_start, 0),
160 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_1, 1),
161 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_2, 0),
162 ROW_FIELD_EQ(calldata_hashing_end, 1),
163 ROW_FIELD_EQ(calldata_hashing_sel_end_not_empty, 1),
164 ROW_FIELD_EQ(calldata_hashing_context_id, 3),
165 ROW_FIELD_EQ(calldata_hashing_index_0_, 0),
166 ROW_FIELD_EQ(calldata_hashing_index_1_, 1),
167 ROW_FIELD_EQ(calldata_hashing_index_2_, 2),
168 ROW_FIELD_EQ(calldata_hashing_input_0_, DOM_SEP__PUBLIC_CALLDATA),
169 ROW_FIELD_EQ(calldata_hashing_input_1_, 3),
170 ROW_FIELD_EQ(calldata_hashing_input_2_, 0),
171 ROW_FIELD_EQ(calldata_hashing_calldata_size, 1),
172 ROW_FIELD_EQ(calldata_hashing_input_len, 2),
173 ROW_FIELD_EQ(calldata_hashing_rounds_rem, 1),
174 ROW_FIELD_EQ(calldata_hashing_output_hash, calldata_hash_2)));
175}
176
177TEST(CalldataTraceGenTest, BasicRetrievalAndHashingEmpty)
178{
179 TestTraceContainer trace;
180 CalldataTraceBuilder builder;
181
182 const auto calldata_hash = RawPoseidon2::hash({ DOM_SEP__PUBLIC_CALLDATA });
183
184 const auto events = { simulation::CalldataEvent{
185 .context_id = 12,
186 .calldata = {},
187 .calldata_hash = calldata_hash,
188 } };
189
190 builder.process_retrieval(events, trace);
191 builder.process_hashing(events, trace);
192 const auto rows = trace.as_rows();
193
194 // One extra empty row is prepended.
195
196 // Retrieval tracegen should NOT create a row for empty calldata (no special row needed
197 // since sel_end_not_empty = 0 for empty calldata, so no permutation entry is required).
198 EXPECT_THAT(rows.at(1), AllOf(ROW_FIELD_EQ(calldata_sel, 0), ROW_FIELD_EQ(calldata_end, 0)));
199 // Hashing tracegen should set the output hash as H(sep):
200 EXPECT_THAT(rows.at(1),
201 AllOf(ROW_FIELD_EQ(calldata_hashing_sel, 1),
202 ROW_FIELD_EQ(calldata_hashing_start, 1),
203 ROW_FIELD_EQ(calldata_hashing_sel_not_start, 0),
204 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_1, 0),
205 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_2, 0),
206 ROW_FIELD_EQ(calldata_hashing_end, 1),
207 ROW_FIELD_EQ(calldata_hashing_sel_end_not_empty, 0),
208 ROW_FIELD_EQ(calldata_hashing_context_id, 12),
209 ROW_FIELD_EQ(calldata_hashing_index_0_, 0),
210 ROW_FIELD_EQ(calldata_hashing_index_1_, 1),
211 ROW_FIELD_EQ(calldata_hashing_index_2_, 2),
212 ROW_FIELD_EQ(calldata_hashing_input_0_, DOM_SEP__PUBLIC_CALLDATA),
213 ROW_FIELD_EQ(calldata_hashing_input_1_, 0),
214 ROW_FIELD_EQ(calldata_hashing_input_2_, 0),
215 ROW_FIELD_EQ(calldata_hashing_calldata_size, 0),
216 ROW_FIELD_EQ(calldata_hashing_input_len, 1),
217 ROW_FIELD_EQ(calldata_hashing_rounds_rem, 1),
218 ROW_FIELD_EQ(calldata_hashing_output_hash, calldata_hash)));
219}
220
221TEST(CalldataTraceGenTest, LongerHash)
222{
223 TestTraceContainer trace;
224 CalldataTraceBuilder builder;
225
226 std::vector<FF> calldata = random_fields(100);
227 std::vector<FF> preimage = { DOM_SEP__PUBLIC_CALLDATA };
228 preimage.insert(preimage.end(), calldata.begin(), calldata.end());
229 FF output_hash = RawPoseidon2::hash(preimage);
230
231 builder.process_hashing(
232 {
233 simulation::CalldataEvent{
234 .context_id = 1,
235 .calldata = calldata,
236 .calldata_hash = output_hash,
237 },
238 },
239 trace);
240 const auto rows = trace.as_rows();
241 // Omit the prepended first row:
242 const auto calldata_rows = std::span(rows.begin() + 1, rows.end());
243
244 // 100 field calldata => hash 101 fields => 34 poseidon chunks
245 EXPECT_THAT(calldata_rows, SizeIs(34));
246
247 uint32_t expected_index = 0;
248 for (auto row : calldata_rows) {
249 // Elts which should match each row:
250 EXPECT_THAT(row,
251 AllOf(ROW_FIELD_EQ(calldata_hashing_sel, 1),
252 ROW_FIELD_EQ(calldata_hashing_context_id, 1),
253 ROW_FIELD_EQ(calldata_hashing_calldata_size, 100),
254 ROW_FIELD_EQ(calldata_hashing_input_len, 101),
255 ROW_FIELD_EQ(calldata_hashing_output_hash, output_hash)));
256
257 // Elts which change each row:
258 EXPECT_THAT(
259 row,
260 AllOf(ROW_FIELD_EQ(calldata_hashing_index_0_, expected_index),
261 ROW_FIELD_EQ(calldata_hashing_index_1_, expected_index + 1),
262 ROW_FIELD_EQ(calldata_hashing_index_2_, expected_index + 2),
263 ROW_FIELD_EQ(calldata_hashing_input_0_, preimage.at(expected_index)),
264 ROW_FIELD_EQ(calldata_hashing_input_1_, preimage.at(expected_index + 1)),
265 // The final value is padded:
266 ROW_FIELD_EQ(calldata_hashing_input_2_, expected_index == 99 ? 0 : preimage.at(expected_index + 2)),
267 ROW_FIELD_EQ(calldata_hashing_rounds_rem, 34 - (expected_index / 3))));
268
269 // Elts for start/end rows:
270 EXPECT_THAT(row,
271 AllOf(ROW_FIELD_EQ(calldata_hashing_start, expected_index == 0 ? 1 : 0),
272 ROW_FIELD_EQ(calldata_hashing_sel_not_start, expected_index == 0 ? 0 : 1),
273 ROW_FIELD_EQ(calldata_hashing_end, expected_index == 99 ? 1 : 0),
274 ROW_FIELD_EQ(calldata_hashing_sel_end_not_empty, expected_index == 99 ? 1 : 0),
275 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_1, 1),
276 // The final value is padded:
277 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_2, expected_index == 99 ? 0 : 1)));
278
279 expected_index += 3;
280 }
281}
282
283} // namespace
284} // namespace bb::avm2::tracegen
#define DOM_SEP__PUBLIC_CALLDATA
std::vector< AvmFullRowConstRef > as_rows() const
static FF hash(const std::vector< FF > &input)
Hashes a vector of field elements.
AluTraceBuilder builder
Definition alu.test.cpp:124
TestTraceContainer trace
#define ROW_FIELD_EQ(field_name, expression)
Definition macros.hpp:7
std::vector< FF > random_fields(size_t n)
Definition fixtures.cpp:23
TEST(BoomerangMegaCircuitBuilder, BasicCircuit)
std::vector< MemoryValue > calldata