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 assert(start < end);
294 const uint64_t range = end - start;
295 const uint256_t mask = (range == 256) ? -uint256_t(1) : (uint256_t(1) << range) - 1;
296 return ((*this) >> start) & mask;
297}
298
299constexpr uint256_t uint256_t::pow(const uint256_t& exponent) const
300{
301 uint256_t accumulator{ data[0], data[1], data[2], data[3] };
302 uint256_t to_mul{ data[0], data[1], data[2], data[3] };
303 const uint64_t maximum_set_bit = exponent.get_msb();
304
305 for (int i = static_cast<int>(maximum_set_bit) - 1; i >= 0; --i) {
306 accumulator *= accumulator;
307 if (exponent.get_bit(static_cast<uint64_t>(i))) {
308 accumulator *= to_mul;
309 }
310 }
311 if (exponent == uint256_t(0)) {
312 accumulator = uint256_t(1);
313 } else if (*this == uint256_t(0)) {
314 accumulator = uint256_t(0);
315 }
316 return accumulator;
317}
318
319constexpr bool uint256_t::get_bit(const uint64_t bit_index) const
320{
321 ASSERT_IN_CONSTEXPR(bit_index < 256);
322 if (bit_index > 255) {
323 return static_cast<bool>(0);
324 }
325 const auto idx = static_cast<size_t>(bit_index >> 6);
326 const size_t shift = bit_index & 63;
327 return static_cast<bool>((data[idx] >> shift) & 1);
328}
329
330constexpr uint64_t uint256_t::get_msb() const
331{
332 uint64_t idx = numeric::get_msb(data[3]);
333 idx = (idx == 0 && data[3] == 0) ? numeric::get_msb(data[2]) : idx + 64;
334 idx = (idx == 0 && data[2] == 0) ? numeric::get_msb(data[1]) : idx + 64;
335 idx = (idx == 0 && data[1] == 0) ? numeric::get_msb(data[0]) : idx + 64;
336 return idx;
337}
338
339constexpr uint256_t uint256_t::operator+(const uint256_t& other) const
340{
341 const auto [r0, t0] = addc(data[0], other.data[0], 0);
342 const auto [r1, t1] = addc(data[1], other.data[1], t0);
343 const auto [r2, t2] = addc(data[2], other.data[2], t1);
344 const auto r3 = addc_discard_hi(data[3], other.data[3], t2);
345 return { r0, r1, r2, r3 };
346};
347
348constexpr uint256_t uint256_t::operator-(const uint256_t& other) const
349{
350
351 const auto [r0, t0] = sbb(data[0], other.data[0], 0);
352 const auto [r1, t1] = sbb(data[1], other.data[1], t0);
353 const auto [r2, t2] = sbb(data[2], other.data[2], t1);
354 const auto r3 = sbb_discard_hi(data[3], other.data[3], t2);
355 return { r0, r1, r2, r3 };
356}
357
359{
360 return uint256_t(0) - *this;
361}
362
363constexpr uint256_t uint256_t::operator*(const uint256_t& other) const
364{
365
366#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
367 const auto [r0, t0] = mac(0, data[0], other.data[0], 0ULL);
368 const auto [q0, t1] = mac(0, data[0], other.data[1], t0);
369 const auto [q1, t2] = mac(0, data[0], other.data[2], t1);
370 const auto q2 = mac_discard_hi(0, data[0], other.data[3], t2);
371
372 const auto [r1, t3] = mac(q0, data[1], other.data[0], 0ULL);
373 const auto [q3, t4] = mac(q1, data[1], other.data[1], t3);
374 const auto q4 = mac_discard_hi(q2, data[1], other.data[2], t4);
375
376 const auto [r2, t5] = mac(q3, data[2], other.data[0], 0ULL);
377 const auto q5 = mac_discard_hi(q4, data[2], other.data[1], t5);
378
379 const auto r3 = mac_discard_hi(q5, data[3], other.data[0], 0ULL);
380
381 return { r0, r1, r2, r3 };
382#else
383 // Convert 4 64-bit limbs to 9 29-bit limbs
384 const auto left = wasm_convert(data);
385 const auto right = wasm_convert(other.data);
386 uint64_t temp_0 = 0;
387 uint64_t temp_1 = 0;
388 uint64_t temp_2 = 0;
389 uint64_t temp_3 = 0;
390 uint64_t temp_4 = 0;
391 uint64_t temp_5 = 0;
392 uint64_t temp_6 = 0;
393 uint64_t temp_7 = 0;
394 uint64_t temp_8 = 0;
395
396 // Multiply and add the product of left limb 0 by all right limbs
397 wasm_madd(left[0], &right[0], temp_0, temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8);
398 // Multiply left limb 1 by limbs 0-7 ((1,8) doesn't need to be computed, because it overflows)
399 temp_1 += left[1] * right[0];
400 temp_2 += left[1] * right[1];
401 temp_3 += left[1] * right[2];
402 temp_4 += left[1] * right[3];
403 temp_5 += left[1] * right[4];
404 temp_6 += left[1] * right[5];
405 temp_7 += left[1] * right[6];
406 temp_8 += left[1] * right[7];
407 // Left limb 2 by right 0-6, etc
408 temp_2 += left[2] * right[0];
409 temp_3 += left[2] * right[1];
410 temp_4 += left[2] * right[2];
411 temp_5 += left[2] * right[3];
412 temp_6 += left[2] * right[4];
413 temp_7 += left[2] * right[5];
414 temp_8 += left[2] * right[6];
415 temp_3 += left[3] * right[0];
416 temp_4 += left[3] * right[1];
417 temp_5 += left[3] * right[2];
418 temp_6 += left[3] * right[3];
419 temp_7 += left[3] * right[4];
420 temp_8 += left[3] * right[5];
421 temp_4 += left[4] * right[0];
422 temp_5 += left[4] * right[1];
423 temp_6 += left[4] * right[2];
424 temp_7 += left[4] * right[3];
425 temp_8 += left[4] * right[4];
426 temp_5 += left[5] * right[0];
427 temp_6 += left[5] * right[1];
428 temp_7 += left[5] * right[2];
429 temp_8 += left[5] * right[3];
430 temp_6 += left[6] * right[0];
431 temp_7 += left[6] * right[1];
432 temp_8 += left[6] * right[2];
433 temp_7 += left[7] * right[0];
434 temp_8 += left[7] * right[1];
435 temp_8 += left[8] * right[0];
436
437 // Convert from relaxed form to strict 29-bit form
438 constexpr uint64_t mask = 0x1fffffff;
439 temp_1 += temp_0 >> WASM_LIMB_BITS;
440 temp_0 &= mask;
441 temp_2 += temp_1 >> WASM_LIMB_BITS;
442 temp_1 &= mask;
443 temp_3 += temp_2 >> WASM_LIMB_BITS;
444 temp_2 &= mask;
445 temp_4 += temp_3 >> WASM_LIMB_BITS;
446 temp_3 &= mask;
447 temp_5 += temp_4 >> WASM_LIMB_BITS;
448 temp_4 &= mask;
449 temp_6 += temp_5 >> WASM_LIMB_BITS;
450 temp_5 &= mask;
451 temp_7 += temp_6 >> WASM_LIMB_BITS;
452 temp_6 &= mask;
453 temp_8 += temp_7 >> WASM_LIMB_BITS;
454 temp_7 &= mask;
455
456 // Convert back to 4 64-bit limbs
457 return { (temp_0 << 0) | (temp_1 << 29) | (temp_2 << 58),
458 (temp_2 >> 6) | (temp_3 << 23) | (temp_4 << 52),
459 (temp_4 >> 12) | (temp_5 << 17) | (temp_6 << 46),
460 (temp_6 >> 18) | (temp_7 << 11) | (temp_8 << 40) };
461#endif
462}
463
464constexpr uint256_t uint256_t::operator/(const uint256_t& other) const
465{
466 return divmod(other).first;
467}
468
469constexpr uint256_t uint256_t::operator%(const uint256_t& other) const
470{
471 return divmod(other).second;
472}
473
474constexpr uint256_t uint256_t::operator&(const uint256_t& other) const
475{
476 return { data[0] & other.data[0], data[1] & other.data[1], data[2] & other.data[2], data[3] & other.data[3] };
477}
478
479constexpr uint256_t uint256_t::operator^(const uint256_t& other) const
480{
481 return { data[0] ^ other.data[0], data[1] ^ other.data[1], data[2] ^ other.data[2], data[3] ^ other.data[3] };
482}
483
484constexpr uint256_t uint256_t::operator|(const uint256_t& other) const
485{
486 return { data[0] | other.data[0], data[1] | other.data[1], data[2] | other.data[2], data[3] | other.data[3] };
487}
488
490{
491 return { ~data[0], ~data[1], ~data[2], ~data[3] };
492}
493
494constexpr bool uint256_t::operator==(const uint256_t& other) const
495{
496 return data[0] == other.data[0] && data[1] == other.data[1] && data[2] == other.data[2] && data[3] == other.data[3];
497}
498
499constexpr bool uint256_t::operator!=(const uint256_t& other) const
500{
501 return !(*this == other);
502}
503
504constexpr bool uint256_t::operator!() const
505{
506 return *this == uint256_t(0ULL);
507}
508
509constexpr bool uint256_t::operator>(const uint256_t& other) const
510{
511 bool t0 = data[3] > other.data[3];
512 bool t1 = data[3] == other.data[3] && data[2] > other.data[2];
513 bool t2 = data[3] == other.data[3] && data[2] == other.data[2] && data[1] > other.data[1];
514 bool t3 =
515 data[3] == other.data[3] && data[2] == other.data[2] && data[1] == other.data[1] && data[0] > other.data[0];
516 return t0 || t1 || t2 || t3;
517}
518
519constexpr bool uint256_t::operator>=(const uint256_t& other) const
520{
521 return (*this > other) || (*this == other);
522}
523
524constexpr bool uint256_t::operator<(const uint256_t& other) const
525{
526 return other > *this;
527}
528
529constexpr bool uint256_t::operator<=(const uint256_t& other) const
530{
531 return (*this < other) || (*this == other);
532}
533
534constexpr uint256_t uint256_t::operator>>(const uint256_t& other) const
535{
536 uint64_t total_shift = other.data[0];
537
538 if (total_shift >= 256 || (other.data[1] != 0U) || (other.data[2] != 0U) || (other.data[3] != 0U)) {
539 return 0;
540 }
541
542 if (total_shift == 0) {
543 return *this;
544 }
545
546 uint64_t num_shifted_limbs = total_shift >> 6ULL;
547 uint64_t limb_shift = total_shift & 63ULL;
548
549 std::array<uint64_t, 4> shifted_limbs = { 0, 0, 0, 0 };
550
551 if (limb_shift == 0) {
552 shifted_limbs[0] = data[0];
553 shifted_limbs[1] = data[1];
554 shifted_limbs[2] = data[2];
555 shifted_limbs[3] = data[3];
556 } else {
557 uint64_t remainder_shift = 64ULL - limb_shift;
558
559 shifted_limbs[3] = data[3] >> limb_shift;
560
561 uint64_t remainder = (data[3]) << remainder_shift;
562
563 shifted_limbs[2] = (data[2] >> limb_shift) + remainder;
564
565 remainder = (data[2]) << remainder_shift;
566
567 shifted_limbs[1] = (data[1] >> limb_shift) + remainder;
568
569 remainder = (data[1]) << remainder_shift;
570
571 shifted_limbs[0] = (data[0] >> limb_shift) + remainder;
572 }
573 uint256_t result(0);
574
575 for (size_t i = 0; i < 4 - num_shifted_limbs; ++i) {
576 result.data[i] = shifted_limbs[static_cast<size_t>(i + num_shifted_limbs)];
577 }
578
579 return result;
580}
581
582constexpr uint256_t uint256_t::operator<<(const uint256_t& other) const
583{
584 uint64_t total_shift = other.data[0];
585
586 if (total_shift >= 256 || (other.data[1] != 0U) || (other.data[2] != 0U) || (other.data[3] != 0U)) {
587 return 0;
588 }
589
590 if (total_shift == 0) {
591 return *this;
592 }
593 uint64_t num_shifted_limbs = total_shift >> 6ULL;
594 uint64_t limb_shift = total_shift & 63ULL;
595
596 std::array<uint64_t, 4> shifted_limbs = { 0, 0, 0, 0 };
597
598 if (limb_shift == 0) {
599 shifted_limbs[0] = data[0];
600 shifted_limbs[1] = data[1];
601 shifted_limbs[2] = data[2];
602 shifted_limbs[3] = data[3];
603 } else {
604 uint64_t remainder_shift = 64ULL - limb_shift;
605
606 shifted_limbs[0] = data[0] << limb_shift;
607
608 uint64_t remainder = data[0] >> remainder_shift;
609
610 shifted_limbs[1] = (data[1] << limb_shift) + remainder;
611
612 remainder = data[1] >> remainder_shift;
613
614 shifted_limbs[2] = (data[2] << limb_shift) + remainder;
615
616 remainder = data[2] >> remainder_shift;
617
618 shifted_limbs[3] = (data[3] << limb_shift) + remainder;
619 }
620 uint256_t result(0);
621
622 for (size_t i = 0; i < 4 - num_shifted_limbs; ++i) {
623 result.data[static_cast<size_t>(i + num_shifted_limbs)] = shifted_limbs[i];
624 }
625
626 return result;
627}
628
629// For serialization
630void uint256_t::msgpack_pack(auto& packer) const
631{
632 // The data is then converted to big endian format using htonll, which stands for "host to network long
633 // long". This is necessary because the data will be written to a raw msgpack buffer, which requires big
634 // endian format.
635 uint64_t bin_data[4] = { htonll(data[3]), htonll(data[2]), htonll(data[1]), htonll(data[0]) };
636
637 // The packer is then used to write the binary data to the buffer, just like in read() and write() methods.
638 packer.pack_bin(sizeof(bin_data));
639 packer.pack_bin_body((const char*)bin_data, sizeof(bin_data)); // NOLINT
640}
641
642// For serialization
644{
645 // The binary data is first extracted from the msgpack object.
646 std::array<uint8_t, sizeof(data)> raw_data = o;
647
648 // The binary data is then read as big endian uint64_t's. This is done by casting the raw data to uint64_t*
649 // and then using ntohll ("network to host long long") to correct the endianness to the host's endianness.
650 uint64_t* cast_data = (uint64_t*)&raw_data[0]; // NOLINT
651 uint64_t reversed[] = { ntohll(cast_data[3]), ntohll(cast_data[2]), ntohll(cast_data[1]), ntohll(cast_data[0]) };
652
653 // The corrected data is then copied back into the uint256_t's data array.
654 for (int i = 0; i < 4; i++) {
655 data[i] = reversed[i];
656 }
657}
658} // namespace bb::numeric
#define ASSERT_IN_CONSTEXPR(expression,...)
Definition assert.hpp:68
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