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