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: Planned, auditors: [], 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 return { data[0] & 0x1fffffff,
119 (data[0] >> 29) & 0x1fffffff,
120 ((data[0] >> 58) & 0x3f) | ((data[1] & 0x7fffff) << 6),
121 (data[1] >> 23) & 0x1fffffff,
122 ((data[1] >> 52) & 0xfff) | ((data[2] & 0x1ffff) << 12),
123 (data[2] >> 17) & 0x1fffffff,
124 ((data[2] >> 46) & 0x3ffff) | ((data[3] & 0x7ff) << 18),
125 (data[3] >> 11) & 0x1fffffff,
126 (data[3] >> 40) & 0x1fffffff };
127}
128#endif
130{
131 if (*this == 0 || b == 0) {
132 return { 0, 0 };
133 }
134 if (b == 1) {
135 return { *this, 0 };
136 }
137 if (*this == b) {
138 return { 1, 0 };
139 }
140 if (b > *this) {
141 return { 0, *this };
142 }
143
144 uint256_t quotient = 0;
145 uint256_t remainder = *this;
146
147 uint64_t bit_difference = get_msb() - b.get_msb();
148
149 uint256_t divisor = b << bit_difference;
150 uint256_t accumulator = uint256_t(1) << bit_difference;
151
152 // if the divisor is bigger than the remainder, a and b have the same bit length
153 if (divisor > remainder) {
154 divisor >>= 1;
155 accumulator >>= 1;
156 }
157
158 // while the remainder is bigger than our original divisor, we can subtract multiples of b from the remainder,
159 // and add to the quotient
160 while (remainder >= b) {
161
162 // we've shunted 'divisor' up to have the same bit length as our remainder.
163 // If remainder >= divisor, then a is at least '1 << bit_difference' multiples of b
164 if (remainder >= divisor) {
165 remainder -= divisor;
166 // we can use OR here instead of +, as
167 // accumulator is always a nice power of two
168 quotient |= accumulator;
169 }
170 divisor >>= 1;
171 accumulator >>= 1;
172 }
173
174 return { quotient, remainder };
175}
176
185{
186 if (*this == 0 || b == 0) {
187 return { 0, 0 };
188 }
189 if (b == 1) {
190 return { *this, 0 };
191 }
192
193#if !defined(__wasm__)
194 uint256_t quotient;
195 uint64_t remainder = 0;
196 for (int i = 3; i >= 0; --i) {
197 uint128_t cur = (static_cast<uint128_t>(remainder) << 64) | data[i];
198 quotient.data[i] = static_cast<uint64_t>(cur / b);
199 remainder = static_cast<uint64_t>(cur % b);
200 }
201 return { quotient, remainder };
202#else
203 // Fallback to the general divmod since wasm doesn't have native support for 128-bit instructions.
204 auto [q, r] = divmod(uint256_t(b));
205 return { q, static_cast<uint64_t>(r.data[0]) };
206#endif
207}
208
214{
215#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
216 const auto [r0, t0] = mul_wide(data[0], other.data[0]);
217 const auto [q0, t1] = mac(t0, data[0], other.data[1], 0);
218 const auto [q1, t2] = mac(t1, data[0], other.data[2], 0);
219 const auto [q2, z0] = mac(t2, data[0], other.data[3], 0);
220
221 const auto [r1, t3] = mac(q0, data[1], other.data[0], 0);
222 const auto [q3, t4] = mac(q1, data[1], other.data[1], t3);
223 const auto [q4, t5] = mac(q2, data[1], other.data[2], t4);
224 const auto [q5, z1] = mac(z0, data[1], other.data[3], t5);
225
226 const auto [r2, t6] = mac(q3, data[2], other.data[0], 0);
227 const auto [q6, t7] = mac(q4, data[2], other.data[1], t6);
228 const auto [q7, t8] = mac(q5, data[2], other.data[2], t7);
229 const auto [q8, z2] = mac(z1, data[2], other.data[3], t8);
230
231 const auto [r3, t9] = mac(q6, data[3], other.data[0], 0);
232 const auto [r4, t10] = mac(q7, data[3], other.data[1], t9);
233 const auto [r5, t11] = mac(q8, data[3], other.data[2], t10);
234 const auto [r6, r7] = mac(z2, data[3], other.data[3], t11);
235
236 uint256_t lo(r0, r1, r2, r3);
237 uint256_t hi(r4, r5, r6, r7);
238 return { lo, hi };
239#else
240 // Convert 4 64-bit limbs to 9 29-bit limbs
241 const auto left = wasm_convert(data);
242 const auto right = wasm_convert(other.data);
243 constexpr uint64_t mask = 0x1fffffff;
244 uint64_t temp_0 = 0;
245 uint64_t temp_1 = 0;
246 uint64_t temp_2 = 0;
247 uint64_t temp_3 = 0;
248 uint64_t temp_4 = 0;
249 uint64_t temp_5 = 0;
250 uint64_t temp_6 = 0;
251 uint64_t temp_7 = 0;
252 uint64_t temp_8 = 0;
253 uint64_t temp_9 = 0;
254 uint64_t temp_10 = 0;
255 uint64_t temp_11 = 0;
256 uint64_t temp_12 = 0;
257 uint64_t temp_13 = 0;
258 uint64_t temp_14 = 0;
259 uint64_t temp_15 = 0;
260 uint64_t temp_16 = 0;
261
262 // Multiply and addd all limbs
263 wasm_madd(left[0], &right[0], temp_0, temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8);
264 wasm_madd(left[1], &right[0], temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9);
265 wasm_madd(left[2], &right[0], temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10);
266 wasm_madd(left[3], &right[0], temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11);
267 wasm_madd(left[4], &right[0], temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12);
268 wasm_madd(left[5], &right[0], temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13);
269 wasm_madd(left[6], &right[0], temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14);
270 wasm_madd(left[7], &right[0], temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15);
271 wasm_madd(left[8], &right[0], temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15, temp_16);
272
273 // Convert from relaxed form into strict 29-bit form (except for temp_16)
274 temp_1 += temp_0 >> WASM_LIMB_BITS;
275 temp_0 &= mask;
276 temp_2 += temp_1 >> WASM_LIMB_BITS;
277 temp_1 &= mask;
278 temp_3 += temp_2 >> WASM_LIMB_BITS;
279 temp_2 &= mask;
280 temp_4 += temp_3 >> WASM_LIMB_BITS;
281 temp_3 &= mask;
282 temp_5 += temp_4 >> WASM_LIMB_BITS;
283 temp_4 &= mask;
284 temp_6 += temp_5 >> WASM_LIMB_BITS;
285 temp_5 &= mask;
286 temp_7 += temp_6 >> WASM_LIMB_BITS;
287 temp_6 &= mask;
288 temp_8 += temp_7 >> WASM_LIMB_BITS;
289 temp_7 &= mask;
290 temp_9 += temp_8 >> WASM_LIMB_BITS;
291 temp_8 &= mask;
292 temp_10 += temp_9 >> WASM_LIMB_BITS;
293 temp_9 &= mask;
294 temp_11 += temp_10 >> WASM_LIMB_BITS;
295 temp_10 &= mask;
296 temp_12 += temp_11 >> WASM_LIMB_BITS;
297 temp_11 &= mask;
298 temp_13 += temp_12 >> WASM_LIMB_BITS;
299 temp_12 &= mask;
300 temp_14 += temp_13 >> WASM_LIMB_BITS;
301 temp_13 &= mask;
302 temp_15 += temp_14 >> WASM_LIMB_BITS;
303 temp_14 &= mask;
304 temp_16 += temp_15 >> WASM_LIMB_BITS;
305 temp_15 &= mask;
306
307 // Convert to 2 4-64-bit limb uint256_t objects
308 return { { (temp_0 << 0) | (temp_1 << 29) | (temp_2 << 58),
309 (temp_2 >> 6) | (temp_3 << 23) | (temp_4 << 52),
310 (temp_4 >> 12) | (temp_5 << 17) | (temp_6 << 46),
311 (temp_6 >> 18) | (temp_7 << 11) | (temp_8 << 40) },
312 { (temp_8 >> 24) | (temp_9 << 5) | (temp_10 << 34) | (temp_11 << 63),
313 (temp_11 >> 1) | (temp_12 << 28) | (temp_13 << 57),
314 (temp_13 >> 7) | (temp_14 << 22) | (temp_15 << 51),
315 (temp_15 >> 13) | (temp_16 << 16) } };
316#endif
317}
318
324constexpr uint256_t uint256_t::slice(const uint64_t start, const uint64_t end) const
325{
326 assert(start < end);
327 const uint64_t range = end - start;
328 const uint256_t mask = (range == 256) ? -uint256_t(1) : (uint256_t(1) << range) - 1;
329 return ((*this) >> start) & mask;
330}
331
332constexpr uint256_t uint256_t::pow(const uint256_t& exponent) const
333{
334 uint256_t accumulator{ data[0], data[1], data[2], data[3] };
335 uint256_t to_mul{ data[0], data[1], data[2], data[3] };
336 const uint64_t maximum_set_bit = exponent.get_msb();
337
338 for (int i = static_cast<int>(maximum_set_bit) - 1; i >= 0; --i) {
339 accumulator *= accumulator;
340 if (exponent.get_bit(static_cast<uint64_t>(i))) {
341 accumulator *= to_mul;
342 }
343 }
344 if (exponent == uint256_t(0)) {
345 accumulator = uint256_t(1);
346 } else if (*this == uint256_t(0)) {
347 accumulator = uint256_t(0);
348 }
349 return accumulator;
350}
351
352constexpr bool uint256_t::get_bit(const uint64_t bit_index) const
353{
354 if (bit_index > 255) {
355 return static_cast<bool>(0);
356 }
357 const auto idx = static_cast<size_t>(bit_index >> 6);
358 const size_t shift = bit_index & 63;
359 return static_cast<bool>((data[idx] >> shift) & 1);
360}
361
362constexpr uint64_t uint256_t::get_msb() const
363{
364 uint64_t idx = numeric::get_msb(data[3]);
365 idx = (idx == 0 && data[3] == 0) ? numeric::get_msb(data[2]) : idx + 64;
366 idx = (idx == 0 && data[2] == 0) ? numeric::get_msb(data[1]) : idx + 64;
367 idx = (idx == 0 && data[1] == 0) ? numeric::get_msb(data[0]) : idx + 64;
368 return idx;
369}
370
371constexpr uint256_t uint256_t::operator+(const uint256_t& other) const
372{
373 const auto [r0, t0] = addc(data[0], other.data[0], 0);
374 const auto [r1, t1] = addc(data[1], other.data[1], t0);
375 const auto [r2, t2] = addc(data[2], other.data[2], t1);
376 const auto r3 = addc_discard_hi(data[3], other.data[3], t2);
377 return { r0, r1, r2, r3 };
378};
379
380constexpr uint256_t uint256_t::operator-(const uint256_t& other) const
381{
382
383 const auto [r0, t0] = sbb(data[0], other.data[0], 0);
384 const auto [r1, t1] = sbb(data[1], other.data[1], t0);
385 const auto [r2, t2] = sbb(data[2], other.data[2], t1);
386 const auto r3 = sbb_discard_hi(data[3], other.data[3], t2);
387 return { r0, r1, r2, r3 };
388}
389
391{
392 return uint256_t(0) - *this;
393}
394
395constexpr uint256_t uint256_t::operator*(const uint256_t& other) const
396{
397
398#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
399 const auto [r0, t0] = mac(0, data[0], other.data[0], 0ULL);
400 const auto [q0, t1] = mac(0, data[0], other.data[1], t0);
401 const auto [q1, t2] = mac(0, data[0], other.data[2], t1);
402 const auto q2 = mac_discard_hi(0, data[0], other.data[3], t2);
403
404 const auto [r1, t3] = mac(q0, data[1], other.data[0], 0ULL);
405 const auto [q3, t4] = mac(q1, data[1], other.data[1], t3);
406 const auto q4 = mac_discard_hi(q2, data[1], other.data[2], t4);
407
408 const auto [r2, t5] = mac(q3, data[2], other.data[0], 0ULL);
409 const auto q5 = mac_discard_hi(q4, data[2], other.data[1], t5);
410
411 const auto r3 = mac_discard_hi(q5, data[3], other.data[0], 0ULL);
412
413 return { r0, r1, r2, r3 };
414#else
415 // Convert 4 64-bit limbs to 9 29-bit limbs
416 const auto left = wasm_convert(data);
417 const auto right = wasm_convert(other.data);
418 uint64_t temp_0 = 0;
419 uint64_t temp_1 = 0;
420 uint64_t temp_2 = 0;
421 uint64_t temp_3 = 0;
422 uint64_t temp_4 = 0;
423 uint64_t temp_5 = 0;
424 uint64_t temp_6 = 0;
425 uint64_t temp_7 = 0;
426 uint64_t temp_8 = 0;
427
428 // Multiply and add the product of left limb 0 by all right limbs
429 wasm_madd(left[0], &right[0], temp_0, temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8);
430 // Multiply left limb 1 by limbs 0-7 ((1,8) doesn't need to be computed, because it overflows)
431 temp_1 += left[1] * right[0];
432 temp_2 += left[1] * right[1];
433 temp_3 += left[1] * right[2];
434 temp_4 += left[1] * right[3];
435 temp_5 += left[1] * right[4];
436 temp_6 += left[1] * right[5];
437 temp_7 += left[1] * right[6];
438 temp_8 += left[1] * right[7];
439 // Left limb 2 by right 0-6, etc
440 temp_2 += left[2] * right[0];
441 temp_3 += left[2] * right[1];
442 temp_4 += left[2] * right[2];
443 temp_5 += left[2] * right[3];
444 temp_6 += left[2] * right[4];
445 temp_7 += left[2] * right[5];
446 temp_8 += left[2] * right[6];
447 temp_3 += left[3] * right[0];
448 temp_4 += left[3] * right[1];
449 temp_5 += left[3] * right[2];
450 temp_6 += left[3] * right[3];
451 temp_7 += left[3] * right[4];
452 temp_8 += left[3] * right[5];
453 temp_4 += left[4] * right[0];
454 temp_5 += left[4] * right[1];
455 temp_6 += left[4] * right[2];
456 temp_7 += left[4] * right[3];
457 temp_8 += left[4] * right[4];
458 temp_5 += left[5] * right[0];
459 temp_6 += left[5] * right[1];
460 temp_7 += left[5] * right[2];
461 temp_8 += left[5] * right[3];
462 temp_6 += left[6] * right[0];
463 temp_7 += left[6] * right[1];
464 temp_8 += left[6] * right[2];
465 temp_7 += left[7] * right[0];
466 temp_8 += left[7] * right[1];
467 temp_8 += left[8] * right[0];
468
469 // Convert from relaxed form to strict 29-bit form
470 constexpr uint64_t mask = 0x1fffffff;
471 temp_1 += temp_0 >> WASM_LIMB_BITS;
472 temp_0 &= mask;
473 temp_2 += temp_1 >> WASM_LIMB_BITS;
474 temp_1 &= mask;
475 temp_3 += temp_2 >> WASM_LIMB_BITS;
476 temp_2 &= mask;
477 temp_4 += temp_3 >> WASM_LIMB_BITS;
478 temp_3 &= mask;
479 temp_5 += temp_4 >> WASM_LIMB_BITS;
480 temp_4 &= mask;
481 temp_6 += temp_5 >> WASM_LIMB_BITS;
482 temp_5 &= mask;
483 temp_7 += temp_6 >> WASM_LIMB_BITS;
484 temp_6 &= mask;
485 temp_8 += temp_7 >> WASM_LIMB_BITS;
486 temp_7 &= mask;
487
488 // Convert back to 4 64-bit limbs
489 return { (temp_0 << 0) | (temp_1 << 29) | (temp_2 << 58),
490 (temp_2 >> 6) | (temp_3 << 23) | (temp_4 << 52),
491 (temp_4 >> 12) | (temp_5 << 17) | (temp_6 << 46),
492 (temp_6 >> 18) | (temp_7 << 11) | (temp_8 << 40) };
493#endif
494}
495
496constexpr uint256_t uint256_t::operator/(const uint256_t& other) const
497{
498 return divmod(other).first;
499}
500
501constexpr uint256_t uint256_t::operator%(const uint256_t& other) const
502{
503 return divmod(other).second;
504}
505
506constexpr uint256_t uint256_t::operator&(const uint256_t& other) const
507{
508 return { data[0] & other.data[0], data[1] & other.data[1], data[2] & other.data[2], data[3] & other.data[3] };
509}
510
511constexpr uint256_t uint256_t::operator^(const uint256_t& other) const
512{
513 return { data[0] ^ other.data[0], data[1] ^ other.data[1], data[2] ^ other.data[2], data[3] ^ other.data[3] };
514}
515
516constexpr uint256_t uint256_t::operator|(const uint256_t& other) const
517{
518 return { data[0] | other.data[0], data[1] | other.data[1], data[2] | other.data[2], data[3] | other.data[3] };
519}
520
522{
523 return { ~data[0], ~data[1], ~data[2], ~data[3] };
524}
525
526constexpr bool uint256_t::operator==(const uint256_t& other) const
527{
528 return data[0] == other.data[0] && data[1] == other.data[1] && data[2] == other.data[2] && data[3] == other.data[3];
529}
530
531constexpr bool uint256_t::operator!=(const uint256_t& other) const
532{
533 return !(*this == other);
534}
535
536constexpr bool uint256_t::operator!() const
537{
538 return *this == uint256_t(0ULL);
539}
540
541constexpr bool uint256_t::operator>(const uint256_t& other) const
542{
543 bool t0 = data[3] > other.data[3];
544 bool t1 = data[3] == other.data[3] && data[2] > other.data[2];
545 bool t2 = data[3] == other.data[3] && data[2] == other.data[2] && data[1] > other.data[1];
546 bool t3 =
547 data[3] == other.data[3] && data[2] == other.data[2] && data[1] == other.data[1] && data[0] > other.data[0];
548 return t0 || t1 || t2 || t3;
549}
550
551constexpr bool uint256_t::operator>=(const uint256_t& other) const
552{
553 return (*this > other) || (*this == other);
554}
555
556constexpr bool uint256_t::operator<(const uint256_t& other) const
557{
558 return other > *this;
559}
560
561constexpr bool uint256_t::operator<=(const uint256_t& other) const
562{
563 return (*this < other) || (*this == other);
564}
565
566constexpr uint256_t uint256_t::operator>>(const uint256_t& other) const
567{
568 uint64_t total_shift = other.data[0];
569
570 if (total_shift >= 256 || (other.data[1] != 0U) || (other.data[2] != 0U) || (other.data[3] != 0U)) {
571 return 0;
572 }
573
574 if (total_shift == 0) {
575 return *this;
576 }
577
578 uint64_t num_shifted_limbs = total_shift >> 6ULL;
579 uint64_t limb_shift = total_shift & 63ULL;
580
581 std::array<uint64_t, 4> shifted_limbs = { 0, 0, 0, 0 };
582
583 if (limb_shift == 0) {
584 shifted_limbs[0] = data[0];
585 shifted_limbs[1] = data[1];
586 shifted_limbs[2] = data[2];
587 shifted_limbs[3] = data[3];
588 } else {
589 uint64_t remainder_shift = 64ULL - limb_shift;
590
591 shifted_limbs[3] = data[3] >> limb_shift;
592
593 uint64_t remainder = (data[3]) << remainder_shift;
594
595 shifted_limbs[2] = (data[2] >> limb_shift) + remainder;
596
597 remainder = (data[2]) << remainder_shift;
598
599 shifted_limbs[1] = (data[1] >> limb_shift) + remainder;
600
601 remainder = (data[1]) << remainder_shift;
602
603 shifted_limbs[0] = (data[0] >> limb_shift) + remainder;
604 }
605 uint256_t result(0);
606
607 for (size_t i = 0; i < 4 - num_shifted_limbs; ++i) {
608 result.data[i] = shifted_limbs[static_cast<size_t>(i + num_shifted_limbs)];
609 }
610
611 return result;
612}
613
614constexpr uint256_t uint256_t::operator<<(const uint256_t& other) const
615{
616 uint64_t total_shift = other.data[0];
617
618 if (total_shift >= 256 || (other.data[1] != 0U) || (other.data[2] != 0U) || (other.data[3] != 0U)) {
619 return 0;
620 }
621
622 if (total_shift == 0) {
623 return *this;
624 }
625 uint64_t num_shifted_limbs = total_shift >> 6ULL;
626 uint64_t limb_shift = total_shift & 63ULL;
627
628 std::array<uint64_t, 4> shifted_limbs = { 0, 0, 0, 0 };
629
630 if (limb_shift == 0) {
631 shifted_limbs[0] = data[0];
632 shifted_limbs[1] = data[1];
633 shifted_limbs[2] = data[2];
634 shifted_limbs[3] = data[3];
635 } else {
636 uint64_t remainder_shift = 64ULL - limb_shift;
637
638 shifted_limbs[0] = data[0] << limb_shift;
639
640 uint64_t remainder = data[0] >> remainder_shift;
641
642 shifted_limbs[1] = (data[1] << limb_shift) + remainder;
643
644 remainder = data[1] >> remainder_shift;
645
646 shifted_limbs[2] = (data[2] << limb_shift) + remainder;
647
648 remainder = data[2] >> remainder_shift;
649
650 shifted_limbs[3] = (data[3] << limb_shift) + remainder;
651 }
652 uint256_t result(0);
653
654 for (size_t i = 0; i < 4 - num_shifted_limbs; ++i) {
655 result.data[static_cast<size_t>(i + num_shifted_limbs)] = shifted_limbs[i];
656 }
657
658 return result;
659}
660
661// For serialization
662void uint256_t::msgpack_pack(auto& packer) const
663{
664 // The data is then converted to big endian format using htonll, which stands for "host to network long
665 // long". This is necessary because the data will be written to a raw msgpack buffer, which requires big
666 // endian format.
667 uint64_t bin_data[4] = { htonll(data[3]), htonll(data[2]), htonll(data[1]), htonll(data[0]) };
668
669 // The packer is then used to write the binary data to the buffer, just like in read() and write() methods.
670 packer.pack_bin(sizeof(bin_data));
671 packer.pack_bin_body((const char*)bin_data, sizeof(bin_data)); // NOLINT
672}
673
674// For serialization
676{
677 // The binary data is first extracted from the msgpack object.
678 std::array<uint8_t, sizeof(data)> raw_data = o;
679
680 // The binary data is then read as big endian uint64_t's. This is done by casting the raw data to uint64_t*
681 // and then using ntohll ("network to host long long") to correct the endianness to the host's endianness.
682 uint64_t* cast_data = (uint64_t*)&raw_data[0]; // NOLINT
683 uint64_t reversed[] = { ntohll(cast_data[3]), ntohll(cast_data[2]), ntohll(cast_data[1]), ntohll(cast_data[0]) };
684
685 // The corrected data is then copied back into the uint256_t's data array.
686 for (int i = 0; i < 4; i++) {
687 data[i] = reversed[i];
688 }
689}
690} // 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:47
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