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 builder.process_hashing(
37 {
38 simulation::CalldataEvent{
39 .context_id = 1,
40 .calldata_size = 3,
41 .calldata = { 10, 20, 30 },
42 },
43 },
44 trace);
45 const auto rows = trace.as_rows();
46
47 // One extra empty row is prepended.
48 EXPECT_THAT(rows.at(1),
49 AllOf(ROW_FIELD_EQ(calldata_hashing_sel, 1),
50 ROW_FIELD_EQ(calldata_hashing_start, 1),
51 ROW_FIELD_EQ(calldata_hashing_sel_not_start, 0),
52 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_1, 1),
53 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_2, 1),
54 ROW_FIELD_EQ(calldata_hashing_latch, 0),
55 ROW_FIELD_EQ(calldata_hashing_context_id, 1),
56 ROW_FIELD_EQ(calldata_hashing_index_0_, 0),
57 ROW_FIELD_EQ(calldata_hashing_index_1_, 1),
58 ROW_FIELD_EQ(calldata_hashing_index_2_, 2),
59 ROW_FIELD_EQ(calldata_hashing_input_0_, GENERATOR_INDEX__PUBLIC_CALLDATA),
60 ROW_FIELD_EQ(calldata_hashing_input_1_, 10),
61 ROW_FIELD_EQ(calldata_hashing_input_2_, 20),
62 ROW_FIELD_EQ(calldata_hashing_calldata_size, 3),
63 ROW_FIELD_EQ(calldata_hashing_input_len, 4),
64 ROW_FIELD_EQ(calldata_hashing_rounds_rem, 2),
65 ROW_FIELD_EQ(calldata_hashing_output_hash,
67
68 // Latched row
69 EXPECT_THAT(rows.at(2),
70 AllOf(ROW_FIELD_EQ(calldata_hashing_sel, 1),
71 ROW_FIELD_EQ(calldata_hashing_start, 0),
72 ROW_FIELD_EQ(calldata_hashing_sel_not_start, 1),
73 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_1, 0),
74 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_2, 0),
75 ROW_FIELD_EQ(calldata_hashing_latch, 1),
76 ROW_FIELD_EQ(calldata_hashing_context_id, 1),
77 ROW_FIELD_EQ(calldata_hashing_index_0_, 3),
78 ROW_FIELD_EQ(calldata_hashing_index_1_, 4),
79 ROW_FIELD_EQ(calldata_hashing_index_2_, 5),
80 ROW_FIELD_EQ(calldata_hashing_input_0_, 30),
81 ROW_FIELD_EQ(calldata_hashing_input_1_, 0),
82 ROW_FIELD_EQ(calldata_hashing_input_2_, 0),
83 ROW_FIELD_EQ(calldata_hashing_calldata_size, 3),
84 ROW_FIELD_EQ(calldata_hashing_input_len, 4),
85 ROW_FIELD_EQ(calldata_hashing_rounds_rem, 1),
86 ROW_FIELD_EQ(calldata_hashing_output_hash,
88}
89
90TEST(CalldataTraceGenTest, BasicRetrievalAndHashing)
91{
92 TestTraceContainer trace;
93 CalldataTraceBuilder builder;
94
95 const auto events = { simulation::CalldataEvent{
96 .context_id = 3,
97 .calldata_size = 2,
98 .calldata = { 1, 2 },
99 },
100 simulation::CalldataEvent{
101 .context_id = 1,
102 .calldata_size = 1,
103 .calldata = { 3 },
104 } };
105
106 builder.process_retrieval(events, trace);
107 builder.process_hashing(events, trace);
108 const auto rows = trace.as_rows();
109
110 // One extra empty row is prepended.
111
112 // Retrieval tracegen should have sorted by context_id:
113 EXPECT_THAT(rows.at(1),
114 AllOf(ROW_FIELD_EQ(calldata_sel, 1),
115 ROW_FIELD_EQ(calldata_latch, 1),
116 ROW_FIELD_EQ(calldata_context_id, 1),
117 ROW_FIELD_EQ(calldata_index, 1),
118 ROW_FIELD_EQ(calldata_value, 3),
119 // Note that the diff is shifted by 1 to ensure the context_ids are increasing:
120 ROW_FIELD_EQ(calldata_diff_context_id, 1)));
121 EXPECT_THAT(rows.at(2),
122 AllOf(ROW_FIELD_EQ(calldata_sel, 1),
123 ROW_FIELD_EQ(calldata_latch, 0),
124 ROW_FIELD_EQ(calldata_context_id, 3),
125 ROW_FIELD_EQ(calldata_index, 1),
126 ROW_FIELD_EQ(calldata_value, 1),
127 ROW_FIELD_EQ(calldata_diff_context_id, 0)));
128 EXPECT_THAT(rows.at(3),
129 AllOf(ROW_FIELD_EQ(calldata_sel, 1),
130 ROW_FIELD_EQ(calldata_latch, 1),
131 ROW_FIELD_EQ(calldata_context_id, 3),
132 ROW_FIELD_EQ(calldata_index, 2),
133 ROW_FIELD_EQ(calldata_value, 2),
134 ROW_FIELD_EQ(calldata_diff_context_id, 0)));
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_latch, 1),
143 ROW_FIELD_EQ(calldata_hashing_context_id, 3),
144 ROW_FIELD_EQ(calldata_hashing_index_0_, 0),
145 ROW_FIELD_EQ(calldata_hashing_index_1_, 1),
146 ROW_FIELD_EQ(calldata_hashing_index_2_, 2),
147 ROW_FIELD_EQ(calldata_hashing_input_0_, GENERATOR_INDEX__PUBLIC_CALLDATA),
148 ROW_FIELD_EQ(calldata_hashing_input_1_, 1),
149 ROW_FIELD_EQ(calldata_hashing_input_2_, 2),
150 ROW_FIELD_EQ(calldata_hashing_calldata_size, 2),
151 ROW_FIELD_EQ(calldata_hashing_input_len, 3),
152 ROW_FIELD_EQ(calldata_hashing_rounds_rem, 1),
153 ROW_FIELD_EQ(calldata_hashing_output_hash,
155
156 EXPECT_THAT(
157 rows.at(2),
158 AllOf(ROW_FIELD_EQ(calldata_hashing_sel, 1),
159 ROW_FIELD_EQ(calldata_hashing_start, 1),
160 ROW_FIELD_EQ(calldata_hashing_sel_not_start, 0),
161 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_1, 1),
162 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_2, 0),
163 ROW_FIELD_EQ(calldata_hashing_latch, 1),
164 ROW_FIELD_EQ(calldata_hashing_context_id, 1),
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_, GENERATOR_INDEX__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, RawPoseidon2::hash({ GENERATOR_INDEX__PUBLIC_CALLDATA, 3 }))));
175}
176
177TEST(CalldataTraceGenTest, BasicRetrievalAndHashingEmpty)
178{
179 TestTraceContainer trace;
180 CalldataTraceBuilder builder;
181
182 const auto events = { simulation::CalldataEvent{
183 .context_id = 12,
184 .calldata_size = 0,
185 .calldata = {},
186 } };
187
188 builder.process_retrieval(events, trace);
189 builder.process_hashing(events, trace);
190 const auto rows = trace.as_rows();
191
192 // One extra empty row is prepended.
193
194 // Retrieval tracegen should have created the special empty case row:
195 EXPECT_THAT(rows.at(1),
196 AllOf(ROW_FIELD_EQ(calldata_sel, 1),
197 ROW_FIELD_EQ(calldata_latch, 1),
198 ROW_FIELD_EQ(calldata_context_id, 12),
199 // This is the only case where the index is 0 and sel is on:
200 ROW_FIELD_EQ(calldata_index, 0)));
201 // Hashing tracegen should set the output hash as H(sep):
202 EXPECT_THAT(
203 rows.at(1),
204 AllOf(ROW_FIELD_EQ(calldata_hashing_sel, 1),
205 ROW_FIELD_EQ(calldata_hashing_start, 1),
206 ROW_FIELD_EQ(calldata_hashing_sel_not_start, 0),
207 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_1, 0),
208 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_2, 0),
209 ROW_FIELD_EQ(calldata_hashing_latch, 1),
210 ROW_FIELD_EQ(calldata_hashing_context_id, 12),
211 ROW_FIELD_EQ(calldata_hashing_index_0_, 0),
212 ROW_FIELD_EQ(calldata_hashing_index_1_, 1),
213 ROW_FIELD_EQ(calldata_hashing_index_2_, 2),
214 ROW_FIELD_EQ(calldata_hashing_input_0_, GENERATOR_INDEX__PUBLIC_CALLDATA),
215 ROW_FIELD_EQ(calldata_hashing_input_1_, 0),
216 ROW_FIELD_EQ(calldata_hashing_input_2_, 0),
217 ROW_FIELD_EQ(calldata_hashing_calldata_size, 0),
218 ROW_FIELD_EQ(calldata_hashing_input_len, 1),
219 ROW_FIELD_EQ(calldata_hashing_rounds_rem, 1),
220 ROW_FIELD_EQ(calldata_hashing_output_hash, RawPoseidon2::hash({ GENERATOR_INDEX__PUBLIC_CALLDATA }))));
221}
222
223TEST(CalldataTraceGenTest, LongerHash)
224{
225 TestTraceContainer trace;
226 CalldataTraceBuilder builder;
227
228 std::vector<FF> calldata = random_fields(100);
229 std::vector<FF> preimage = { GENERATOR_INDEX__PUBLIC_CALLDATA };
230 preimage.insert(preimage.end(), calldata.begin(), calldata.end());
231 FF output_hash = RawPoseidon2::hash(preimage);
232
233 builder.process_hashing(
234 {
235 simulation::CalldataEvent{
236 .context_id = 1,
237 .calldata_size = 100,
238 .calldata = calldata,
239 },
240 },
241 trace);
242 const auto rows = trace.as_rows();
243 // Omit the prepended first row:
244 const auto calldata_rows = std::span(rows.begin() + 1, rows.end());
245
246 // 100 field calldata => hash 101 fields => 34 poseidon chunks
247 EXPECT_THAT(calldata_rows, SizeIs(34));
248
249 uint32_t expected_index = 0;
250 for (auto row : calldata_rows) {
251 // Elts which should match each row:
252 EXPECT_THAT(row,
253 AllOf(ROW_FIELD_EQ(calldata_hashing_sel, 1),
254 ROW_FIELD_EQ(calldata_hashing_context_id, 1),
255 ROW_FIELD_EQ(calldata_hashing_calldata_size, 100),
256 ROW_FIELD_EQ(calldata_hashing_input_len, 101),
257 ROW_FIELD_EQ(calldata_hashing_output_hash, output_hash)));
258
259 // Elts which change each row:
260 EXPECT_THAT(
261 row,
262 AllOf(ROW_FIELD_EQ(calldata_hashing_index_0_, expected_index),
263 ROW_FIELD_EQ(calldata_hashing_index_1_, expected_index + 1),
264 ROW_FIELD_EQ(calldata_hashing_index_2_, expected_index + 2),
265 ROW_FIELD_EQ(calldata_hashing_input_0_, preimage.at(expected_index)),
266 ROW_FIELD_EQ(calldata_hashing_input_1_, preimage.at(expected_index + 1)),
267 // The final value is padded:
268 ROW_FIELD_EQ(calldata_hashing_input_2_, expected_index == 99 ? 0 : preimage.at(expected_index + 2)),
269 ROW_FIELD_EQ(calldata_hashing_rounds_rem, 34 - (expected_index / 3))));
270
271 // Elts for start/end rows:
272 EXPECT_THAT(row,
273 AllOf(ROW_FIELD_EQ(calldata_hashing_start, expected_index == 0 ? 1 : 0),
274 ROW_FIELD_EQ(calldata_hashing_sel_not_start, expected_index == 0 ? 0 : 1),
275 ROW_FIELD_EQ(calldata_hashing_latch, expected_index == 99 ? 1 : 0),
276 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_1, 1),
277 // The final value is padded:
278 ROW_FIELD_EQ(calldata_hashing_sel_not_padding_2, expected_index == 99 ? 0 : 1)));
279
280 expected_index += 3;
281 }
282}
283
284} // namespace
285} // namespace bb::avm2::tracegen
#define GENERATOR_INDEX__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:123
TestTraceContainer trace
#define ROW_FIELD_EQ(field_name, expression)
Definition macros.hpp:15
TEST(EmitUnencryptedLogTest, Basic)
std::vector< FF > random_fields(size_t n)
Definition fixtures.cpp:23
typename Flavor::FF FF
std::vector< FF > calldata