Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
alu.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 {
19
20using ::testing::_;
21using ::testing::ElementsAre;
22using ::testing::Return;
23using ::testing::StrictMock;
24
25namespace {
26
27TEST(AvmSimulationAluTest, Add)
28{
29 EventEmitter<AluEvent> alu_event_emitter;
30 StrictMock<MockGreaterThan> gt;
31 StrictMock<MockFieldGreaterThan> field_gt;
32 StrictMock<MockRangeCheck> range_check;
33 Alu alu(gt, field_gt, range_check, alu_event_emitter);
34
35 auto a = MemoryValue::from<uint32_t>(1);
36 auto b = MemoryValue::from<uint32_t>(2);
37
38 auto c = alu.add(a, b);
39
40 EXPECT_EQ(c, MemoryValue::from<uint32_t>(3));
41
42 auto events = alu_event_emitter.dump_events();
43 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::ADD, .a = a, .b = b, .c = c }));
44}
45
46TEST(AvmSimulationAluTest, AddOverflow)
47{
48 EventEmitter<AluEvent> alu_event_emitter;
49 StrictMock<MockGreaterThan> gt;
50 StrictMock<MockFieldGreaterThan> field_gt;
51 StrictMock<MockRangeCheck> range_check;
52 Alu alu(gt, field_gt, range_check, alu_event_emitter);
53
54 auto a = MemoryValue::from<uint32_t>(static_cast<uint32_t>(get_tag_max_value(MemoryTag::U32)));
55 auto b = MemoryValue::from<uint32_t>(2);
56
57 auto c = alu.add(a, b);
58
59 EXPECT_EQ(c, MemoryValue::from<uint32_t>(1));
60
61 auto events = alu_event_emitter.dump_events();
62 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::ADD, .a = a, .b = b, .c = c }));
63}
64
65TEST(AvmSimulationAluTest, NegativeAddTag)
66{
67 EventEmitter<AluEvent> alu_event_emitter;
68 StrictMock<MockGreaterThan> gt;
69 StrictMock<MockFieldGreaterThan> field_gt;
70 StrictMock<MockRangeCheck> range_check;
71 Alu alu(gt, field_gt, range_check, alu_event_emitter);
72
73 auto a = MemoryValue::from<uint32_t>(1);
74 auto b = MemoryValue::from<uint64_t>(2);
75
76 EXPECT_THROW(alu.add(a, b), AluException);
77
78 auto events = alu_event_emitter.dump_events();
79 EXPECT_THAT(events,
80 ElementsAre(AluEvent{ .operation = AluOperation::ADD,
81 .a = a,
82 .b = b,
83 .c = MemoryValue::from_tag(static_cast<MemoryTag>(0), 0),
84 .error = AluError::TAG_ERROR }));
85}
86
87TEST(AvmSimulationAluTest, Sub)
88{
89 EventEmitter<AluEvent> alu_event_emitter;
90 StrictMock<MockGreaterThan> gt;
91 StrictMock<MockFieldGreaterThan> field_gt;
92 StrictMock<MockRangeCheck> range_check;
93 Alu alu(gt, field_gt, range_check, alu_event_emitter);
94
95 auto a = MemoryValue::from<uint32_t>(2);
96 auto b = MemoryValue::from<uint32_t>(1);
97
98 auto c = alu.sub(a, b);
99
100 EXPECT_EQ(c, MemoryValue::from<uint32_t>(1));
101
102 auto events = alu_event_emitter.dump_events();
103 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::SUB, .a = a, .b = b, .c = c }));
104}
105
106TEST(AvmSimulationAluTest, SubUnderflow)
107{
108 EventEmitter<AluEvent> alu_event_emitter;
109 StrictMock<MockGreaterThan> gt;
110 StrictMock<MockFieldGreaterThan> field_gt;
111 StrictMock<MockRangeCheck> range_check;
112 Alu alu(gt, field_gt, range_check, alu_event_emitter);
113
114 auto a = MemoryValue::from<uint64_t>(1);
115 auto b = MemoryValue::from<uint64_t>(2);
116
117 auto c = alu.sub(a, b);
118
120
121 auto events = alu_event_emitter.dump_events();
122 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::SUB, .a = a, .b = b, .c = c }));
123}
124
125TEST(AvmSimulationAluTest, SubFFUnderflow)
126{
127 EventEmitter<AluEvent> alu_event_emitter;
128 StrictMock<MockGreaterThan> gt;
129 StrictMock<MockFieldGreaterThan> field_gt;
130 StrictMock<MockRangeCheck> range_check;
131 Alu alu(gt, field_gt, range_check, alu_event_emitter);
132
133 auto a = MemoryValue::from<FF>(1);
134 auto b = MemoryValue::from<FF>(2);
135
136 auto c = alu.sub(a, b);
137
139
140 auto events = alu_event_emitter.dump_events();
141 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::SUB, .a = a, .b = b, .c = c }));
142}
143
144TEST(AvmSimulationAluTest, NegativeSubTag)
145{
146 EventEmitter<AluEvent> alu_event_emitter;
147 StrictMock<MockGreaterThan> gt;
148 StrictMock<MockFieldGreaterThan> field_gt;
149 StrictMock<MockRangeCheck> range_check;
150 Alu alu(gt, field_gt, range_check, alu_event_emitter);
151
152 auto a = MemoryValue::from<uint32_t>(2);
153 auto b = MemoryValue::from<uint64_t>(1);
154
155 EXPECT_THROW(alu.sub(a, b), AluException);
156
157 auto events = alu_event_emitter.dump_events();
158 EXPECT_THAT(events,
159 ElementsAre(AluEvent{ .operation = AluOperation::SUB,
160 .a = a,
161 .b = b,
162 .c = MemoryValue::from_tag(static_cast<MemoryTag>(0), 0),
163 .error = AluError::TAG_ERROR }));
164}
165
166TEST(AvmSimulationAluTest, Mul)
167{
168 EventEmitter<AluEvent> alu_event_emitter;
169 StrictMock<MockGreaterThan> gt;
170 StrictMock<MockFieldGreaterThan> field_gt;
171 StrictMock<MockRangeCheck> range_check;
172 Alu alu(gt, field_gt, range_check, alu_event_emitter);
173
174 auto a = MemoryValue::from<uint32_t>(2);
175 auto b = MemoryValue::from<uint32_t>(3);
176
177 auto c = alu.mul(a, b);
178
179 EXPECT_EQ(c, MemoryValue::from<uint32_t>(6));
180
181 auto events = alu_event_emitter.dump_events();
182 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::MUL, .a = a, .b = b, .c = c }));
183}
184
185TEST(AvmSimulationAluTest, MulOverflow)
186{
187 EventEmitter<AluEvent> alu_event_emitter;
188 StrictMock<MockGreaterThan> gt;
189 StrictMock<MockFieldGreaterThan> field_gt;
190 StrictMock<MockRangeCheck> range_check;
191 Alu alu(gt, field_gt, range_check, alu_event_emitter);
192
193 auto a = MemoryValue::from<uint32_t>(static_cast<uint32_t>(get_tag_max_value(MemoryTag::U32)));
194 auto b = MemoryValue::from<uint32_t>(2);
195
196 auto c = alu.mul(a, b);
197
198 EXPECT_EQ(c, MemoryValue::from<uint32_t>(static_cast<uint32_t>(get_tag_max_value(MemoryTag::U32) - 1)));
199
200 auto events = alu_event_emitter.dump_events();
201 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::MUL, .a = a, .b = b, .c = c }));
202}
203
204TEST(AvmSimulationAluTest, MulOverflowU128)
205{
206 EventEmitter<AluEvent> alu_event_emitter;
207 StrictMock<MockGreaterThan> gt;
208 StrictMock<MockFieldGreaterThan> field_gt;
209 StrictMock<MockRangeCheck> range_check;
210 Alu alu(gt, field_gt, range_check, alu_event_emitter);
211
213
214 auto a = MemoryValue::from<uint128_t>(max);
215 auto b = MemoryValue::from<uint128_t>(max - 3);
216
217 // For u128s, we range check a_lo, a_hi, b_lo, b_hi, and c_hi:
218 EXPECT_CALL(range_check, assert_range(_, 64)).Times(5);
219
220 auto c = alu.mul(a, b);
221
222 EXPECT_EQ(c, MemoryValue::from<uint128_t>(4));
223
224 auto events = alu_event_emitter.dump_events();
225 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::MUL, .a = a, .b = b, .c = c }));
226}
227
228TEST(AvmSimulationAluTest, Div)
229{
230 EventEmitter<AluEvent> alu_event_emitter;
231 StrictMock<MockGreaterThan> gt;
232 StrictMock<MockFieldGreaterThan> field_gt;
233 StrictMock<MockRangeCheck> range_check;
234 Alu alu(gt, field_gt, range_check, alu_event_emitter);
235
236 auto a = MemoryValue::from<uint32_t>(6);
237 auto b = MemoryValue::from<uint32_t>(3);
238
239 EXPECT_CALL(gt, gt(b, MemoryValue::from<uint32_t>(0))).WillOnce(Return(true));
240
241 auto c = alu.div(a, b);
242
243 EXPECT_EQ(c, MemoryValue::from<uint32_t>(2));
244
245 auto events = alu_event_emitter.dump_events();
246 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::DIV, .a = a, .b = b, .c = c }));
247}
248
249TEST(AvmSimulationAluTest, DivU128)
250{
251 EventEmitter<AluEvent> alu_event_emitter;
252 StrictMock<MockGreaterThan> gt;
253 StrictMock<MockFieldGreaterThan> field_gt;
254 StrictMock<MockRangeCheck> range_check;
255 Alu alu(gt, field_gt, range_check, alu_event_emitter);
256
258
259 auto a = MemoryValue::from<uint128_t>(max);
260 auto b = MemoryValue::from<uint128_t>(2);
261
262 EXPECT_CALL(gt, gt(b, MemoryValue::from<uint128_t>(1))).WillOnce(Return(true));
263
264 // For u128s, we range check c_lo, c_hi, b_lo, b_hi:
265 EXPECT_CALL(range_check, assert_range(_, 64)).Times(4);
266
267 auto c = alu.div(a, b);
268
269 EXPECT_EQ(c, MemoryValue::from<uint128_t>(max >> 1));
270
271 auto events = alu_event_emitter.dump_events();
272 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::DIV, .a = a, .b = b, .c = c }));
273}
274
275TEST(AvmSimulationAluTest, DivByZero)
276{
277 EventEmitter<AluEvent> alu_event_emitter;
278 StrictMock<MockGreaterThan> gt;
279 StrictMock<MockFieldGreaterThan> field_gt;
280 StrictMock<MockRangeCheck> range_check;
281 Alu alu(gt, field_gt, range_check, alu_event_emitter);
282
283 auto a = MemoryValue::from<uint32_t>(6);
284 auto b = MemoryValue::from<uint32_t>(0);
285
286 EXPECT_THROW(alu.div(a, b), AluException);
287
288 auto events = alu_event_emitter.dump_events();
289 EXPECT_THAT(
290 events,
291 ElementsAre(AluEvent{ .operation = AluOperation::DIV, .a = a, .b = b, .error = AluError::DIV_0_ERROR }));
292}
293
294TEST(AvmSimulationAluTest, DivFFTag)
295{
296 EventEmitter<AluEvent> alu_event_emitter;
297 StrictMock<MockGreaterThan> gt;
298 StrictMock<MockFieldGreaterThan> field_gt;
299 StrictMock<MockRangeCheck> range_check;
300 Alu alu(gt, field_gt, range_check, alu_event_emitter);
301
302 auto a = MemoryValue::from<FF>(2);
303 auto b = MemoryValue::from<FF>(2);
304
305 EXPECT_THROW(alu.div(a, b), AluException);
306
307 auto events = alu_event_emitter.dump_events();
308 EXPECT_THAT(events,
309 ElementsAre(AluEvent{ .operation = AluOperation::DIV,
310 .a = a,
311 .b = b,
312 .c = MemoryValue::from_tag(static_cast<MemoryTag>(0), 0),
313 .error = AluError::TAG_ERROR }));
314}
315
316TEST(AvmSimulationAluTest, FDiv)
317{
318 EventEmitter<AluEvent> alu_event_emitter;
319 StrictMock<MockGreaterThan> gt;
320 StrictMock<MockFieldGreaterThan> field_gt;
321 StrictMock<MockRangeCheck> range_check;
322 Alu alu(gt, field_gt, range_check, alu_event_emitter);
323
324 auto a = MemoryValue::from<FF>(FF::modulus - 4);
325 auto b = MemoryValue::from<FF>(2);
326
327 auto c = alu.fdiv(a, b);
328
329 EXPECT_EQ(c, MemoryValue::from<FF>(FF::modulus - 2));
330
331 auto events = alu_event_emitter.dump_events();
332 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::FDIV, .a = a, .b = b, .c = c }));
333}
334
335TEST(AvmSimulationAluTest, FDivByZero)
336{
337 EventEmitter<AluEvent> alu_event_emitter;
338 StrictMock<MockGreaterThan> gt;
339 StrictMock<MockFieldGreaterThan> field_gt;
340 StrictMock<MockRangeCheck> range_check;
341 Alu alu(gt, field_gt, range_check, alu_event_emitter);
342
343 auto a = MemoryValue::from<FF>(FF::modulus - 4);
344 auto b = MemoryValue::from<FF>(0);
345
346 EXPECT_THROW(alu.fdiv(a, b), AluException);
347
348 auto events = alu_event_emitter.dump_events();
349 EXPECT_THAT(
350 events,
351 ElementsAre(AluEvent{ .operation = AluOperation::FDIV, .a = a, .b = b, .error = AluError::DIV_0_ERROR }));
352}
353
354TEST(AvmSimulationAluTest, FDivNonFFTag)
355{
356 EventEmitter<AluEvent> alu_event_emitter;
357 StrictMock<MockGreaterThan> gt;
358 StrictMock<MockFieldGreaterThan> field_gt;
359 StrictMock<MockRangeCheck> range_check;
360 Alu alu(gt, field_gt, range_check, alu_event_emitter);
361
362 auto a = MemoryValue::from<uint64_t>(2);
363 auto b = MemoryValue::from<uint64_t>(2);
364
365 EXPECT_THROW(alu.fdiv(a, b), AluException);
366
367 auto events = alu_event_emitter.dump_events();
368 EXPECT_THAT(events,
369 ElementsAre(AluEvent{ .operation = AluOperation::FDIV,
370 .a = a,
371 .b = b,
372 .c = MemoryValue::from_tag(static_cast<MemoryTag>(0), 0),
373 .error = AluError::TAG_ERROR }));
374}
375
376TEST(AvmSimulationAluTest, LT)
377{
378 EventEmitter<AluEvent> alu_event_emitter;
379 StrictMock<MockGreaterThan> gt;
380 StrictMock<MockFieldGreaterThan> field_gt;
381 StrictMock<MockRangeCheck> range_check;
382 Alu alu(gt, field_gt, range_check, alu_event_emitter);
383
384 auto a = MemoryValue::from<uint32_t>(1);
385 auto b = MemoryValue::from<uint32_t>(2);
386
387 EXPECT_CALL(gt, gt(b, a)).WillOnce(Return(true));
388
389 auto c = alu.lt(a, b);
390
391 EXPECT_EQ(c, MemoryValue::from<uint1_t>(1));
392
393 auto events = alu_event_emitter.dump_events();
394 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::LT, .a = a, .b = b, .c = c }));
395}
396
397TEST(AvmSimulationAluTest, LTFF)
398{
399 EventEmitter<AluEvent> alu_event_emitter;
400 StrictMock<MockGreaterThan> gt;
401 StrictMock<MockFieldGreaterThan> field_gt;
402 StrictMock<MockRangeCheck> range_check;
403 Alu alu(gt, field_gt, range_check, alu_event_emitter);
404
405 auto a = MemoryValue::from<FF>(FF::modulus - 3);
406 auto b = MemoryValue::from<FF>(2);
407
408 EXPECT_CALL(gt, gt(b, a)).WillOnce(Return(false));
409
410 auto c = alu.lt(a, b);
411
412 EXPECT_EQ(c, MemoryValue::from<uint1_t>(0));
413
414 auto events = alu_event_emitter.dump_events();
415 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::LT, .a = a, .b = b, .c = c }));
416}
417
418TEST(AvmSimulationAluTest, NegativeLTTag)
419{
420 EventEmitter<AluEvent> alu_event_emitter;
421 StrictMock<MockGreaterThan> gt;
422 StrictMock<MockFieldGreaterThan> field_gt;
423 StrictMock<MockRangeCheck> range_check;
424 Alu alu(gt, field_gt, range_check, alu_event_emitter);
425
426 auto a = MemoryValue::from<uint32_t>(1);
427 auto b = MemoryValue::from<uint64_t>(2);
428
429 EXPECT_THROW(alu.lt(a, b), AluException);
430
431 auto events = alu_event_emitter.dump_events();
432 EXPECT_THAT(events,
433 ElementsAre(AluEvent{ .operation = AluOperation::LT,
434 .a = a,
435 .b = b,
436 .c = MemoryValue::from_tag(static_cast<MemoryTag>(0), 0),
437 .error = AluError::TAG_ERROR }));
438}
439
440TEST(AvmSimulationAluTest, LTE)
441{
442 EventEmitter<AluEvent> alu_event_emitter;
443 StrictMock<MockGreaterThan> gt;
444 StrictMock<MockFieldGreaterThan> field_gt;
445 StrictMock<MockRangeCheck> range_check;
446 Alu alu(gt, field_gt, range_check, alu_event_emitter);
447
448 auto a = MemoryValue::from<uint32_t>(1);
449 auto b = MemoryValue::from<uint32_t>(2);
450
451 EXPECT_CALL(gt, gt(a, b)).WillOnce(Return(false));
452
453 auto c = alu.lte(a, b);
454
455 EXPECT_EQ(c, MemoryValue::from<uint1_t>(1));
456
457 auto events = alu_event_emitter.dump_events();
458 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::LTE, .a = a, .b = b, .c = c }));
459}
460
461TEST(AvmSimulationAluTest, LTEEq)
462{
463 EventEmitter<AluEvent> alu_event_emitter;
464 StrictMock<MockGreaterThan> gt;
465 StrictMock<MockFieldGreaterThan> field_gt;
466 StrictMock<MockRangeCheck> range_check;
467 Alu alu(gt, field_gt, range_check, alu_event_emitter);
468
469 auto a = MemoryValue::from<uint128_t>(2);
470 auto b = MemoryValue::from<uint128_t>(2);
471
472 EXPECT_CALL(gt, gt(a, b)).WillOnce(Return(false));
473
474 auto c = alu.lte(a, b);
475
476 EXPECT_EQ(c, MemoryValue::from<uint1_t>(1));
477
478 auto events = alu_event_emitter.dump_events();
479 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::LTE, .a = a, .b = b, .c = c }));
480}
481
482TEST(AvmSimulationAluTest, LTEFF)
483{
484 EventEmitter<AluEvent> alu_event_emitter;
485 StrictMock<MockGreaterThan> gt;
486 StrictMock<MockFieldGreaterThan> field_gt;
487 StrictMock<MockRangeCheck> range_check;
488 Alu alu(gt, field_gt, range_check, alu_event_emitter);
489
490 auto a = MemoryValue::from<FF>(FF::modulus - 3);
491 auto b = MemoryValue::from<FF>(2);
492
493 EXPECT_CALL(gt, gt(a, b)).WillOnce(Return(true));
494
495 auto c = alu.lte(a, b);
496
497 EXPECT_EQ(c, MemoryValue::from<uint1_t>(0));
498
499 auto events = alu_event_emitter.dump_events();
500 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::LTE, .a = a, .b = b, .c = c }));
501}
502
503// TODO(MW): Required? Same path as ADD tag error tests
504TEST(AvmSimulationAluTest, NegativeLTETag)
505{
506 EventEmitter<AluEvent> alu_event_emitter;
507 StrictMock<MockGreaterThan> gt;
508 StrictMock<MockFieldGreaterThan> field_gt;
509 StrictMock<MockRangeCheck> range_check;
510 Alu alu(gt, field_gt, range_check, alu_event_emitter);
511
512 auto a = MemoryValue::from<uint32_t>(1);
513 auto b = MemoryValue::from<uint64_t>(2);
514
515 EXPECT_THROW(alu.lte(a, b), AluException);
516
517 auto events = alu_event_emitter.dump_events();
518 EXPECT_THAT(events,
519 ElementsAre(AluEvent{ .operation = AluOperation::LTE, .a = a, .b = b, .error = AluError::TAG_ERROR }));
520}
521
522TEST(AvmSimulationAluTest, EQEquality)
523{
524 EventEmitter<AluEvent> alu_event_emitter;
525 StrictMock<MockGreaterThan> gt;
526 StrictMock<MockFieldGreaterThan> field_gt;
527 StrictMock<MockRangeCheck> range_check;
528 Alu alu(gt, field_gt, range_check, alu_event_emitter);
529
530 auto a = MemoryValue::from<uint128_t>(123456789);
531 auto b = MemoryValue::from<uint128_t>(123456789);
532
533 auto c = alu.eq(a, b);
534
535 EXPECT_EQ(c, MemoryValue::from<uint1_t>(1));
536
537 auto events = alu_event_emitter.dump_events();
538 EXPECT_THAT(events,
539 ElementsAre(AluEvent{ .operation = AluOperation::EQ, .a = a, .b = b, .c = c, .error = std::nullopt }));
540}
541
542TEST(AvmSimulationAluTest, EQInequality)
543{
544 EventEmitter<AluEvent> alu_event_emitter;
545 StrictMock<MockGreaterThan> gt;
546 StrictMock<MockFieldGreaterThan> field_gt;
547 StrictMock<MockRangeCheck> range_check;
548 Alu alu(gt, field_gt, range_check, alu_event_emitter);
549
550 auto a = MemoryValue::from<FF>(123456789);
551 auto b = MemoryValue::from<FF>(123456788);
552
553 auto c = alu.eq(a, b);
554
555 EXPECT_EQ(c, MemoryValue::from<uint1_t>(0));
556
557 auto events = alu_event_emitter.dump_events();
558 EXPECT_THAT(events,
559 ElementsAre(AluEvent{ .operation = AluOperation::EQ, .a = a, .b = b, .c = c, .error = std::nullopt }));
560}
561
562TEST(AvmSimulationAluTest, EQTagError)
563{
564 EventEmitter<AluEvent> alu_event_emitter;
565 StrictMock<MockGreaterThan> gt;
566 StrictMock<MockFieldGreaterThan> field_gt;
567 StrictMock<MockRangeCheck> range_check;
568 Alu alu(gt, field_gt, range_check, alu_event_emitter);
569
570 auto a = MemoryValue::from<uint1_t>(1);
571 auto b = MemoryValue::from<uint8_t>(1);
572
573 EXPECT_THROW(alu.eq(a, b), AluException);
574
575 auto events = alu_event_emitter.dump_events();
576 EXPECT_THAT(events,
577 ElementsAre(AluEvent{ .operation = AluOperation::EQ,
578 .a = a,
579 .b = b,
580 .c = MemoryValue::from_tag(static_cast<MemoryTag>(0), 0),
581 .error = AluError::TAG_ERROR }));
582}
583
584TEST(AvmSimulationAluTest, NotBasic)
585{
586 EventEmitter<AluEvent> alu_event_emitter;
587 StrictMock<MockGreaterThan> gt;
588 StrictMock<MockFieldGreaterThan> field_gt;
589 StrictMock<MockRangeCheck> range_check;
590 Alu alu(gt, field_gt, range_check, alu_event_emitter);
591
592 const auto a = MemoryValue::from<uint64_t>(98321);
593 const auto b = alu.op_not(a);
594
595 EXPECT_EQ(b, ~a);
596
597 auto events = alu_event_emitter.dump_events();
598 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::NOT, .a = a, .b = b, .error = std::nullopt }));
599}
600
601TEST(AvmSimulationAluTest, NotFFTagError)
602{
603 EventEmitter<AluEvent> alu_event_emitter;
604 StrictMock<MockGreaterThan> gt;
605 StrictMock<MockFieldGreaterThan> field_gt;
606 StrictMock<MockRangeCheck> range_check;
607 Alu alu(gt, field_gt, range_check, alu_event_emitter);
608
609 auto a = MemoryValue::from<FF>(FF::modulus - 3);
610
611 EXPECT_THROW(alu.op_not(a), AluException);
612
613 auto events = alu_event_emitter.dump_events();
614 EXPECT_THAT(events,
615 ElementsAre(AluEvent{ .operation = AluOperation::NOT,
616 .a = a,
617 .b = MemoryValue::from_tag(static_cast<MemoryTag>(0), 0),
618 .error = AluError::TAG_ERROR }));
619}
620
621TEST(AvmSimulationAluTest, Shl)
622{
623 EventEmitter<AluEvent> alu_event_emitter;
624 StrictMock<MockGreaterThan> gt;
625 StrictMock<MockFieldGreaterThan> field_gt;
626 StrictMock<MockRangeCheck> range_check;
627 Alu alu(gt, field_gt, range_check, alu_event_emitter);
628
629 auto a = MemoryValue::from<uint32_t>(64);
630 auto b = MemoryValue::from<uint32_t>(2);
631
632 // a_lo and a_hi range checks:
633 EXPECT_CALL(range_check, assert_range(64, 30)).Times(1);
634 EXPECT_CALL(range_check, assert_range(0, 2)).Times(1);
635
636 auto c = alu.shl(a, b);
637
638 EXPECT_EQ(c, MemoryValue::from<uint32_t>(256));
639
640 auto events = alu_event_emitter.dump_events();
641 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::SHL, .a = a, .b = b, .c = c }));
642}
643
644TEST(AvmSimulationAluTest, ShlOverflow)
645{
646 EventEmitter<AluEvent> alu_event_emitter;
647 StrictMock<MockGreaterThan> gt;
648 StrictMock<MockFieldGreaterThan> field_gt;
649 StrictMock<MockRangeCheck> range_check;
650 Alu alu(gt, field_gt, range_check, alu_event_emitter);
651
652 auto a = MemoryValue::from<uint32_t>(64);
653 auto b = MemoryValue::from<uint32_t>(100);
654
655 // a_lo and a_hi range checks:
656 EXPECT_CALL(range_check, assert_range(68, 32)).Times(1);
657 EXPECT_CALL(range_check, assert_range(0, 32)).Times(1);
658
659 auto c = alu.shl(a, b);
660
661 EXPECT_EQ(c, MemoryValue::from<uint32_t>(0));
662
663 auto events = alu_event_emitter.dump_events();
664 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::SHL, .a = a, .b = b, .c = c }));
665}
666
667TEST(AvmSimulationAluTest, NegativeShlTagMismatch)
668{
669 EventEmitter<AluEvent> alu_event_emitter;
670 StrictMock<MockGreaterThan> gt;
671 StrictMock<MockFieldGreaterThan> field_gt;
672 StrictMock<MockRangeCheck> range_check;
673 Alu alu(gt, field_gt, range_check, alu_event_emitter);
674
675 auto a = MemoryValue::from<uint32_t>(64);
676 auto b = MemoryValue::from<uint64_t>(2);
677
678 EXPECT_THROW(alu.shl(a, b), AluException);
679
680 auto events = alu_event_emitter.dump_events();
681 EXPECT_THAT(events,
682 ElementsAre(AluEvent{ .operation = AluOperation::SHL,
683 .a = a,
684 .b = b,
685 .c = MemoryValue::from_tag(static_cast<MemoryTag>(0), 0),
686 .error = AluError::TAG_ERROR }));
687}
688
689TEST(AvmSimulationAluTest, Shr)
690{
691 EventEmitter<AluEvent> alu_event_emitter;
692 StrictMock<MockGreaterThan> gt;
693 StrictMock<MockFieldGreaterThan> field_gt;
694 StrictMock<MockRangeCheck> range_check;
695 Alu alu(gt, field_gt, range_check, alu_event_emitter);
696
697 auto a = MemoryValue::from<uint32_t>(64);
698 auto b = MemoryValue::from<uint32_t>(2);
699
700 // a_lo and a_hi range checks:
701 EXPECT_CALL(range_check, assert_range(0, 2)).Times(1);
702 EXPECT_CALL(range_check, assert_range(16, 30)).Times(1);
703
704 auto c = alu.shr(a, b);
705
706 EXPECT_EQ(c, MemoryValue::from<uint32_t>(16));
707
708 auto events = alu_event_emitter.dump_events();
709 EXPECT_THAT(events, ElementsAre(AluEvent{ .operation = AluOperation::SHR, .a = a, .b = b, .c = c }));
710}
711
712TEST(AvmSimulationAluTest, ShrFFTag)
713{
714 EventEmitter<AluEvent> alu_event_emitter;
715 StrictMock<MockGreaterThan> gt;
716 StrictMock<MockFieldGreaterThan> field_gt;
717 StrictMock<MockRangeCheck> range_check;
718 Alu alu(gt, field_gt, range_check, alu_event_emitter);
719
720 auto a = MemoryValue::from<FF>(64);
721 auto b = MemoryValue::from<FF>(2);
722
723 EXPECT_THROW(alu.shr(a, b), AluException);
724
725 auto events = alu_event_emitter.dump_events();
726 EXPECT_THAT(events,
727 ElementsAre(AluEvent{ .operation = AluOperation::SHR,
728 .a = a,
729 .b = b,
730 .c = MemoryValue::from_tag(static_cast<MemoryTag>(0), 0),
731 .error = AluError::TAG_ERROR }));
732}
733
734TEST(AvmSimulationAluTest, TruncateTrivial)
735{
736 EventEmitter<AluEvent> alu_event_emitter;
737 StrictMock<MockGreaterThan> gt;
738 StrictMock<MockFieldGreaterThan> field_gt;
739 StrictMock<MockRangeCheck> range_check;
740 Alu alu(gt, field_gt, range_check, alu_event_emitter);
741
742 FF a = 8762;
743
744 auto b = alu.truncate(a, static_cast<MemoryTag>(MemoryTag::U16));
745 auto c = MemoryValue::from<uint16_t>(8762);
746 EXPECT_EQ(b, c);
747
748 auto events = alu_event_emitter.dump_events();
749 EXPECT_THAT(events,
750 ElementsAre(AluEvent{ .operation = AluOperation::TRUNCATE,
752 .b = MemoryValue::from_tag(MemoryTag::FF, static_cast<uint8_t>(MemoryTag::U16)),
753 .c = c,
754 .error = std::nullopt }));
755}
756
757TEST(AvmSimulationAluTest, TruncateLess128Bits)
758{
759 EventEmitter<AluEvent> alu_event_emitter;
760 StrictMock<MockGreaterThan> gt;
761 StrictMock<MockFieldGreaterThan> field_gt;
762 StrictMock<MockRangeCheck> range_check;
763 Alu alu(gt, field_gt, range_check, alu_event_emitter);
764
765 FF a = (1 << 16) + 12222;
766
767 EXPECT_CALL(range_check, assert_range(1, 112)).Times(1);
768
769 auto b = alu.truncate(a, static_cast<MemoryTag>(MemoryTag::U16));
770 auto c = MemoryValue::from<uint16_t>(12222);
771 EXPECT_EQ(b, c);
772
773 auto events = alu_event_emitter.dump_events();
774 EXPECT_THAT(events,
775 ElementsAre(AluEvent{ .operation = AluOperation::TRUNCATE,
777 .b = MemoryValue::from_tag(MemoryTag::FF, static_cast<uint8_t>(MemoryTag::U16)),
778 .c = c,
779 .error = std::nullopt }));
780}
781
782TEST(AvmSimulationAluTest, TruncateGreater128Bits)
783{
784 EventEmitter<AluEvent> alu_event_emitter;
785 StrictMock<MockGreaterThan> gt;
786 StrictMock<MockFieldGreaterThan> field_gt;
787 StrictMock<MockRangeCheck> range_check;
788 Alu alu(gt, field_gt, range_check, alu_event_emitter);
789
790 FF a = (static_cast<uint256_t>(176) << 175) + (static_cast<uint256_t>(234) << 32) + 123456789;
791 U256Decomposition decomposition_a = { .lo = (static_cast<uint128_t>(234) << 32) + 123456789, .hi = 176 };
792
793 EXPECT_CALL(range_check, assert_range(234, 96)).Times(1);
794 EXPECT_CALL(field_gt, canon_dec(a)).Times(1).WillOnce(Return(decomposition_a));
795
796 auto b = alu.truncate(a, static_cast<MemoryTag>(MemoryTag::U32));
797 auto c = MemoryValue::from<uint32_t>(123456789);
798
799 EXPECT_EQ(b, c);
800
801 auto events = alu_event_emitter.dump_events();
802 EXPECT_THAT(events,
803 ElementsAre(AluEvent{ .operation = AluOperation::TRUNCATE,
805 .b = MemoryValue::from_tag(MemoryTag::FF, static_cast<uint8_t>(MemoryTag::U32)),
806 .c = c,
807 .error = std::nullopt }));
808}
809
810} // namespace
811} // namespace bb::avm2::simulation
static TaggedValue from_tag(ValueTag tag, FF value)
RangeCheck range_check
GreaterThan gt
FF a
FF b
TEST(EmitUnencryptedLogTest, Basic)
uint256_t get_tag_max_value(ValueTag tag)
ValueTag MemoryTag
typename Flavor::FF FF
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
unsigned __int128 uint128_t
Definition serialize.hpp:44
NiceMock< MockFieldGreaterThan > field_gt