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