Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
uint256_impl.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Luke], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
8#include "../bitop/get_msb.hpp"
9#include "./uint256.hpp"
12namespace bb::numeric {
13
14constexpr std::pair<uint64_t, uint64_t> uint256_t::mul_wide(const uint64_t a, const uint64_t b)
15{
16 const uint64_t a_lo = a & 0xffffffffULL;
17 const uint64_t a_hi = a >> 32ULL;
18 const uint64_t b_lo = b & 0xffffffffULL;
19 const uint64_t b_hi = b >> 32ULL;
20
21 const uint64_t lo_lo = a_lo * b_lo;
22 const uint64_t hi_lo = a_hi * b_lo;
23 const uint64_t lo_hi = a_lo * b_hi;
24 const uint64_t hi_hi = a_hi * b_hi;
25
26 const uint64_t cross = (lo_lo >> 32ULL) + (hi_lo & 0xffffffffULL) + lo_hi;
27
28 return { (cross << 32ULL) | (lo_lo & 0xffffffffULL), (hi_lo >> 32ULL) + (cross >> 32ULL) + hi_hi };
29}
30
31// compute a + b + carry, returning the carry
32constexpr std::pair<uint64_t, uint64_t> uint256_t::addc(const uint64_t a, const uint64_t b, const uint64_t carry_in)
33{
34 const uint64_t sum = a + b;
35 const auto carry_temp = static_cast<uint64_t>(sum < a);
36 const uint64_t r = sum + carry_in;
37 const uint64_t carry_out = carry_temp + static_cast<uint64_t>(r < carry_in);
38 return { r, carry_out };
39}
40
41constexpr uint64_t uint256_t::addc_discard_hi(const uint64_t a, const uint64_t b, const uint64_t carry_in)
42{
43 return a + b + carry_in;
44}
45
46constexpr std::pair<uint64_t, uint64_t> uint256_t::sbb(const uint64_t a, const uint64_t b, const uint64_t borrow_in)
47{
48 const uint64_t t_1 = a - (borrow_in >> 63ULL);
49 const auto borrow_temp_1 = static_cast<uint64_t>(t_1 > a);
50 const uint64_t t_2 = t_1 - b;
51 const auto borrow_temp_2 = static_cast<uint64_t>(t_2 > t_1);
52
53 return { t_2, 0ULL - (borrow_temp_1 | borrow_temp_2) };
54}
55
56constexpr uint64_t uint256_t::sbb_discard_hi(const uint64_t a, const uint64_t b, const uint64_t borrow_in)
57{
58 return a - b - (borrow_in >> 63ULL);
59}
60
61// {r, carry_out} = a + carry_in + b * c
63 const uint64_t b,
64 const uint64_t c,
65 const uint64_t carry_in)
66{
68 result.first += a;
69 const auto overflow_c = static_cast<uint64_t>(result.first < a);
70 result.first += carry_in;
71 const auto overflow_carry = static_cast<uint64_t>(result.first < carry_in);
72 result.second += (overflow_c + overflow_carry);
73 return result;
74}
75
76constexpr uint64_t uint256_t::mac_discard_hi(const uint64_t a,
77 const uint64_t b,
78 const uint64_t c,
79 const uint64_t carry_in)
80{
81 return (b * c + a + carry_in);
82}
83#if defined(__wasm__) || !defined(__SIZEOF_INT128__)
84
89constexpr void uint256_t::wasm_madd(const uint64_t& left_limb,
90 const uint64_t* right_limbs,
91 uint64_t& result_0,
92 uint64_t& result_1,
93 uint64_t& result_2,
94 uint64_t& result_3,
95 uint64_t& result_4,
96 uint64_t& result_5,
97 uint64_t& result_6,
98 uint64_t& result_7,
99 uint64_t& result_8)
100{
101 result_0 += left_limb * right_limbs[0];
102 result_1 += left_limb * right_limbs[1];
103 result_2 += left_limb * right_limbs[2];
104 result_3 += left_limb * right_limbs[3];
105 result_4 += left_limb * right_limbs[4];
106 result_5 += left_limb * right_limbs[5];
107 result_6 += left_limb * right_limbs[6];
108 result_7 += left_limb * right_limbs[7];
109 result_8 += left_limb * right_limbs[8];
110}
111
117{
118 // 0x1fffffff == 2^30 - 1
119 return {
120 data[0] & 0x1fffffff, // bits [0, 29) from data[0]
121 (data[0] >> 29) & 0x1fffffff, // bits [29, 58) from data[0]
122 ((data[0] >> 58) & 0x3f) |
123 ((data[1] & 0x7fffff) << 6), // bits [58, 64) from data[0] + bits [0, 23) from data[1]
124 (data[1] >> 23) & 0x1fffffff, // bits [23, 52) from data[1]
125 ((data[1] >> 52) & 0xfff) |
126 ((data[2] & 0x1ffff) << 12), // bits [52, 64) from data[1] + bits [0, 17) from data[2]
127 (data[2] >> 17) & 0x1fffffff, // bits [17, 46) from data[2]
128 ((data[2] >> 46) & 0x3ffff) |
129 ((data[3] & 0x7ff) << 18), // bits [46, 64) from data[2] + bits [0, 11) from data[3]
130 (data[3] >> 11) & 0x1fffffff, // bits [11, 40) from data[3]
131 (data[3] >> 40) & 0x1fffffff // bits [40, 64) from data[3]
132 };
133}
134#endif
136{
137 if (b == 0) {
138 throw_or_abort("uint256_t::divmod: divisor must be nonzero");
139 }
140 if (*this == 0) {
141 return { 0, 0 };
142 }
143 if (b == 1) {
144 return { *this, 0 };
145 }
146 if (*this == b) {
147 return { 1, 0 };
148 }
149 if (b > *this) {
150 return { 0, *this };
151 }
152
153 uint256_t quotient = 0;
154 uint256_t remainder = *this;
155
156 uint64_t bit_difference = get_msb() - b.get_msb();
157
158 uint256_t divisor = b << bit_difference;
159 uint256_t accumulator = uint256_t(1) << bit_difference;
160
161 // if the divisor is bigger than the remainder, a and b have the same bit length
162 if (divisor > remainder) {
163 divisor >>= 1;
164 accumulator >>= 1;
165 }
166
167 // while the remainder is bigger than our original divisor, we can subtract multiples of b from the remainder,
168 // and add to the quotient
169 while (remainder >= b) {
170
171 // we've shunted 'divisor' up to have the same bit length as our remainder.
172 // If remainder >= divisor, then a is at least '1 << bit_difference' multiples of b
173 if (remainder >= divisor) {
174 remainder -= divisor;
175 // we can use OR here instead of +, as
176 // accumulator is always a nice power of two
177 quotient |= accumulator;
178 }
179 divisor >>= 1;
180 accumulator >>= 1;
181 }
182
183 return { quotient, remainder };
184}
185
194{
195 if (b == 0) {
196 throw_or_abort("uint256_t::divmod: divisor must be nonzero");
197 }
198 if (*this == 0) {
199 return { 0, 0 };
200 }
201 if (b == 1) {
202 return { *this, 0 };
203 }
204
205#if !defined(__wasm__)
206 uint256_t quotient;
207 uint64_t remainder = 0;
208 for (int i = 3; i >= 0; --i) {
209 uint128_t cur = (static_cast<uint128_t>(remainder) << 64) | data[i];
210 quotient.data[i] = static_cast<uint64_t>(cur / b);
211 remainder = static_cast<uint64_t>(cur % b);
212 }
213 return { quotient, remainder };
214#else
215 // Fallback to the general divmod since wasm doesn't have native support for 128-bit instructions.
216 auto [q, r] = divmod(uint256_t(b));
217 return { q, static_cast<uint64_t>(r.data[0]) };
218#endif
219}
220
226{
227#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
228 const auto [r0, t0] = mul_wide(data[0], other.data[0]);
229 const auto [q0, t1] = mac(t0, data[0], other.data[1], 0);
230 const auto [q1, t2] = mac(t1, data[0], other.data[2], 0);
231 const auto [q2, z0] = mac(t2, data[0], other.data[3], 0);
232
233 const auto [r1, t3] = mac(q0, data[1], other.data[0], 0);
234 const auto [q3, t4] = mac(q1, data[1], other.data[1], t3);
235 const auto [q4, t5] = mac(q2, data[1], other.data[2], t4);
236 const auto [q5, z1] = mac(z0, data[1], other.data[3], t5);
237
238 const auto [r2, t6] = mac(q3, data[2], other.data[0], 0);
239 const auto [q6, t7] = mac(q4, data[2], other.data[1], t6);
240 const auto [q7, t8] = mac(q5, data[2], other.data[2], t7);
241 const auto [q8, z2] = mac(z1, data[2], other.data[3], t8);
242
243 const auto [r3, t9] = mac(q6, data[3], other.data[0], 0);
244 const auto [r4, t10] = mac(q7, data[3], other.data[1], t9);
245 const auto [r5, t11] = mac(q8, data[3], other.data[2], t10);
246 const auto [r6, r7] = mac(z2, data[3], other.data[3], t11);
247
248 uint256_t lo(r0, r1, r2, r3);
249 uint256_t hi(r4, r5, r6, r7);
250 return { lo, hi };
251#else
252 // Convert 4 64-bit limbs to 9 29-bit limbs
253 const auto left = wasm_convert(data);
254 const auto right = wasm_convert(other.data);
255 constexpr uint64_t mask = 0x1fffffff;
256 uint64_t temp_0 = 0;
257 uint64_t temp_1 = 0;
258 uint64_t temp_2 = 0;
259 uint64_t temp_3 = 0;
260 uint64_t temp_4 = 0;
261 uint64_t temp_5 = 0;
262 uint64_t temp_6 = 0;
263 uint64_t temp_7 = 0;
264 uint64_t temp_8 = 0;
265 uint64_t temp_9 = 0;
266 uint64_t temp_10 = 0;
267 uint64_t temp_11 = 0;
268 uint64_t temp_12 = 0;
269 uint64_t temp_13 = 0;
270 uint64_t temp_14 = 0;
271 uint64_t temp_15 = 0;
272 uint64_t temp_16 = 0;
273
274 // Multiply and addd all limbs
275 wasm_madd(left[0], &right[0], temp_0, temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8);
276 wasm_madd(left[1], &right[0], temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9);
277 wasm_madd(left[2], &right[0], temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10);
278 wasm_madd(left[3], &right[0], temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11);
279 wasm_madd(left[4], &right[0], temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12);
280 wasm_madd(left[5], &right[0], temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13);
281 wasm_madd(left[6], &right[0], temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14);
282 wasm_madd(left[7], &right[0], temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15);
283 wasm_madd(left[8], &right[0], temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15, temp_16);
284
285 // Convert from relaxed form into strict 29-bit form (except for temp_16)
286 temp_1 += temp_0 >> WASM_LIMB_BITS;
287 temp_0 &= mask;
288 temp_2 += temp_1 >> WASM_LIMB_BITS;
289 temp_1 &= mask;
290 temp_3 += temp_2 >> WASM_LIMB_BITS;
291 temp_2 &= mask;
292 temp_4 += temp_3 >> WASM_LIMB_BITS;
293 temp_3 &= mask;
294 temp_5 += temp_4 >> WASM_LIMB_BITS;
295 temp_4 &= mask;
296 temp_6 += temp_5 >> WASM_LIMB_BITS;
297 temp_5 &= mask;
298 temp_7 += temp_6 >> WASM_LIMB_BITS;
299 temp_6 &= mask;
300 temp_8 += temp_7 >> WASM_LIMB_BITS;
301 temp_7 &= mask;
302 temp_9 += temp_8 >> WASM_LIMB_BITS;
303 temp_8 &= mask;
304 temp_10 += temp_9 >> WASM_LIMB_BITS;
305 temp_9 &= mask;
306 temp_11 += temp_10 >> WASM_LIMB_BITS;
307 temp_10 &= mask;
308 temp_12 += temp_11 >> WASM_LIMB_BITS;
309 temp_11 &= mask;
310 temp_13 += temp_12 >> WASM_LIMB_BITS;
311 temp_12 &= mask;
312 temp_14 += temp_13 >> WASM_LIMB_BITS;
313 temp_13 &= mask;
314 temp_15 += temp_14 >> WASM_LIMB_BITS;
315 temp_14 &= mask;
316 temp_16 += temp_15 >> WASM_LIMB_BITS;
317 temp_15 &= mask;
318
319 // Convert to 2 4-64-bit limb uint256_t objects
320 return { { (temp_0 << 0) | (temp_1 << 29) | (temp_2 << 58),
321 (temp_2 >> 6) | (temp_3 << 23) | (temp_4 << 52),
322 (temp_4 >> 12) | (temp_5 << 17) | (temp_6 << 46),
323 (temp_6 >> 18) | (temp_7 << 11) | (temp_8 << 40) },
324 { (temp_8 >> 24) | (temp_9 << 5) | (temp_10 << 34) | (temp_11 << 63),
325 (temp_11 >> 1) | (temp_12 << 28) | (temp_13 << 57),
326 (temp_13 >> 7) | (temp_14 << 22) | (temp_15 << 51),
327 (temp_15 >> 13) | (temp_16 << 16) } };
328#endif
329}
330
336constexpr uint256_t uint256_t::slice(const uint64_t start, const uint64_t end) const
337{
338 // Plain assert is used here because BB_ASSERT_DEBUG defines a std::ostringstream, which is
339 // a non-literal type and therefore disallowed in the body of a constexpr function before C++23.
340 assert(start <= end);
341 const uint64_t range = end - start;
342 const uint256_t mask = (range == 256) ? -uint256_t(1) : (uint256_t(1) << range) - 1;
343 return ((*this) >> start) & mask;
344}
345
346constexpr uint256_t uint256_t::pow(const uint256_t& exponent) const
347{
348 uint256_t accumulator{ data[0], data[1], data[2], data[3] };
349 uint256_t to_mul{ data[0], data[1], data[2], data[3] };
350 const uint64_t maximum_set_bit = exponent.get_msb();
351
352 for (int i = static_cast<int>(maximum_set_bit) - 1; i >= 0; --i) {
353 accumulator *= accumulator;
354 if (exponent.get_bit(static_cast<uint64_t>(i))) {
355 accumulator *= to_mul;
356 }
357 }
358 if (exponent == uint256_t(0)) {
359 accumulator = uint256_t(1);
360 } else if (*this == uint256_t(0)) {
361 accumulator = uint256_t(0);
362 }
363 return accumulator;
364}
365
366constexpr bool uint256_t::get_bit(const uint64_t bit_index) const
367{
368 if (bit_index > 255) {
369 return static_cast<bool>(0);
370 }
371 const auto idx = static_cast<size_t>(bit_index >> 6);
372 const size_t shift = bit_index & 63;
373 return static_cast<bool>((data[idx] >> shift) & 1);
374}
375
376constexpr uint64_t uint256_t::get_msb() const
377{
378 uint64_t idx = numeric::get_msb(data[3]);
379 idx = (idx == 0 && data[3] == 0) ? numeric::get_msb(data[2]) : idx + 64;
380 idx = (idx == 0 && data[2] == 0) ? numeric::get_msb(data[1]) : idx + 64;
381 idx = (idx == 0 && data[1] == 0) ? numeric::get_msb(data[0]) : idx + 64;
382 return idx;
383}
384
385constexpr uint256_t uint256_t::operator+(const uint256_t& other) const
386{
387 const auto [r0, t0] = addc(data[0], other.data[0], 0);
388 const auto [r1, t1] = addc(data[1], other.data[1], t0);
389 const auto [r2, t2] = addc(data[2], other.data[2], t1);
390 const auto r3 = addc_discard_hi(data[3], other.data[3], t2);
391 return { r0, r1, r2, r3 };
392};
393
394constexpr uint256_t uint256_t::operator-(const uint256_t& other) const
395{
396
397 const auto [r0, t0] = sbb(data[0], other.data[0], 0);
398 const auto [r1, t1] = sbb(data[1], other.data[1], t0);
399 const auto [r2, t2] = sbb(data[2], other.data[2], t1);
400 const auto r3 = sbb_discard_hi(data[3], other.data[3], t2);
401 return { r0, r1, r2, r3 };
402}
403
405{
406 return uint256_t(0) - *this;
407}
408
409constexpr uint256_t uint256_t::operator*(const uint256_t& other) const
410{
411
412#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
413 const auto [r0, t0] = mac(0, data[0], other.data[0], 0ULL);
414 const auto [q0, t1] = mac(0, data[0], other.data[1], t0);
415 const auto [q1, t2] = mac(0, data[0], other.data[2], t1);
416 const auto q2 = mac_discard_hi(0, data[0], other.data[3], t2);
417
418 const auto [r1, t3] = mac(q0, data[1], other.data[0], 0ULL);
419 const auto [q3, t4] = mac(q1, data[1], other.data[1], t3);
420 const auto q4 = mac_discard_hi(q2, data[1], other.data[2], t4);
421
422 const auto [r2, t5] = mac(q3, data[2], other.data[0], 0ULL);
423 const auto q5 = mac_discard_hi(q4, data[2], other.data[1], t5);
424
425 const auto r3 = mac_discard_hi(q5, data[3], other.data[0], 0ULL);
426
427 return { r0, r1, r2, r3 };
428#else
429 // Convert 4 64-bit limbs to 9 29-bit limbs
430 const auto left = wasm_convert(data);
431 const auto right = wasm_convert(other.data);
432 uint64_t temp_0 = 0;
433 uint64_t temp_1 = 0;
434 uint64_t temp_2 = 0;
435 uint64_t temp_3 = 0;
436 uint64_t temp_4 = 0;
437 uint64_t temp_5 = 0;
438 uint64_t temp_6 = 0;
439 uint64_t temp_7 = 0;
440 uint64_t temp_8 = 0;
441
442 // Multiply and add the product of left limb 0 by all right limbs
443 wasm_madd(left[0], &right[0], temp_0, temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8);
444 // Multiply left limb 1 by limbs 0-7 ((1,8) doesn't need to be computed, because it overflows)
445 temp_1 += left[1] * right[0];
446 temp_2 += left[1] * right[1];
447 temp_3 += left[1] * right[2];
448 temp_4 += left[1] * right[3];
449 temp_5 += left[1] * right[4];
450 temp_6 += left[1] * right[5];
451 temp_7 += left[1] * right[6];
452 temp_8 += left[1] * right[7];
453 // Left limb 2 by right 0-6, etc
454 temp_2 += left[2] * right[0];
455 temp_3 += left[2] * right[1];
456 temp_4 += left[2] * right[2];
457 temp_5 += left[2] * right[3];
458 temp_6 += left[2] * right[4];
459 temp_7 += left[2] * right[5];
460 temp_8 += left[2] * right[6];
461 temp_3 += left[3] * right[0];
462 temp_4 += left[3] * right[1];
463 temp_5 += left[3] * right[2];
464 temp_6 += left[3] * right[3];
465 temp_7 += left[3] * right[4];
466 temp_8 += left[3] * right[5];
467 temp_4 += left[4] * right[0];
468 temp_5 += left[4] * right[1];
469 temp_6 += left[4] * right[2];
470 temp_7 += left[4] * right[3];
471 temp_8 += left[4] * right[4];
472 temp_5 += left[5] * right[0];
473 temp_6 += left[5] * right[1];
474 temp_7 += left[5] * right[2];
475 temp_8 += left[5] * right[3];
476 temp_6 += left[6] * right[0];
477 temp_7 += left[6] * right[1];
478 temp_8 += left[6] * right[2];
479 temp_7 += left[7] * right[0];
480 temp_8 += left[7] * right[1];
481 temp_8 += left[8] * right[0];
482
483 // Convert from relaxed form to strict 29-bit form
484 constexpr uint64_t mask = 0x1fffffff;
485 temp_1 += temp_0 >> WASM_LIMB_BITS;
486 temp_0 &= mask;
487 temp_2 += temp_1 >> WASM_LIMB_BITS;
488 temp_1 &= mask;
489 temp_3 += temp_2 >> WASM_LIMB_BITS;
490 temp_2 &= mask;
491 temp_4 += temp_3 >> WASM_LIMB_BITS;
492 temp_3 &= mask;
493 temp_5 += temp_4 >> WASM_LIMB_BITS;
494 temp_4 &= mask;
495 temp_6 += temp_5 >> WASM_LIMB_BITS;
496 temp_5 &= mask;
497 temp_7 += temp_6 >> WASM_LIMB_BITS;
498 temp_6 &= mask;
499 temp_8 += temp_7 >> WASM_LIMB_BITS;
500 temp_7 &= mask;
501
502 // Convert back to 4 64-bit limbs
503 return { (temp_0 << 0) | (temp_1 << 29) | (temp_2 << 58),
504 (temp_2 >> 6) | (temp_3 << 23) | (temp_4 << 52),
505 (temp_4 >> 12) | (temp_5 << 17) | (temp_6 << 46),
506 (temp_6 >> 18) | (temp_7 << 11) | (temp_8 << 40) };
507#endif
508}
509
510constexpr uint256_t uint256_t::operator/(const uint256_t& other) const
511{
512 return divmod(other).first;
513}
514
515constexpr uint256_t uint256_t::operator%(const uint256_t& other) const
516{
517 return divmod(other).second;
518}
519
520constexpr uint256_t uint256_t::operator&(const uint256_t& other) const
521{
522 return { data[0] & other.data[0], data[1] & other.data[1], data[2] & other.data[2], data[3] & other.data[3] };
523}
524
525constexpr uint256_t uint256_t::operator^(const uint256_t& other) const
526{
527 return { data[0] ^ other.data[0], data[1] ^ other.data[1], data[2] ^ other.data[2], data[3] ^ other.data[3] };
528}
529
530constexpr uint256_t uint256_t::operator|(const uint256_t& other) const
531{
532 return { data[0] | other.data[0], data[1] | other.data[1], data[2] | other.data[2], data[3] | other.data[3] };
533}
534
536{
537 return { ~data[0], ~data[1], ~data[2], ~data[3] };
538}
539
540constexpr bool uint256_t::operator==(const uint256_t& other) const
541{
542 return data[0] == other.data[0] && data[1] == other.data[1] && data[2] == other.data[2] && data[3] == other.data[3];
543}
544
545constexpr bool uint256_t::operator!=(const uint256_t& other) const
546{
547 return !(*this == other);
548}
549
550constexpr bool uint256_t::operator!() const
551{
552 return *this == uint256_t(0ULL);
553}
554
555constexpr bool uint256_t::operator>(const uint256_t& other) const
556{
557 bool t0 = data[3] > other.data[3];
558 bool t1 = data[3] == other.data[3] && data[2] > other.data[2];
559 bool t2 = data[3] == other.data[3] && data[2] == other.data[2] && data[1] > other.data[1];
560 bool t3 =
561 data[3] == other.data[3] && data[2] == other.data[2] && data[1] == other.data[1] && data[0] > other.data[0];
562 return t0 || t1 || t2 || t3;
563}
564
565constexpr bool uint256_t::operator>=(const uint256_t& other) const
566{
567 return (*this > other) || (*this == other);
568}
569
570constexpr bool uint256_t::operator<(const uint256_t& other) const
571{
572 return other > *this;
573}
574
575constexpr bool uint256_t::operator<=(const uint256_t& other) const
576{
577 return (*this < other) || (*this == other);
578}
579
580constexpr uint256_t uint256_t::operator>>(const uint256_t& other) const
581{
582 uint64_t total_shift = other.data[0];
583
584 if (total_shift >= 256 || (other.data[1] != 0U) || (other.data[2] != 0U) || (other.data[3] != 0U)) {
585 return 0;
586 }
587
588 if (total_shift == 0) {
589 return *this;
590 }
591
592 uint64_t num_shifted_limbs = total_shift >> 6ULL;
593 uint64_t limb_shift = total_shift & 63ULL;
594
595 std::array<uint64_t, 4> shifted_limbs = { 0, 0, 0, 0 };
596
597 if (limb_shift == 0) {
598 shifted_limbs[0] = data[0];
599 shifted_limbs[1] = data[1];
600 shifted_limbs[2] = data[2];
601 shifted_limbs[3] = data[3];
602 } else {
603 uint64_t remainder_shift = 64ULL - limb_shift;
604
605 shifted_limbs[3] = data[3] >> limb_shift;
606
607 uint64_t remainder = (data[3]) << remainder_shift;
608
609 shifted_limbs[2] = (data[2] >> limb_shift) + remainder;
610
611 remainder = (data[2]) << remainder_shift;
612
613 shifted_limbs[1] = (data[1] >> limb_shift) + remainder;
614
615 remainder = (data[1]) << remainder_shift;
616
617 shifted_limbs[0] = (data[0] >> limb_shift) + remainder;
618 }
619 uint256_t result(0);
620
621 for (size_t i = 0; i < 4 - num_shifted_limbs; ++i) {
622 result.data[i] = shifted_limbs[static_cast<size_t>(i + num_shifted_limbs)];
623 }
624
625 return result;
626}
627
628constexpr uint256_t uint256_t::operator<<(const uint256_t& other) const
629{
630 uint64_t total_shift = other.data[0];
631
632 if (total_shift >= 256 || (other.data[1] != 0U) || (other.data[2] != 0U) || (other.data[3] != 0U)) {
633 return 0;
634 }
635
636 if (total_shift == 0) {
637 return *this;
638 }
639 uint64_t num_shifted_limbs = total_shift >> 6ULL;
640 uint64_t limb_shift = total_shift & 63ULL;
641
642 std::array<uint64_t, 4> shifted_limbs = { 0, 0, 0, 0 };
643
644 if (limb_shift == 0) {
645 shifted_limbs[0] = data[0];
646 shifted_limbs[1] = data[1];
647 shifted_limbs[2] = data[2];
648 shifted_limbs[3] = data[3];
649 } else {
650 uint64_t remainder_shift = 64ULL - limb_shift;
651
652 shifted_limbs[0] = data[0] << limb_shift;
653
654 uint64_t remainder = data[0] >> remainder_shift;
655
656 shifted_limbs[1] = (data[1] << limb_shift) + remainder;
657
658 remainder = data[1] >> remainder_shift;
659
660 shifted_limbs[2] = (data[2] << limb_shift) + remainder;
661
662 remainder = data[2] >> remainder_shift;
663
664 shifted_limbs[3] = (data[3] << limb_shift) + remainder;
665 }
666 uint256_t result(0);
667
668 for (size_t i = 0; i < 4 - num_shifted_limbs; ++i) {
669 result.data[static_cast<size_t>(i + num_shifted_limbs)] = shifted_limbs[i];
670 }
671
672 return result;
673}
674
675// For serialization
676void uint256_t::msgpack_pack(auto& packer) const
677{
678 // The data is then converted to big endian format using htonll, which stands for "host to network long
679 // long". This is necessary because the data will be written to a raw msgpack buffer, which requires big
680 // endian format.
681 uint64_t bin_data[4] = { htonll(data[3]), htonll(data[2]), htonll(data[1]), htonll(data[0]) };
682
683 // The packer is then used to write the binary data to the buffer, just like in read() and write() methods.
684 packer.pack_bin(sizeof(bin_data));
685 packer.pack_bin_body((const char*)bin_data, sizeof(bin_data)); // NOLINT
686}
687
688// For serialization
690{
691 // The binary data is first extracted from the msgpack object.
692 std::array<uint8_t, sizeof(data)> raw_data = o;
693
694 // The binary data is then read as big endian uint64_t's. This is done by casting the raw data to uint64_t*
695 // and then using ntohll ("network to host long long") to correct the endianness to the host's endianness.
696 uint64_t* cast_data = (uint64_t*)&raw_data[0]; // NOLINT
697 uint64_t reversed[] = { ntohll(cast_data[3]), ntohll(cast_data[2]), ntohll(cast_data[1]), ntohll(cast_data[0]) };
698
699 // The corrected data is then copied back into the uint256_t's data array.
700 for (int i = 0; i < 4; i++) {
701 data[i] = reversed[i];
702 }
703}
704} // namespace bb::numeric
constexpr std::pair< uint256_t, uint256_t > mul_extended(const uint256_t &other) const
Compute the result of multiplication modulu 2**512.
constexpr uint256_t operator^(const uint256_t &other) const
constexpr uint256_t operator~() const
constexpr uint256_t operator%(const uint256_t &other) const
static constexpr std::pair< uint64_t, uint64_t > addc(uint64_t a, uint64_t b, uint64_t carry_in)
constexpr uint256_t operator*(const uint256_t &other) const
constexpr uint256_t operator+(const uint256_t &other) const
static constexpr uint64_t sbb_discard_hi(uint64_t a, uint64_t b, uint64_t borrow_in)
static constexpr std::array< uint64_t, WASM_NUM_LIMBS > wasm_convert(const uint64_t *data)
Convert from 4 64-bit limbs to 9 29-bit limbs.
constexpr bool get_bit(uint64_t bit_index) const
constexpr uint256_t() noexcept
Definition uint256.hpp:39
constexpr uint256_t operator<<(const uint256_t &other) const
constexpr bool operator!() const
constexpr bool operator==(const uint256_t &other) const
constexpr uint256_t operator&(const uint256_t &other) const
static constexpr void wasm_madd(const uint64_t &left_limb, const uint64_t *right_limbs, uint64_t &result_0, uint64_t &result_1, uint64_t &result_2, uint64_t &result_3, uint64_t &result_4, uint64_t &result_5, uint64_t &result_6, uint64_t &result_7, uint64_t &result_8)
Multiply one limb by 9 limbs and add to resulting limbs.
constexpr bool operator>(const uint256_t &other) const
static constexpr std::pair< uint64_t, uint64_t > mac(uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in)
constexpr bool operator<(const uint256_t &other) const
static constexpr std::pair< uint64_t, uint64_t > sbb(uint64_t a, uint64_t b, uint64_t borrow_in)
constexpr bool operator>=(const uint256_t &other) const
constexpr uint256_t operator|(const uint256_t &other) const
constexpr bool operator!=(const uint256_t &other) const
constexpr uint256_t operator-() const
static constexpr uint64_t mac_discard_hi(uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in)
constexpr uint256_t operator/(const uint256_t &other) const
constexpr uint256_t pow(const uint256_t &exponent) const
constexpr uint256_t slice(uint64_t start, uint64_t end) const
static constexpr std::pair< uint64_t, uint64_t > mul_wide(uint64_t a, uint64_t b)
static constexpr uint64_t addc_discard_hi(uint64_t a, uint64_t b, uint64_t carry_in)
constexpr bool operator<=(const uint256_t &other) const
constexpr std::pair< uint256_t, uint256_t > divmod(const uint256_t &b) const
constexpr uint256_t operator>>(const uint256_t &other) const
constexpr uint64_t get_msb() const
void msgpack_pack(auto &packer) const
const std::vector< MemoryValue > data
FF a
FF b
#define WASM_LIMB_BITS
constexpr T get_msb(const T in)
Definition get_msb.hpp:50
Inner sum(Cont< Inner, Args... > const &in)
Definition container.hpp:70
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
unsigned __int128 uint128_t
Definition serialize.hpp:45
void throw_or_abort(std::string const &err)