Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
data_copy.test.cpp
Go to the documentation of this file.
2
3#include <cstdint>
4#include <gmock/gmock.h>
5#include <gtest/gtest.h>
6
17
18namespace bb::avm2::simulation {
19namespace {
20
21using ::testing::ElementsAre;
22using ::testing::Return;
23using ::testing::ReturnRef;
24using ::testing::StrictMock;
25
26class DataCopySimulationTest : public ::testing::Test {
27 protected:
28 DataCopySimulationTest()
29 {
30 ON_CALL(context, get_memory()).WillByDefault(ReturnRef(mem));
31
32 // Standard EventEmitter Expectations
33 EXPECT_CALL(context, get_memory());
34 EXPECT_CALL(execution_id_manager, get_execution_id());
35 EXPECT_CALL(context, get_context_id());
36 }
37
38 MemoryStore mem;
39 StrictMock<MockExecutionIdManager> execution_id_manager;
40 PureGreaterThan gt;
41 StrictMock<MockContext> context;
42 EventEmitter<DataCopyEvent> event_emitter;
43 DataCopy data_copy = DataCopy(execution_id_manager, gt, event_emitter);
44
45 uint32_t dst_addr = 0; // Destination address in memory for the copied returndata.
46};
47
48class NestedCdCopySimulationTest : public DataCopySimulationTest {
49 protected:
50 NestedCdCopySimulationTest()
51 {
52 // Load up parent context
53 for (uint32_t i = 0; i < parent_cd_size; ++i) {
55 }
56 EXPECT_CALL(context, get_parent_cd_addr()).WillRepeatedly(Return(parent_cd_addr));
57 EXPECT_CALL(context, get_parent_cd_size()).WillRepeatedly(Return(parent_cd_size));
58 EXPECT_CALL(context, get_parent_id());
59 EXPECT_CALL(context, has_parent()).WillRepeatedly(Return(true));
60 }
61
62 std::vector<MemoryValue> calldata = { MemoryValue::from<FF>(1), MemoryValue::from<FF>(2), MemoryValue::from<FF>(3),
63 MemoryValue::from<FF>(4), MemoryValue::from<FF>(5), MemoryValue::from<FF>(6),
64 MemoryValue::from<FF>(7), MemoryValue::from<FF>(8) };
65 uint32_t parent_cd_addr = 100; // Address where the parent calldata is stored.
66 uint32_t parent_cd_size = static_cast<uint32_t>(calldata.size());
67 uint32_t cd_offset = 0;
68};
69
70TEST_F(NestedCdCopySimulationTest, CdZero)
71{
72 // Copy zero calldata from the parent context to memory
73 uint32_t cd_copy_size = 0;
74 uint32_t cd_offset = 0;
75
77
78 auto c = mem.get(dst_addr);
79 EXPECT_TRUE(c.as_ff().is_zero());
80}
81
82TEST_F(NestedCdCopySimulationTest, CdCopyAll)
83{
84 // Copy all calldata from the parent context to memory
85 uint32_t cd_copy_size = static_cast<uint32_t>(calldata.size());
86
87 EXPECT_CALL(context, get_calldata(cd_offset, cd_copy_size)).WillOnce(Return(calldata));
88
89 uint32_t dst_addr = 0;
90 data_copy.cd_copy(context, cd_copy_size, cd_offset, dst_addr);
91
92 // This should write all the calldata values
93 std::vector<FF> calldata_in_memory;
94 for (uint32_t i = 0; i < cd_copy_size; ++i) {
95 auto c = mem.get(dst_addr + i);
96 calldata_in_memory.emplace_back(c.as_ff());
97 }
98 EXPECT_THAT(calldata_in_memory, ElementsAre(1, 2, 3, 4, 5, 6, 7, 8));
99}
100
101TEST_F(NestedCdCopySimulationTest, CdCopyPartial)
102{
103 // Copy come calldata from the parent context to memory
104 uint32_t cd_copy_size = 2;
105
106 EXPECT_CALL(context, get_calldata(cd_offset, cd_copy_size))
107 .WillOnce(Return(std::vector<MemoryValue>{ MemoryValue::from<FF>(1),
108 MemoryValue::from<FF>(2) })); // Only copy first two values
109
110 data_copy.cd_copy(context, cd_copy_size, cd_offset, dst_addr);
111
112 // This should write all the calldata values
113 std::vector<FF> calldata_in_memory;
114 for (uint32_t i = 0; i < cd_copy_size; ++i) {
115 auto c = mem.get(dst_addr + i);
116 calldata_in_memory.emplace_back(c.as_ff());
117 }
118 EXPECT_THAT(calldata_in_memory, ElementsAre(1, 2));
119}
120
121TEST_F(NestedCdCopySimulationTest, CdFullWithPadding)
122{
123 // Copy some calldata from the parent context to memory, but with padding
124 uint32_t cd_copy_size = 10; // Request more than available
125
126 std::vector<MemoryValue> expected_calldata = {
127 MemoryValue::from<FF>(1), MemoryValue::from<FF>(2), MemoryValue::from<FF>(3), MemoryValue::from<FF>(4),
128 MemoryValue::from<FF>(5), MemoryValue::from<FF>(6), MemoryValue::from<FF>(7), MemoryValue::from<FF>(8),
129 MemoryValue::from<FF>(0), MemoryValue::from<FF>(0)
130 }; // Should pad with zeros
131 EXPECT_CALL(context, get_calldata(cd_offset, cd_copy_size)).WillOnce(Return(expected_calldata));
132
133 data_copy.cd_copy(context, cd_copy_size, cd_offset, dst_addr);
134
135 // This should write all the calldata values and pad the rest with zeros
136 std::vector<FF> calldata_in_memory;
137 for (uint32_t i = 0; i < cd_copy_size; ++i) {
138 auto c = mem.get(dst_addr + i);
139 calldata_in_memory.emplace_back(c.as_ff());
140 }
141 EXPECT_THAT(calldata_in_memory, ElementsAre(1, 2, 3, 4, 5, 6, 7, 8, 0, 0));
142}
143
144TEST_F(NestedCdCopySimulationTest, CdPartialWithPadding)
145{
146 // Copy some calldata from the parent context to memory, but with padding
147 uint32_t cd_copy_size = 4; // Request more than available
148 uint32_t cd_offset = 6; // Offset into calldata
149
150 std::vector<MemoryValue> expected_calldata = {
151 MemoryValue::from<FF>(7),
152 MemoryValue::from<FF>(8),
153 MemoryValue::from<FF>(0),
154 MemoryValue::from<FF>(0),
155 }; // Should pad with zeros
156
157 EXPECT_CALL(context, get_calldata(cd_offset, cd_copy_size)).WillOnce(Return(expected_calldata));
158
159 data_copy.cd_copy(context, cd_copy_size, cd_offset, dst_addr);
160
161 // This should write all the calldata values and pad the rest with zeros
162 std::vector<FF> calldata_in_memory;
163 for (uint32_t i = 0; i < cd_copy_size; ++i) {
164 auto c = mem.get(dst_addr + i);
165 calldata_in_memory.emplace_back(c.as_ff());
166 }
167 EXPECT_THAT(calldata_in_memory, ElementsAre(7, 8, 0, 0));
168}
169
170class RdCopySimulationTest : public DataCopySimulationTest {
171 protected:
172 RdCopySimulationTest()
173 {
174 // Set up the parent context address
175 EXPECT_CALL(context, get_last_rd_addr()).WillRepeatedly(Return(child_rd_addr));
176 EXPECT_CALL(context, get_last_rd_size()).WillRepeatedly(Return(child_rd_size));
177 EXPECT_CALL(context, get_last_child_id()).WillRepeatedly(Return(child_context_id));
178 EXPECT_CALL(context, has_parent()).WillRepeatedly(Return(true));
179 EXPECT_CALL(context, get_last_child_id()).WillRepeatedly(Return(2));
180 }
182 MemoryValue::from<FF>(9), MemoryValue::from<FF>(10), MemoryValue::from<FF>(11), MemoryValue::from<FF>(12)
183 }; // Example returndata to be copied.
184 uint32_t child_rd_size = static_cast<uint32_t>(returndata.size());
185 uint32_t child_rd_addr = 200; // Address where the parent returndata is stored.
186 uint32_t child_context_id = 2;
187};
188
189TEST_F(RdCopySimulationTest, RdZero)
190{
191 // Copy zero returndata from the last executed context to memory
192 uint32_t rd_copy_size = 0;
193 uint32_t rd_offset = 0;
194
195 data_copy.rd_copy(context, rd_copy_size, rd_offset, dst_addr);
196
197 auto c = mem.get(dst_addr);
198 EXPECT_TRUE(c.as_ff().is_zero());
199}
200
201TEST_F(RdCopySimulationTest, RdCopyAll)
202{
203 // Copy all returndata from the last executed context to memory
204 uint32_t rd_copy_size = static_cast<uint32_t>(returndata.size());
205 uint32_t rd_offset = 0;
206
207 EXPECT_CALL(context, get_returndata(rd_offset, rd_copy_size)).WillOnce(Return(returndata));
208
209 data_copy.rd_copy(context, rd_copy_size, rd_offset, dst_addr);
210
211 // This should write all the returndata values
212 std::vector<FF> returndata_in_memory;
213 for (uint32_t i = 0; i < rd_copy_size; ++i) {
214 auto c = mem.get(dst_addr + i);
215 returndata_in_memory.emplace_back(c.as_ff());
216 }
217 EXPECT_THAT(returndata_in_memory, ElementsAre(9, 10, 11, 12));
218}
219
220TEST_F(RdCopySimulationTest, RdCopyPartial)
221{
222 // Copy some returndata from the last executed context to memory
223 uint32_t rd_copy_size = 2;
224 uint32_t rd_offset = 1; // Start copying from second element
225
226 EXPECT_CALL(context, get_returndata(rd_offset, rd_copy_size))
227 .WillOnce(Return(std::vector<MemoryValue>{ MemoryValue::from<FF>(10),
228 MemoryValue::from<FF>(11) })); // Only copy second and third values
229
230 data_copy.rd_copy(context, rd_copy_size, rd_offset, dst_addr);
231
232 // This should write the selected returndata values
233 std::vector<FF> returndata_in_memory;
234 for (uint32_t i = 0; i < rd_copy_size; ++i) {
235 auto c = mem.get(dst_addr + i);
236 returndata_in_memory.emplace_back(c.as_ff());
237 }
238 EXPECT_THAT(returndata_in_memory, ElementsAre(10, 11));
239}
240
241TEST_F(RdCopySimulationTest, RdFullWithPadding)
242{
243 // Copy some returndata from the last executed context to memory, but with padding
244 uint32_t rd_copy_size = 10; // Request more than available
245 uint32_t rd_offset = 0; // Start copying from first element
246
247 std::vector<MemoryValue> expected_returndata = {
248 MemoryValue::from<FF>(9), MemoryValue::from<FF>(10), MemoryValue::from<FF>(11), MemoryValue::from<FF>(12),
249 MemoryValue::from<FF>(0), MemoryValue::from<FF>(0), MemoryValue::from<FF>(0), MemoryValue::from<FF>(0),
250 MemoryValue::from<FF>(0), MemoryValue::from<FF>(0)
251 }; // Should pad with zeros
252 EXPECT_CALL(context, get_returndata(rd_offset, rd_copy_size)).WillOnce(Return(expected_returndata));
253
254 data_copy.rd_copy(context, rd_copy_size, rd_offset, dst_addr);
255
256 // This should write all the returndata values and pad the rest with zeros
257 std::vector<FF> returndata_in_memory;
258 for (uint32_t i = 0; i < rd_copy_size; ++i) {
259 auto c = mem.get(dst_addr + i);
260 returndata_in_memory.emplace_back(c.as_ff());
261 }
262 EXPECT_THAT(returndata_in_memory, ElementsAre(9, 10, 11, 12, 0, 0, 0, 0, 0, 0));
263}
264
265TEST_F(RdCopySimulationTest, RdPartialWithPadding)
266{
267 // Copy some returndata from the last executed context to memory, but with padding
268 uint32_t rd_copy_size = 4; // Request more than available
269 uint32_t rd_offset = 2; // Start copying from third element
270
271 std::vector<MemoryValue> expected_returndata = {
272 MemoryValue::from<FF>(11),
273 MemoryValue::from<FF>(12),
274 MemoryValue::from<FF>(0),
275 MemoryValue::from<FF>(0),
276 }; // Should pad with zeros
277
278 EXPECT_CALL(context, get_returndata(rd_offset, rd_copy_size)).WillOnce(Return(expected_returndata));
279
280 data_copy.rd_copy(context, rd_copy_size, rd_offset, dst_addr);
281
282 // This should write all the returndata values and pad the rest with zeros
283 std::vector<FF> returndata_in_memory;
284 for (uint32_t i = 0; i < rd_copy_size; ++i) {
285 auto c = mem.get(dst_addr + i);
286 returndata_in_memory.emplace_back(c.as_ff());
287 }
288 EXPECT_THAT(returndata_in_memory, ElementsAre(11, 12, 0, 0));
289}
290
291} // namespace
292} // namespace bb::avm2::simulation
static TaggedValue from(T value)
void rd_copy(ContextInterface &context, uint32_t copy_size, uint32_t offset, MemoryAddress dst_addr) override
Copies returndata from the last executed context to the dst_addr.
void cd_copy(ContextInterface &context, uint32_t copy_size, uint32_t offset, MemoryAddress dst_addr) override
Writes calldata into dst_addr. There is slight difference in how enqueued and nested contexts are han...
Definition data_copy.cpp:98
const MemoryValue & get(MemoryAddress index) const override
ExecutionIdManager execution_id_manager
MemoryStore mem
EventEmitter< DataCopyEvent > event_emitter
uint32_t dst_addr
GreaterThan gt
StrictMock< MockContext > context
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:185
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::vector< MemoryValue > calldata
uint32_t child_rd_addr
uint32_t parent_cd_addr
uint32_t child_context_id
uint32_t child_rd_size
DataCopy data_copy
uint32_t parent_cd_size
std::vector< MemoryValue > returndata
uint32_t cd_offset