Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
tagged_value.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
8
9namespace bb::avm2 {
10namespace {
11
12// Test constructor and basic properties for each supported type
13TEST(TaggedValueTest, ConstructorAndTypeProperties)
14{
15 // Test uint1_t
16 auto val_u1 = TaggedValue::from<uint1_t>(true);
17 EXPECT_EQ(val_u1.get_tag(), ValueTag::U1);
18 EXPECT_EQ(val_u1.as<uint1_t>().value(), 1);
19
20 // Test uint8_t
21 auto val_u8 = TaggedValue::from<uint8_t>(42);
22 EXPECT_EQ(val_u8.get_tag(), ValueTag::U8);
23 EXPECT_EQ(val_u8.as<uint8_t>(), 42);
24
25 // Test uint16_t
26 auto val_u16 = TaggedValue::from<uint16_t>(1000);
27 EXPECT_EQ(val_u16.get_tag(), ValueTag::U16);
28 EXPECT_EQ(val_u16.as<uint16_t>(), 1000);
29
30 // Test uint32_t
31 auto val_u32 = TaggedValue::from<uint32_t>(100000);
32 EXPECT_EQ(val_u32.get_tag(), ValueTag::U32);
33 EXPECT_EQ(val_u32.as<uint32_t>(), 100000);
34
35 // Test uint64_t
36 auto val_u64 = TaggedValue::from<uint64_t>(1ULL << 40);
37 EXPECT_EQ(val_u64.get_tag(), ValueTag::U64);
38 EXPECT_EQ(val_u64.as<uint64_t>(), 1ULL << 40);
39
40 // Test uint128_t
41 auto val_u128 = TaggedValue::from<uint128_t>(uint128_t(1) << 100);
42 EXPECT_EQ(val_u128.get_tag(), ValueTag::U128);
43 EXPECT_EQ(val_u128.as<uint128_t>(), uint128_t(1) << 100);
44
45 // Test FF
46 auto val_ff = TaggedValue::from<FF>(123);
47 EXPECT_EQ(val_ff.get_tag(), ValueTag::FF);
48 EXPECT_EQ(val_ff.as<FF>(), FF(123));
49}
50
51// Test from_tag method
52TEST(TaggedValueTest, FromTag)
53{
54 FF value = 42;
55
56 auto val_u1 = TaggedValue::from_tag(ValueTag::U1, 1);
57 EXPECT_EQ(val_u1.get_tag(), ValueTag::U1);
58 EXPECT_EQ(val_u1.as<uint1_t>().value(), 1);
59
60 auto val_u1_zero = TaggedValue::from_tag(ValueTag::U1, 0);
61 EXPECT_EQ(val_u1_zero.get_tag(), ValueTag::U1);
62 EXPECT_EQ(val_u1_zero.as<uint1_t>().value(), 0);
63
65 EXPECT_EQ(val_u8.get_tag(), ValueTag::U8);
66 EXPECT_EQ(val_u8.as<uint8_t>(), 42);
67
69 EXPECT_EQ(val_u16.get_tag(), ValueTag::U16);
70 EXPECT_EQ(val_u16.as<uint16_t>(), 42);
71
73 EXPECT_EQ(val_u32.get_tag(), ValueTag::U32);
74 EXPECT_EQ(val_u32.as<uint32_t>(), 42);
75
77 EXPECT_EQ(val_u64.get_tag(), ValueTag::U64);
78 EXPECT_EQ(val_u64.as<uint64_t>(), 42);
79
81 EXPECT_EQ(val_u128.get_tag(), ValueTag::U128);
82 EXPECT_EQ(val_u128.as<uint128_t>(), 42);
83
85 EXPECT_EQ(val_ff.get_tag(), ValueTag::FF);
86 EXPECT_EQ(val_ff.as<FF>(), value);
87}
88
89// Test from_tag_truncating method
90TEST(TaggedValueTest, FromTagTruncating)
91{
92 // U1 - truncates to 1 bit
93 auto val_u1 = TaggedValue::from_tag_truncating(ValueTag::U1, 3); // 3 = 1 mod 2
94 EXPECT_EQ(val_u1.get_tag(), ValueTag::U1);
95 EXPECT_EQ(val_u1.as<uint1_t>().value(), 1);
96
98 EXPECT_EQ(val_u1_zero.get_tag(), ValueTag::U1);
99 EXPECT_EQ(val_u1_zero.as<uint1_t>().value(), 0);
100
101 // U8 - truncates to 8 bits
103 EXPECT_EQ(val_u8.get_tag(), ValueTag::U8);
104 EXPECT_EQ(val_u8.as<uint8_t>(), 42);
105
106 auto val_u8_truncated = TaggedValue::from_tag_truncating(ValueTag::U8, 300); // 300 = 44 mod 256
107 EXPECT_EQ(val_u8_truncated.get_tag(), ValueTag::U8);
108 EXPECT_EQ(val_u8_truncated.as<uint8_t>(), 44);
109
110 // U16 - truncates to 16 bits
112 EXPECT_EQ(val_u16.get_tag(), ValueTag::U16);
113 EXPECT_EQ(val_u16.as<uint16_t>(), 1000);
114
115 auto val_u16_truncated = TaggedValue::from_tag_truncating(ValueTag::U16, 70000); // 70000 = 4464 mod 65536
116 EXPECT_EQ(val_u16_truncated.get_tag(), ValueTag::U16);
117 EXPECT_EQ(val_u16_truncated.as<uint16_t>(), 4464);
118
119 // U32 - truncates to 32 bits
120 auto val_u32 = TaggedValue::from_tag_truncating(ValueTag::U32, 100000);
121 EXPECT_EQ(val_u32.get_tag(), ValueTag::U32);
122 EXPECT_EQ(val_u32.as<uint32_t>(), 100000);
123
124 FF large_u32 = FF(uint256_t(1) << 33) + FF(42); // 2^33 + 42 = 42 mod 2^32
125 auto val_u32_truncated = TaggedValue::from_tag_truncating(ValueTag::U32, large_u32);
126 EXPECT_EQ(val_u32_truncated.get_tag(), ValueTag::U32);
127 EXPECT_EQ(val_u32_truncated.as<uint32_t>(), 42);
128
129 // U64 - truncates to 64 bits
130 auto val_u64 = TaggedValue::from_tag_truncating(ValueTag::U64, 1ULL << 40);
131 EXPECT_EQ(val_u64.get_tag(), ValueTag::U64);
132 EXPECT_EQ(val_u64.as<uint64_t>(), 1ULL << 40);
133
134 FF large_u64 = FF(uint256_t(1) << 65) + FF(123); // 2^65 + 123 = 123 mod 2^64
135 auto val_u64_truncated = TaggedValue::from_tag_truncating(ValueTag::U64, large_u64);
136 EXPECT_EQ(val_u64_truncated.get_tag(), ValueTag::U64);
137 EXPECT_EQ(val_u64_truncated.as<uint64_t>(), 123);
138
139 // U128 - truncates to 128 bits
141 EXPECT_EQ(val_u128.get_tag(), ValueTag::U128);
142 EXPECT_EQ(val_u128.as<uint128_t>(), uint128_t(1) << 100);
143
144 FF large_u128 = (uint256_t(1) << 129) + 456; // 2^129 + 456 = 456 mod 2^128
145 auto val_u128_truncated = TaggedValue::from_tag_truncating(ValueTag::U128, large_u128);
146 EXPECT_EQ(val_u128_truncated.get_tag(), ValueTag::U128);
147 EXPECT_EQ(val_u128_truncated.as<uint128_t>(), 456);
148
149 // FF - no truncation
150 FF large_ff = FF::random_element();
151 auto val_ff = TaggedValue::from_tag_truncating(ValueTag::FF, large_ff);
152 EXPECT_EQ(val_ff.get_tag(), ValueTag::FF);
153 EXPECT_EQ(val_ff.as<FF>(), large_ff);
154}
155
156// Test from_tag method with out of bounds values
157TEST(TaggedValueTest, FromTagOutOfBounds)
158{
159 // U8 - max value is 255
160 EXPECT_NO_THROW(TaggedValue::from_tag(ValueTag::U8, FF(255)));
161 EXPECT_THROW(TaggedValue::from_tag(ValueTag::U8, FF(256)), std::runtime_error);
162
163 // U16 - max value is 65535
164 EXPECT_NO_THROW(TaggedValue::from_tag(ValueTag::U16, FF(65535)));
165 EXPECT_THROW(TaggedValue::from_tag(ValueTag::U16, FF(65536)), std::runtime_error);
166
167 // U32 - max value is 2^32-1
168 EXPECT_NO_THROW(TaggedValue::from_tag(ValueTag::U32, FF((1ULL << 32) - 1)));
169 EXPECT_THROW(TaggedValue::from_tag(ValueTag::U32, FF(1ULL << 32)), std::runtime_error);
170
171 // U64 - max value is 2^64-1
172 FF max_u64 = FF(uint256_t((1ULL << 63)) * 2 - 1);
173 EXPECT_NO_THROW(TaggedValue::from_tag(ValueTag::U64, max_u64));
174 EXPECT_THROW(TaggedValue::from_tag(ValueTag::U64, max_u64 + FF(1)), std::runtime_error);
175
176 // U128 - max value is 2^128-1
177 FF max_u128 = FF(uint256_t(1) << 128) - FF(1);
178 EXPECT_NO_THROW(TaggedValue::from_tag(ValueTag::U128, max_u128));
179 EXPECT_THROW(TaggedValue::from_tag(ValueTag::U128, max_u128 + FF(1)), std::runtime_error);
180
181 // Invalid tag
182 EXPECT_THROW(TaggedValue::from_tag(static_cast<ValueTag>(100), FF(1)), std::runtime_error);
183}
184
185// Test as_ff method
186TEST(TaggedValueTest, AsFF)
187{
188 // Test conversion to FF from each type
189 auto val_u1 = TaggedValue::from<uint1_t>(1);
190 EXPECT_EQ(val_u1.as_ff(), FF(1));
191
192 auto val_u8 = TaggedValue::from<uint8_t>(42);
193 EXPECT_EQ(val_u8.as_ff(), FF(42));
194
195 auto val_u16 = TaggedValue::from<uint16_t>(1000);
196 EXPECT_EQ(val_u16.as_ff(), FF(1000));
197
198 auto val_u32 = TaggedValue::from<uint32_t>(100000);
199 EXPECT_EQ(val_u32.as_ff(), FF(100000));
200
201 auto val_u64 = TaggedValue::from<uint64_t>(1ULL << 40);
202 EXPECT_EQ(val_u64.as_ff(), FF(1ULL << 40));
203
204 // uint128 to FF
205 auto val_u128 = TaggedValue::from<uint128_t>(123);
206 EXPECT_EQ(val_u128.as_ff(), FF(123));
207
208 // FF to FF should be identity
209 FF field_val(123);
210 auto val_ff = TaggedValue::from<FF>(field_val);
211 EXPECT_EQ(val_ff.as_ff(), field_val);
212}
213
214// Test arithmetic operations for each type
215TEST(TaggedValueTest, ArithmeticOperations)
216{
217 // Test uint1_t operations
218 auto u1_val0 = TaggedValue::from<uint1_t>(0);
219 auto u1_val1 = TaggedValue::from<uint1_t>(1);
220
221 auto u1_add = u1_val1 + u1_val0;
222 EXPECT_EQ(u1_add.get_tag(), ValueTag::U1);
223 EXPECT_EQ(u1_add.as<uint1_t>().value(), 1);
224
225 auto u1_sub = u1_val1 - u1_val0;
226 EXPECT_EQ(u1_sub.get_tag(), ValueTag::U1);
227 EXPECT_EQ(u1_sub.as<uint1_t>().value(), 1);
228
229 auto u1_mul = u1_val1 * u1_val0;
230 EXPECT_EQ(u1_mul.get_tag(), ValueTag::U1);
231 EXPECT_EQ(u1_mul.as<uint1_t>().value(), 0);
232
233 // Division by zero would throw, so we'll test with non-zero
234 auto u1_div = u1_val1 / u1_val1;
235 EXPECT_EQ(u1_div.get_tag(), ValueTag::U1);
236 EXPECT_EQ(u1_div.as<uint1_t>().value(), 1);
237
238 // Test uint8_t operations
239 auto u8_val1 = TaggedValue::from<uint8_t>(40);
240 auto u8_val2 = TaggedValue::from<uint8_t>(2);
241
242 auto u8_add = u8_val1 + u8_val2;
243 EXPECT_EQ(u8_add.get_tag(), ValueTag::U8);
244 EXPECT_EQ(u8_add.as<uint8_t>(), 42);
245
246 auto u8_sub = u8_val1 - u8_val2;
247 EXPECT_EQ(u8_sub.get_tag(), ValueTag::U8);
248 EXPECT_EQ(u8_sub.as<uint8_t>(), 38);
249
250 auto u8_mul = u8_val1 * u8_val2;
251 EXPECT_EQ(u8_mul.get_tag(), ValueTag::U8);
252 EXPECT_EQ(u8_mul.as<uint8_t>(), 80);
253
254 auto u8_div = u8_val1 / u8_val2;
255 EXPECT_EQ(u8_div.get_tag(), ValueTag::U8);
256 EXPECT_EQ(u8_div.as<uint8_t>(), 20);
257
258 // Test uint16_t operations
259 auto u16_val1 = TaggedValue::from<uint16_t>(1000);
260 auto u16_val2 = TaggedValue::from<uint16_t>(10);
261
262 auto u16_add = u16_val1 + u16_val2;
263 EXPECT_EQ(u16_add.get_tag(), ValueTag::U16);
264 EXPECT_EQ(u16_add.as<uint16_t>(), 1010);
265
266 auto u16_sub = u16_val1 - u16_val2;
267 EXPECT_EQ(u16_sub.get_tag(), ValueTag::U16);
268 EXPECT_EQ(u16_sub.as<uint16_t>(), 990);
269
270 auto u16_mul = u16_val1 * u16_val2;
271 EXPECT_EQ(u16_mul.get_tag(), ValueTag::U16);
272 EXPECT_EQ(u16_mul.as<uint16_t>(), 10000);
273
274 auto u16_div = u16_val1 / u16_val2;
275 EXPECT_EQ(u16_div.get_tag(), ValueTag::U16);
276 EXPECT_EQ(u16_div.as<uint16_t>(), 100);
277
278 // Test uint32_t operations
279 auto u32_val1 = TaggedValue::from<uint32_t>(100000);
280 auto u32_val2 = TaggedValue::from<uint32_t>(25);
281
282 auto u32_add = u32_val1 + u32_val2;
283 EXPECT_EQ(u32_add.get_tag(), ValueTag::U32);
284 EXPECT_EQ(u32_add.as<uint32_t>(), 100025);
285
286 auto u32_sub = u32_val1 - u32_val2;
287 EXPECT_EQ(u32_sub.get_tag(), ValueTag::U32);
288 EXPECT_EQ(u32_sub.as<uint32_t>(), 99975);
289
290 auto u32_mul = u32_val1 * u32_val2;
291 EXPECT_EQ(u32_mul.get_tag(), ValueTag::U32);
292 EXPECT_EQ(u32_mul.as<uint32_t>(), 2500000);
293
294 auto u32_div = u32_val1 / u32_val2;
295 EXPECT_EQ(u32_div.get_tag(), ValueTag::U32);
296 EXPECT_EQ(u32_div.as<uint32_t>(), 4000);
297
298 // Test uint64_t operations
299 auto u64_val1 = TaggedValue::from<uint64_t>(1ULL << 32);
300 auto u64_val2 = TaggedValue::from<uint64_t>(5);
301
302 auto u64_add = u64_val1 + u64_val2;
303 EXPECT_EQ(u64_add.get_tag(), ValueTag::U64);
304 EXPECT_EQ(u64_add.as<uint64_t>(), (1ULL << 32) + 5);
305
306 auto u64_sub = u64_val1 - u64_val2;
307 EXPECT_EQ(u64_sub.get_tag(), ValueTag::U64);
308 EXPECT_EQ(u64_sub.as<uint64_t>(), (1ULL << 32) - 5);
309
310 auto u64_mul = u64_val1 * u64_val2;
311 EXPECT_EQ(u64_mul.get_tag(), ValueTag::U64);
312 EXPECT_EQ(u64_mul.as<uint64_t>(), (1ULL << 32) * 5);
313
314 auto u64_div = u64_val1 / u64_val2;
315 EXPECT_EQ(u64_div.get_tag(), ValueTag::U64);
316 EXPECT_EQ(u64_div.as<uint64_t>(), (1ULL << 32) / 5);
317
318 // Test uint128_t operations
319 auto u128_val1 = TaggedValue::from<uint128_t>(1000000000000ULL);
320 auto u128_val2 = TaggedValue::from<uint128_t>(7);
321
322 auto u128_add = u128_val1 + u128_val2;
323 EXPECT_EQ(u128_add.get_tag(), ValueTag::U128);
324 EXPECT_EQ(u128_add.as<uint128_t>(), uint128_t(1000000000000ULL) + uint128_t(7));
325
326 auto u128_sub = u128_val1 - u128_val2;
327 EXPECT_EQ(u128_sub.get_tag(), ValueTag::U128);
328 EXPECT_EQ(u128_sub.as<uint128_t>(), uint128_t(1000000000000ULL) - uint128_t(7));
329
330 auto u128_mul = u128_val1 * u128_val2;
331 EXPECT_EQ(u128_mul.get_tag(), ValueTag::U128);
332 EXPECT_EQ(u128_mul.as<uint128_t>(), uint128_t(1000000000000ULL) * uint128_t(7));
333
334 auto u128_div = u128_val1 / u128_val2;
335 EXPECT_EQ(u128_div.get_tag(), ValueTag::U128);
336 EXPECT_EQ(u128_div.as<uint128_t>(), uint128_t(1000000000000ULL) / uint128_t(7));
337
338 // Test arithmetic operations with FF
339 auto ff_val1 = TaggedValue::from<FF>(100);
340 auto ff_val2 = TaggedValue::from<FF>(5);
341
342 auto ff_add = ff_val1 + ff_val2;
343 EXPECT_EQ(ff_add.get_tag(), ValueTag::FF);
344 EXPECT_EQ(ff_add.as<FF>(), FF(105));
345
346 auto ff_sub = ff_val1 - ff_val2;
347 EXPECT_EQ(ff_sub.get_tag(), ValueTag::FF);
348 EXPECT_EQ(ff_sub.as<FF>(), FF(95));
349
350 auto ff_mul = ff_val1 * ff_val2;
351 EXPECT_EQ(ff_mul.get_tag(), ValueTag::FF);
352 EXPECT_EQ(ff_mul.as<FF>(), FF(500));
353
354 auto ff_div = ff_val1 / ff_val2;
355 EXPECT_EQ(ff_div.get_tag(), ValueTag::FF);
356 EXPECT_EQ(ff_div.as<FF>(), FF(20));
357}
358
359// Test bitwise operations
360TEST(TaggedValueTest, BitwiseOperations)
361{
362 // Test bitwise AND
363 auto u8_val1 = TaggedValue::from<uint8_t>(0b1010);
364 auto u8_val2 = TaggedValue::from<uint8_t>(0b1100);
365 auto u8_and = u8_val1 & u8_val2;
366 EXPECT_EQ(u8_and.get_tag(), ValueTag::U8);
367 EXPECT_EQ(u8_and.as<uint8_t>(), 0b1000);
368
369 // Test bitwise OR
370 auto u16_val1 = TaggedValue::from<uint16_t>(0b1010);
371 auto u16_val2 = TaggedValue::from<uint16_t>(0b1100);
372 auto u16_or = u16_val1 | u16_val2;
373 EXPECT_EQ(u16_or.get_tag(), ValueTag::U16);
374 EXPECT_EQ(u16_or.as<uint16_t>(), 0b1110);
375
376 // Test bitwise XOR
377 auto u32_val1 = TaggedValue::from<uint32_t>(0b1010);
378 auto u32_val2 = TaggedValue::from<uint32_t>(0b1100);
379 auto u32_xor = u32_val1 ^ u32_val2;
380 EXPECT_EQ(u32_xor.get_tag(), ValueTag::U32);
381 EXPECT_EQ(u32_xor.as<uint32_t>(), 0b0110);
382
383 // Test bitwise NOT
384 auto u64_val = TaggedValue::from<uint64_t>(0xFFFFFFFFFFFFFFF0ULL);
385 auto u64_not = ~u64_val;
386 EXPECT_EQ(u64_not.get_tag(), ValueTag::U64);
387 EXPECT_EQ(u64_not.as<uint64_t>(), 0x000000000000000FULL);
388
389 // Test shift operations
390 auto u8_shift = TaggedValue::from<uint8_t>(0b00000001);
391 auto u8_amount = TaggedValue::from<uint8_t>(2);
392
393 auto u8_shl = u8_shift << u8_amount;
394 EXPECT_EQ(u8_shl.get_tag(), ValueTag::U8);
395 EXPECT_EQ(u8_shl.as<uint8_t>(), 0b00000100);
396
397 auto u8_shift_high = TaggedValue::from<uint8_t>(0b10000000);
398 auto u8_shr = u8_shift_high >> u8_amount;
399 EXPECT_EQ(u8_shr.get_tag(), ValueTag::U8);
400 EXPECT_EQ(u8_shr.as<uint8_t>(), 0b00100000);
401}
402
403// Test unary operations for all types
404TEST(TaggedValueTest, UnaryOperations)
405{
406 // Test unary bit negation.
407 auto u1_val = TaggedValue::from<uint1_t>(1);
408 auto u1_not = ~u1_val;
409 EXPECT_EQ(u1_not.get_tag(), ValueTag::U1);
410 EXPECT_EQ(u1_not.as<uint1_t>().value(), 0);
411
412 auto u8_val = TaggedValue::from<uint8_t>(0xAA); // 10101010
413 auto u8_not = ~u8_val;
414 EXPECT_EQ(u8_not.get_tag(), ValueTag::U8);
415 EXPECT_EQ(u8_not.as<uint8_t>(), 0x55); // 01010101
416
417 auto u16_val = TaggedValue::from<uint16_t>(0xAAAA); // 1010101010101010
418 auto u16_not = ~u16_val;
419 EXPECT_EQ(u16_not.get_tag(), ValueTag::U16);
420 EXPECT_EQ(u16_not.as<uint16_t>(), 0x5555); // 0101010101010101
421
422 auto u32_val = TaggedValue::from<uint32_t>(0xAAAAAAAA); // 10101010...
423 auto u32_not = ~u32_val;
424 EXPECT_EQ(u32_not.get_tag(), ValueTag::U32);
425 EXPECT_EQ(u32_not.as<uint32_t>(), 0x55555555); // 01010101...
426
427 auto u64_val = TaggedValue::from<uint64_t>(0xAAAAAAAAAAAAAAAAULL);
428 auto u64_not = ~u64_val;
429 EXPECT_EQ(u64_not.get_tag(), ValueTag::U64);
430 EXPECT_EQ(u64_not.as<uint64_t>(), 0x5555555555555555ULL);
431
432 uint128_t u128_input = (uint128_t(0xAAAAAAAAAAAAAAAAULL) << 64) | uint128_t(0xAAAAAAAAAAAAAAAAULL);
433 auto u128_val = TaggedValue::from<uint128_t>(u128_input);
434 auto u128_not = ~u128_val;
435 EXPECT_EQ(u128_not.get_tag(), ValueTag::U128);
436 uint128_t expected_u128 = (uint128_t(0x5555555555555555ULL) << 64) | uint128_t(0x5555555555555555ULL);
437 EXPECT_EQ(u128_not.as<uint128_t>(), expected_u128);
438
439 // Test that unary bitwise operations on FF throw exceptions
440 auto ff_val = TaggedValue::from<FF>(123);
441 EXPECT_THROW(~ff_val, InvalidOperationTag);
442}
443
444// Test edge cases with uint1_t
445TEST(TaggedValueTest, Uint1EdgeCases)
446{
447 // Test uint1_t operations
448 auto u1_val0 = TaggedValue::from<uint1_t>(0);
449 auto u1_val1 = TaggedValue::from<uint1_t>(1);
450
451 // Bitwise operations
452 auto u1_and = u1_val1 & u1_val1;
453 EXPECT_EQ(u1_and.get_tag(), ValueTag::U1);
454 EXPECT_EQ(u1_and.as<uint1_t>().value(), 1);
455
456 auto u1_or = u1_val0 | u1_val1;
457 EXPECT_EQ(u1_or.get_tag(), ValueTag::U1);
458 EXPECT_EQ(u1_or.as<uint1_t>().value(), 1);
459
460 auto u1_xor = u1_val1 ^ u1_val1;
461 EXPECT_EQ(u1_xor.get_tag(), ValueTag::U1);
462 EXPECT_EQ(u1_xor.as<uint1_t>().value(), 0);
463
464 auto u1_not = ~u1_val1;
465 EXPECT_EQ(u1_not.get_tag(), ValueTag::U1);
466 EXPECT_EQ(u1_not.as<uint1_t>().value(), 0);
467}
468
469// Test error cases
470TEST(TaggedValueTest, ErrorCases)
471{
472 // Test type mismatch
473 auto u8_val = TaggedValue::from<uint8_t>(42);
474 EXPECT_THROW(u8_val.as<uint16_t>(), std::runtime_error);
475
476 // Test bitwise operations on FF (should throw)
477 auto ff_val1 = TaggedValue::from<FF>(10);
478 auto ff_val2 = TaggedValue::from<FF>(5);
479
480 EXPECT_THROW(ff_val1 & ff_val2, InvalidOperationTag);
481 EXPECT_THROW(ff_val1 | ff_val2, InvalidOperationTag);
482 EXPECT_THROW(ff_val1 ^ ff_val2, InvalidOperationTag);
483 EXPECT_THROW(ff_val1 >> ff_val2, InvalidOperationTag);
484 EXPECT_THROW(ff_val1 << ff_val2, InvalidOperationTag);
485 EXPECT_THROW(~ff_val1, InvalidOperationTag);
486
487 // Test mixed type operations
488 auto u8_val1 = TaggedValue::from<uint8_t>(10);
489 auto u16_val = TaggedValue::from<uint16_t>(5);
490
491 // Binary operations with different types should throw
492 EXPECT_THROW(u8_val1 + u16_val, TagMismatchException);
493 EXPECT_THROW(u8_val1 - u16_val, TagMismatchException);
494 EXPECT_THROW(u8_val1 * u16_val, TagMismatchException);
495 EXPECT_THROW(u8_val1 / u16_val, TagMismatchException);
496 EXPECT_THROW(u8_val1 & u16_val, TagMismatchException);
497 EXPECT_THROW(u8_val1 | u16_val, TagMismatchException);
498 EXPECT_THROW(u8_val1 ^ u16_val, TagMismatchException);
499 EXPECT_THROW(u8_val1 >> u16_val, TagMismatchException);
500 EXPECT_THROW(u8_val1 << u16_val, TagMismatchException);
501
502 // Dividing by zero should throw (see checked_divides)
503 EXPECT_THROW(TaggedValue::from<uint1_t>(1) / TaggedValue::from<uint1_t>(0), DivisionByZero);
504 EXPECT_THROW(u8_val1 / TaggedValue::from<uint8_t>(0), DivisionByZero);
505 EXPECT_THROW(u16_val / TaggedValue::from<uint16_t>(0), DivisionByZero);
506 EXPECT_THROW(TaggedValue::from<uint32_t>(1) / TaggedValue::from<uint32_t>(0), DivisionByZero);
507 EXPECT_THROW(TaggedValue::from<uint64_t>(1) / TaggedValue::from<uint64_t>(0), DivisionByZero);
508 EXPECT_THROW(TaggedValue::from<uint128_t>(1) / TaggedValue::from<uint128_t>(0), DivisionByZero);
509 EXPECT_THROW(ff_val1 / TaggedValue::from<FF>(0), DivisionByZero);
510}
511
512// Test shift operations
513TEST(TaggedValueTest, ShiftOperations)
514{
515 // Shift a uint1_t
516 auto u1_amount = TaggedValue::from<uint1_t>(1);
517 auto u1_shift = TaggedValue::from<uint1_t>(1);
518 auto result_shl_u1 = u1_amount << u1_shift;
519 ASSERT_EQ(result_shl_u1.get_tag(), ValueTag::U1);
520 EXPECT_EQ(result_shl_u1.as<uint1_t>(), static_cast<uint1_t>(0));
521
522 // Shift a uint8_t
523 auto u8_amount = TaggedValue::from<uint8_t>(3);
524 auto u8_shift = TaggedValue::from<uint8_t>(3);
525 auto result_shl_u8 = u8_amount << u8_shift;
526 ASSERT_EQ(result_shl_u8.get_tag(), ValueTag::U8);
527 EXPECT_EQ(result_shl_u8.as<uint8_t>(), 3 << 3);
528
529 // Shift a uint16_t
530 auto u16_amount = TaggedValue::from<uint16_t>(4);
531 auto u16_shift = TaggedValue::from<uint16_t>(3);
532 auto result_shl_u16 = u16_amount << u16_shift;
533 ASSERT_EQ(result_shl_u16.get_tag(), ValueTag::U16);
534 EXPECT_EQ(result_shl_u16.as<uint16_t>(), 4 << 3);
535
536 // Shift a uint32_t
537 auto u32_amount = TaggedValue::from<uint32_t>(4);
538 auto u32_shift = TaggedValue::from<uint32_t>(3);
539 auto result_shl_u32 = u32_amount << u32_shift;
540 ASSERT_EQ(result_shl_u32.get_tag(), ValueTag::U32);
541 EXPECT_EQ(result_shl_u32.as<uint32_t>(), 4 << 3);
542
543 // Shift a uint64_t
544 auto u64_amount = TaggedValue::from<uint64_t>(4);
545 auto u64_shift = TaggedValue::from<uint64_t>(3);
546 auto result_shl_u64 = u64_amount << u64_shift;
547 ASSERT_EQ(result_shl_u64.get_tag(), ValueTag::U64);
548 EXPECT_EQ(result_shl_u64.as<uint64_t>(), 4 << 3);
549
550 // Shift a uint128_t
551 auto u128_amount = TaggedValue::from<uint128_t>(4);
552 auto u128_shift = TaggedValue::from<uint128_t>(3);
553 auto result_shl_u128 = u128_amount << u128_shift;
554 ASSERT_EQ(result_shl_u128.get_tag(), ValueTag::U128);
555 EXPECT_EQ(result_shl_u128.as<uint128_t>(), 4 << 3);
556
557 // Test shift overflow
558 auto u8_shift_overflow = u8_amount << TaggedValue::from<uint8_t>(10);
559 EXPECT_EQ(u8_shift_overflow.get_tag(), ValueTag::U8);
560 EXPECT_EQ(u8_shift_overflow.as<uint8_t>(), 0);
561
562 auto u16_shift_overflow = u16_amount << TaggedValue::from<uint16_t>(17);
563 EXPECT_EQ(u16_shift_overflow.get_tag(), ValueTag::U16);
564 EXPECT_EQ(u16_shift_overflow.as<uint16_t>(), 0);
565
566 auto u32_shift_overflow = u32_amount << TaggedValue::from<uint32_t>(33);
567 EXPECT_EQ(u32_shift_overflow.get_tag(), ValueTag::U32);
568 EXPECT_EQ(u32_shift_overflow.as<uint32_t>(), 0);
569
570 auto u64_shift_overflow = u64_amount << TaggedValue::from<uint64_t>(65);
571 EXPECT_EQ(u64_shift_overflow.get_tag(), ValueTag::U64);
572 EXPECT_EQ(u64_shift_overflow.as<uint64_t>(), 0);
573
574 auto u128_shift_overflow = u128_amount << TaggedValue::from<uint128_t>(129);
575 EXPECT_EQ(u128_shift_overflow.get_tag(), ValueTag::U128);
576 EXPECT_EQ(u128_shift_overflow.as<uint128_t>(), 0);
577
578 u8_shift_overflow = u8_amount >> TaggedValue::from<uint8_t>(10);
579 EXPECT_EQ(u8_shift_overflow.get_tag(), ValueTag::U8);
580 EXPECT_EQ(u8_shift_overflow.as<uint8_t>(), 0);
581
582 u16_shift_overflow = u16_amount >> TaggedValue::from<uint16_t>(17);
583 EXPECT_EQ(u16_shift_overflow.get_tag(), ValueTag::U16);
584 EXPECT_EQ(u16_shift_overflow.as<uint16_t>(), 0);
585
586 u32_shift_overflow = u32_amount >> TaggedValue::from<uint32_t>(33);
587 EXPECT_EQ(u32_shift_overflow.get_tag(), ValueTag::U32);
588 EXPECT_EQ(u32_shift_overflow.as<uint32_t>(), 0);
589
590 u64_shift_overflow = u64_amount >> TaggedValue::from<uint64_t>(65);
591 EXPECT_EQ(u64_shift_overflow.get_tag(), ValueTag::U64);
592 EXPECT_EQ(u64_shift_overflow.as<uint64_t>(), 0);
593
594 u128_shift_overflow = u128_amount >> TaggedValue::from<uint128_t>(129);
595 EXPECT_EQ(u128_shift_overflow.get_tag(), ValueTag::U128);
596 EXPECT_EQ(u128_shift_overflow.as<uint128_t>(), 0);
597}
598
599// Test boundary cases for all types
600TEST(TaggedValueTest, BoundaryCases)
601{
602 // Test uint1_t overflow
603 auto u1_max = TaggedValue::from<uint1_t>(true);
604 auto u1_one = TaggedValue::from<uint1_t>(true);
605 auto u1_overflow = u1_max + u1_one;
606 EXPECT_EQ(u1_overflow.get_tag(), ValueTag::U1);
607 EXPECT_EQ(u1_overflow.as<uint1_t>().value(), 0); // 1+1=0 with overflow
608
609 // Test uint8_t overflow
610 auto u8_max = TaggedValue::from<uint8_t>(255);
611 auto u8_one = TaggedValue::from<uint8_t>(1);
612 auto u8_overflow = u8_max + u8_one;
613 EXPECT_EQ(u8_overflow.get_tag(), ValueTag::U8);
614 EXPECT_EQ(u8_overflow.as<uint8_t>(), 0); // Overflow wraps around
615
616 // Test uint16_t overflow
617 auto u16_max = TaggedValue::from<uint16_t>(65535);
618 auto u16_one = TaggedValue::from<uint16_t>(1);
619 auto u16_overflow = u16_max + u16_one;
620 EXPECT_EQ(u16_overflow.get_tag(), ValueTag::U16);
621 EXPECT_EQ(u16_overflow.as<uint16_t>(), 0); // Overflow wraps around
622
623 // Test uint32_t overflow
624 auto u32_max = TaggedValue::from<uint32_t>(4294967295U);
625 auto u32_one = TaggedValue::from<uint32_t>(1);
626 auto u32_overflow = u32_max + u32_one;
627 EXPECT_EQ(u32_overflow.get_tag(), ValueTag::U32);
628 EXPECT_EQ(u32_overflow.as<uint32_t>(), 0); // Overflow wraps around
629
630 // Test uint64_t overflow
631 auto u64_max = TaggedValue::from<uint64_t>(std::numeric_limits<uint64_t>::max());
632 auto u64_one = TaggedValue::from<uint64_t>(1);
633 auto u64_overflow = u64_max + u64_one;
634 EXPECT_EQ(u64_overflow.get_tag(), ValueTag::U64);
635 EXPECT_EQ(u64_overflow.as<uint64_t>(), 0); // Overflow wraps around
636
637 // Test uint128_t overflow
638 auto u128_max = TaggedValue::from<uint128_t>(~uint128_t(0));
639 auto u128_one = TaggedValue::from<uint128_t>(1);
640 auto u128_overflow = u128_max + u128_one;
641 EXPECT_EQ(u128_overflow.get_tag(), ValueTag::U128);
642 EXPECT_EQ(u128_overflow.as<uint128_t>(), 0); // Overflow wraps around
643
644 // Test underflow for all types
645 auto u1_zero = TaggedValue::from<uint1_t>(0);
646 auto u1_underflow = u1_zero - u1_one;
647 EXPECT_EQ(u1_underflow.get_tag(), ValueTag::U1);
648 EXPECT_EQ(u1_underflow.as<uint1_t>().value(), 1); // 0-1=1 with underflow
649
650 auto u8_zero = TaggedValue::from<uint8_t>(0);
651 auto u8_underflow = u8_zero - u8_one;
652 EXPECT_EQ(u8_underflow.get_tag(), ValueTag::U8);
653 EXPECT_EQ(u8_underflow.as<uint8_t>(), 255); // Underflow wraps around
654
655 auto u16_zero = TaggedValue::from<uint16_t>(0);
656 auto u16_underflow = u16_zero - u16_one;
657 EXPECT_EQ(u16_underflow.get_tag(), ValueTag::U16);
658 EXPECT_EQ(u16_underflow.as<uint16_t>(), 65535); // Underflow wraps around
659
660 auto u32_zero = TaggedValue::from<uint32_t>(0);
661 auto u32_underflow = u32_zero - u32_one;
662 EXPECT_EQ(u32_underflow.get_tag(), ValueTag::U32);
663 EXPECT_EQ(u32_underflow.as<uint32_t>(), 4294967295U); // Underflow wraps around
664
665 auto u64_zero = TaggedValue::from<uint64_t>(0);
666 auto u64_underflow = u64_zero - u64_one;
667 EXPECT_EQ(u64_underflow.get_tag(), ValueTag::U64);
668 EXPECT_EQ(u64_underflow.as<uint64_t>(), std::numeric_limits<uint64_t>::max()); // Underflow wraps around
669
670 auto u128_zero = TaggedValue::from<uint128_t>(0);
671 auto u128_underflow = u128_zero - u128_one;
672 EXPECT_EQ(u128_underflow.get_tag(), ValueTag::U128);
673 EXPECT_EQ(u128_underflow.as<uint128_t>(), ~uint128_t(0)); // Underflow wraps around
674
675 // Test multiplication overflow
676 auto u8_large = TaggedValue::from<uint8_t>(128);
677 auto u8_mul_overflow = u8_large * u8_large;
678 EXPECT_EQ(u8_mul_overflow.get_tag(), ValueTag::U8);
679 EXPECT_EQ(u8_mul_overflow.as<uint8_t>(), 0); // 128*128=16384, which is 0 mod 256
680
681 auto u16_large = TaggedValue::from<uint16_t>(256);
682 auto u16_mul_overflow = u16_large * u16_large;
683 EXPECT_EQ(u16_mul_overflow.get_tag(), ValueTag::U16);
684 EXPECT_EQ(u16_mul_overflow.as<uint16_t>(), 0); // 256*256=65536, which is 0 mod 65536
685
686 // Test shift overflow
687 auto u8_shift = TaggedValue::from<uint8_t>(1);
688 auto u8_shift_amount = TaggedValue::from<uint8_t>(8);
689 auto u8_shift_overflow = u8_shift << u8_shift_amount;
690 EXPECT_EQ(u8_shift_overflow.get_tag(), ValueTag::U8);
691 EXPECT_EQ(u8_shift_overflow.as<uint8_t>(), 0); // 1<<8=256, which is 0 mod 256
692
693 auto ff_large = TaggedValue::from<FF>(FF::modulus - FF(1));
694 auto ff_one = TaggedValue::from<FF>(1);
695 auto ff_wrap = ff_large + ff_one;
696 EXPECT_EQ(ff_wrap.get_tag(), ValueTag::FF);
697 EXPECT_EQ(ff_wrap.as<FF>(), FF(0)); // Modular arithmetic wraps naturally
698}
699
700// Test comparison operations
701TEST(TaggedValueTest, ComparisonOperations)
702{
703 auto u1_val1 = TaggedValue::from<uint1_t>(0);
704 auto u1_val2 = TaggedValue::from<uint1_t>(1);
705 auto u1_val3 = TaggedValue::from<uint1_t>(0);
706 EXPECT_TRUE(u1_val1 < u1_val2);
707 EXPECT_TRUE(u1_val1 == u1_val3);
708 EXPECT_TRUE(u1_val1 <= u1_val3);
709 EXPECT_TRUE(u1_val1 != u1_val2);
710
711 auto u8_val1 = TaggedValue::from<uint8_t>(42);
712 auto u8_val2 = TaggedValue::from<uint8_t>(100);
713 auto u8_val3 = TaggedValue::from<uint8_t>(42);
714 EXPECT_TRUE(u8_val1 < u8_val2);
715 EXPECT_TRUE(u8_val1 == u8_val3);
716 EXPECT_TRUE(u8_val1 <= u8_val3);
717 EXPECT_TRUE(u8_val1 != u8_val2);
718
719 auto u16_val1 = TaggedValue::from<uint16_t>(1000);
720 auto u16_val2 = TaggedValue::from<uint16_t>(2000);
721 auto u16_val3 = TaggedValue::from<uint16_t>(1000);
722 EXPECT_TRUE(u16_val1 < u16_val2);
723 EXPECT_TRUE(u16_val1 == u16_val3);
724 EXPECT_TRUE(u16_val1 <= u16_val3);
725 EXPECT_TRUE(u16_val1 != u16_val2);
726
727 auto u32_val1 = TaggedValue::from<uint32_t>(100000);
728 auto u32_val2 = TaggedValue::from<uint32_t>(200000);
729 auto u32_val3 = TaggedValue::from<uint32_t>(100000);
730 EXPECT_TRUE(u32_val1 < u32_val2);
731 EXPECT_TRUE(u32_val1 == u32_val3);
732 EXPECT_TRUE(u32_val1 <= u32_val3);
733 EXPECT_TRUE(u32_val1 != u32_val2);
734
735 auto u64_val1 = TaggedValue::from<uint64_t>(1ULL << 40);
736 auto u64_val2 = TaggedValue::from<uint64_t>(1ULL << 41);
737 auto u64_val3 = TaggedValue::from<uint64_t>(1ULL << 40);
738 EXPECT_TRUE(u64_val1 < u64_val2);
739 EXPECT_TRUE(u64_val1 == u64_val3);
740 EXPECT_TRUE(u64_val1 <= u64_val3);
741 EXPECT_TRUE(u64_val1 != u64_val2);
742
743 auto u128_val1 = TaggedValue::from<uint128_t>(static_cast<uint128_t>(1) << 100);
744 auto u128_val2 = TaggedValue::from<uint128_t>(static_cast<uint128_t>(1) << 101);
745 auto u128_val3 = TaggedValue::from<uint128_t>(static_cast<uint128_t>(1) << 100);
746 EXPECT_TRUE(u128_val1 < u128_val2);
747 EXPECT_TRUE(u128_val1 == u128_val3);
748 EXPECT_TRUE(u128_val1 <= u128_val3);
749 EXPECT_TRUE(u128_val1 != u128_val2);
750
751 auto ff_val1 = TaggedValue::from<FF>(FF(42));
752 auto ff_val2 = TaggedValue::from<FF>(FF(100));
753 auto ff_val3 = TaggedValue::from<FF>(FF(42));
754 EXPECT_TRUE(ff_val1 < ff_val2);
755 EXPECT_TRUE(ff_val1 == ff_val3);
756 EXPECT_TRUE(ff_val1 <= ff_val3);
757 EXPECT_TRUE(ff_val1 != ff_val2);
758
759 // Comparisons on different types should return false
760 EXPECT_FALSE(u1_val1 < u8_val1);
761 EXPECT_FALSE(u8_val1 <= u16_val1);
762 EXPECT_FALSE(u16_val1 == u32_val1);
763 EXPECT_FALSE(u32_val1 != u64_val1);
764}
765
766} // namespace
767} // namespace bb::avm2
static TaggedValue from_tag_truncating(ValueTag tag, FF value)
static TaggedValue from_tag(ValueTag tag, FF value)
static constexpr uint256_t from_uint128(const uint128_t a) noexcept
Definition uint256.hpp:94
TEST(EmitUnencryptedLogTest, Basic)
AvmFlavorSettings::FF FF
Definition field.hpp:10
unsigned __int128 uint128_t
Definition serialize.hpp:44
static constexpr uint256_t modulus
static field random_element(numeric::RNG *engine=nullptr) noexcept