jaulib v1.3.0
Jau Support Library (C++, Java, ..)
big_int_ops.hpp
Go to the documentation of this file.
1/*
2 * big_int_ops.hpp (this file)
3 * (c) 2024 Gothel Software e.K.
4 *
5 * Includes code from: Botan Lowest Level MPI Algorithms (mp_asmi.h)
6 * (C) 1999-2010 Jack Lloyd
7 * 2006 Luca Piccarreta
8 *
9 * Includes code from: Botan MPI Algorithms (mp_core.h)
10 * (C) 1999-2010,2018 Jack Lloyd
11 * 2006 Luca Piccarreta
12 * 2016 Matthias Gierlings
13 *
14 * jaulib including this code is released under the MIT License (see COPYING)
15 * Botan itself is released under the Simplified BSD License (see COPYING)
16 */
17
18#ifndef JAU_BIG_INT_OPS_HPP_
19#define JAU_BIG_INT_OPS_HPP_
20
21#include <cstdint>
22#include <cassert>
23
24#include <jau/cpp_lang_util.hpp>
25#include <jau/cpuid.hpp>
26#include <jau/ct_utils.hpp>
28
29namespace jau::mp {
30 namespace impl {
31 constexpr size_t best_word_byte_size() {
32 if constexpr ( 64 == jau::cpu::pointer_bit_size() && is_builtin_int128_available() ) {
33 return 8;
34 } else {
35 return 4;
36 }
37 }
38 }
39 #undef JAU_FORCE_MP_WORD_32_BITS
40 #if !defined( JAU_FORCE_MP_WORD_32_BITS )
41 constexpr const size_t mp_word_bits = impl::best_word_byte_size() * CHAR_BIT;
44 constexpr const bool has_mp_dword = is_builtin_int128_available();
45 #elif 1
46 constexpr const size_t mp_word_bits = 32;
47 typedef uint32_t mp_word_t;
48 constexpr const bool has_mp_dword = true;
49 typedef uint64_t mp_dword_t;
50 #elif 0
51 constexpr const size_t mp_word_bits = 64;
52 typedef uint64_t mp_word_t;
53 #if defined(__SIZEOF_INT128__)
54 constexpr const bool has_mp_dword = true;
55 typedef uint128_t mp_dword_t;
56 #else
57 constexpr const bool has_mp_dword = false;
58 #endif
59 #endif
60 constexpr const mp_word_t mp_word_max = ~static_cast<mp_word_t>(0);
61}
62
63namespace jau::mp::ops {
64
65 int bigint_cmp(const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept;
66
67 inline mp_word_t word_add(const mp_word_t x, const mp_word_t y, mp_word_t& carry) noexcept {
68 mp_word_t z = x + y;
69 mp_word_t c1 = (z < x);
70 z += carry;
71 carry = c1 | (z < carry);
72 return z;
73 }
74
75 inline mp_word_t word8_add2(mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept {
76 x[0] = word_add(x[0], y[0], carry);
77 x[1] = word_add(x[1], y[1], carry);
78 x[2] = word_add(x[2], y[2], carry);
79 x[3] = word_add(x[3], y[3], carry);
80 x[4] = word_add(x[4], y[4], carry);
81 x[5] = word_add(x[5], y[5], carry);
82 x[6] = word_add(x[6], y[6], carry);
83 x[7] = word_add(x[7], y[7], carry);
84 return carry;
85 }
86
87 inline mp_word_t word8_add3(mp_word_t z[8], const mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept
88 {
89 z[0] = word_add(x[0], y[0], carry);
90 z[1] = word_add(x[1], y[1], carry);
91 z[2] = word_add(x[2], y[2], carry);
92 z[3] = word_add(x[3], y[3], carry);
93 z[4] = word_add(x[4], y[4], carry);
94 z[5] = word_add(x[5], y[5], carry);
95 z[6] = word_add(x[6], y[6], carry);
96 z[7] = word_add(x[7], y[7], carry);
97 return carry;
98 }
99
100 inline mp_word_t word_sub(mp_word_t x, mp_word_t y, mp_word_t& carry) noexcept {
101 mp_word_t t0 = x - y;
102 mp_word_t c1 = (t0 > x);
103 mp_word_t z = t0 - carry;
104 carry = c1 | (z > t0);
105 return z;
106 }
107
108 inline mp_word_t word8_sub2(mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept {
109 x[0] = word_sub(x[0], y[0], carry);
110 x[1] = word_sub(x[1], y[1], carry);
111 x[2] = word_sub(x[2], y[2], carry);
112 x[3] = word_sub(x[3], y[3], carry);
113 x[4] = word_sub(x[4], y[4], carry);
114 x[5] = word_sub(x[5], y[5], carry);
115 x[6] = word_sub(x[6], y[6], carry);
116 x[7] = word_sub(x[7], y[7], carry);
117 return carry;
118 }
119
120 inline mp_word_t word8_sub2_rev(mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept {
121 x[0] = word_sub(y[0], x[0], carry);
122 x[1] = word_sub(y[1], x[1], carry);
123 x[2] = word_sub(y[2], x[2], carry);
124 x[3] = word_sub(y[3], x[3], carry);
125 x[4] = word_sub(y[4], x[4], carry);
126 x[5] = word_sub(y[5], x[5], carry);
127 x[6] = word_sub(y[6], x[6], carry);
128 x[7] = word_sub(y[7], x[7], carry);
129 return carry;
130 }
131
132 inline mp_word_t word8_sub3(mp_word_t z[8], const mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept {
133 z[0] = word_sub(x[0], y[0], carry);
134 z[1] = word_sub(x[1], y[1], carry);
135 z[2] = word_sub(x[2], y[2], carry);
136 z[3] = word_sub(x[3], y[3], carry);
137 z[4] = word_sub(x[4], y[4], carry);
138 z[5] = word_sub(x[5], y[5], carry);
139 z[6] = word_sub(x[6], y[6], carry);
140 z[7] = word_sub(x[7], y[7], carry);
141 return carry;
142 }
143
144 /** 64x64->128 bit multiplication */
145 inline void mul64x64_128(const uint64_t a, const uint64_t b, uint64_t& lo, uint64_t& hi) noexcept {
146 if constexpr ( is_builtin_int128_available() ) {
147 const uint128_t r = static_cast<uint128_t>(a) * b;
148 hi = (r >> 64) & 0xFFFFFFFFFFFFFFFFUL;
149 lo = (r ) & 0xFFFFFFFFFFFFFFFFUL;
150 } else {
151 /*
152 * Do a 64x64->128 multiply using four 32x32->64 multiplies plus
153 * some adds and shifts. Last resort for CPUs like UltraSPARC (with
154 * 64-bit registers/ALU, but no 64x64->128 multiply) or 32-bit CPUs.
155 */
156 constexpr const size_t HWORD_BITS = 32;
157 constexpr const uint32_t HWORD_MASK = 0xFFFFFFFFU;
158
159 const uint32_t a_hi = (a >> HWORD_BITS);
160 const uint32_t a_lo = (a & HWORD_MASK);
161 const uint32_t b_hi = (b >> HWORD_BITS);
162 const uint32_t b_lo = (b & HWORD_MASK);
163
164 uint64_t x0 = static_cast<uint64_t>(a_hi) * b_hi;
165 uint64_t x1 = static_cast<uint64_t>(a_lo) * b_hi;
166 uint64_t x2 = static_cast<uint64_t>(a_hi) * b_lo;
167 uint64_t x3 = static_cast<uint64_t>(a_lo) * b_lo;
168
169 // this cannot overflow as (2^32-1)^2 + 2^32-1 < 2^64-1
170 x2 += x3 >> HWORD_BITS;
171
172 // this one can overflow
173 x2 += x1;
174
175 // propagate the carry if any
176 x0 += static_cast<uint64_t>(static_cast<bool>(x2 < x1)) << HWORD_BITS;
177
178 hi = x0 + (x2 >> HWORD_BITS);
179 lo = ((x2 & HWORD_MASK) << HWORD_BITS) + (x3 & HWORD_MASK);
180 }
181 }
182
183 /** Word Multiply/Add */
185 if constexpr ( has_mp_dword ) {
186 const mp_dword_t s = static_cast<mp_dword_t>(a) * b + c;
187 c = static_cast<mp_word_t>(s >> mp_word_bits);
188 return static_cast<mp_word_t>(s);
189 } else if constexpr ( 64 == mp_word_bits ) {
190 uint64_t hi, lo;
191
192 mul64x64_128(a, b, lo, hi);
193
194 lo += c;
195 hi += (lo < c); // carry?
196
197 c = hi;
198 return lo;
199 } else {
200 assert( has_mp_dword || 64 == mp_word_bits );
201 return 0;
202 }
203 }
204
205 /** Word Multiply/Add */
207 if constexpr ( has_mp_dword ) {
208 const mp_dword_t s = static_cast<mp_dword_t>(a) * b + c + d;
209 d = static_cast<mp_word_t>(s >> mp_word_bits);
210 return static_cast<mp_word_t>(s);
211 } else if constexpr ( 64 == mp_word_bits ) {
212 uint64_t hi, lo;
213
214 mul64x64_128(a, b, lo, hi);
215
216 lo += c;
217 hi += (lo < c); // carry?
218
219 lo += d;
220 hi += (lo < d); // carry?
221
222 d = hi;
223 return lo;
224 } else {
225 assert( has_mp_dword || 64 == mp_word_bits );
226 return 0;
227 }
228 }
229
230 /*
231 * Eight Word Block Multiply/Add
232 */
233 inline mp_word_t word8_madd3(mp_word_t z[8], const mp_word_t x[8], mp_word_t y, mp_word_t carry) noexcept {
234 z[0] = word_madd3(x[0], y, z[0], carry);
235 z[1] = word_madd3(x[1], y, z[1], carry);
236 z[2] = word_madd3(x[2], y, z[2], carry);
237 z[3] = word_madd3(x[3], y, z[3], carry);
238 z[4] = word_madd3(x[4], y, z[4], carry);
239 z[5] = word_madd3(x[5], y, z[5], carry);
240 z[6] = word_madd3(x[6], y, z[6], carry);
241 z[7] = word_madd3(x[7], y, z[7], carry);
242 return carry;
243 }
244
245 /*
246 * Eight Word Block Linear Multiplication
247 */
248 inline mp_word_t word8_linmul2(mp_word_t x[8], mp_word_t y, mp_word_t carry) noexcept {
249 x[0] = word_madd2(x[0], y, carry);
250 x[1] = word_madd2(x[1], y, carry);
251 x[2] = word_madd2(x[2], y, carry);
252 x[3] = word_madd2(x[3], y, carry);
253 x[4] = word_madd2(x[4], y, carry);
254 x[5] = word_madd2(x[5], y, carry);
255 x[6] = word_madd2(x[6], y, carry);
256 x[7] = word_madd2(x[7], y, carry);
257 return carry;
258 }
259
260 /*
261 * Eight Word Block Linear Multiplication
262 */
263 inline mp_word_t word8_linmul3(mp_word_t z[8], const mp_word_t x[8], mp_word_t y, mp_word_t carry) noexcept {
264 z[0] = word_madd2(x[0], y, carry);
265 z[1] = word_madd2(x[1], y, carry);
266 z[2] = word_madd2(x[2], y, carry);
267 z[3] = word_madd2(x[3], y, carry);
268 z[4] = word_madd2(x[4], y, carry);
269 z[5] = word_madd2(x[5], y, carry);
270 z[6] = word_madd2(x[6], y, carry);
271 z[7] = word_madd2(x[7], y, carry);
272 return carry;
273 }
274
275 /** Two operand addition with carry out */
276 inline mp_word_t bigint_add2(mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept {
277 mp_word_t carry = 0;
278
279 assert(x_size >= y_size);
280
281 const size_t blocks = y_size - (y_size % 8);
282
283 for(size_t i = 0; i != blocks; i += 8) {
284 carry = word8_add2(x + i, y + i, carry);
285 }
286 for(size_t i = blocks; i != y_size; ++i) {
287 x[i] = word_add(x[i], y[i], carry);
288 }
289 for(size_t i = y_size; i != x_size; ++i) {
290 x[i] = word_add(x[i], 0, carry);
291 }
292 return carry;
293 }
294
295 /** Three operand addition with carry out */
296 inline mp_word_t bigint_add3_nc(mp_word_t z[], const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept {
297 if(x_size < y_size)
298 { return bigint_add3_nc(z, y, y_size, x, x_size); }
299
300 mp_word_t carry = 0;
301
302 const size_t blocks = y_size - (y_size % 8);
303
304 for(size_t i = 0; i != blocks; i += 8) {
305 carry = word8_add3(z + i, x + i, y + i, carry);
306 }
307 for(size_t i = blocks; i != y_size; ++i) {
308 z[i] = word_add(x[i], y[i], carry);
309 }
310 for(size_t i = y_size; i != x_size; ++i) {
311 z[i] = word_add(x[i], 0, carry);
312 }
313 return carry;
314 }
315 /** Three operand addition */
316 inline void bigint_add3(mp_word_t z[], const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept {
317 z[x_size > y_size ? x_size : y_size] +=
318 bigint_add3_nc(z, x, x_size, y, y_size);
319 }
320
321 /** Two operand subtraction */
322 inline mp_word_t bigint_sub2(mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept {
323 mp_word_t borrow = 0;
324
325 assert(x_size >= y_size);
326
327 const size_t blocks = y_size - (y_size % 8);
328
329 for(size_t i = 0; i != blocks; i += 8) {
330 borrow = word8_sub2(x + i, y + i, borrow);
331 }
332 for(size_t i = blocks; i != y_size; ++i) {
333 x[i] = word_sub(x[i], y[i], borrow);
334 }
335 for(size_t i = y_size; i != x_size; ++i) {
336 x[i] = word_sub(x[i], 0, borrow);
337 }
338 return borrow;
339 }
340
341 /** Two operand subtraction, x = y - x; assumes y >= x */
342 inline void bigint_sub2_rev(mp_word_t x[], const mp_word_t y[], size_t y_size) noexcept {
343 mp_word_t borrow = 0;
344
345 const size_t blocks = y_size - (y_size % 8);
346
347 for(size_t i = 0; i != blocks; i += 8) {
348 borrow = word8_sub2_rev(x + i, y + i, borrow);
349 }
350 for(size_t i = blocks; i != y_size; ++i) {
351 x[i] = word_sub(y[i], x[i], borrow);
352 }
353 assert(borrow == 0); // y must be greater than x
354 }
355
356 /** Three operand subtraction */
357 inline mp_word_t bigint_sub3(mp_word_t z[], const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept {
358 mp_word_t borrow = 0;
359
360 assert(x_size >= y_size); // Expected sizes
361
362 const size_t blocks = y_size - (y_size % 8);
363
364 for(size_t i = 0; i != blocks; i += 8) {
365 borrow = word8_sub3(z + i, x + i, y + i, borrow);
366 }
367 for(size_t i = blocks; i != y_size; ++i) {
368 z[i] = word_sub(x[i], y[i], borrow);
369 }
370 for(size_t i = y_size; i != x_size; ++i) {
371 z[i] = word_sub(x[i], 0, borrow);
372 }
373 return borrow;
374 }
375
376 /**
377 * Set z to abs(x-y), ie if x >= y, then compute z = x - y
378 * Otherwise compute z = y - x
379 * No borrow is possible since the result is always >= 0
380 *
381 * Return the relative size of x vs y (-1, 0, 1)
382 *
383 * @param z output array of max(x_size,y_size) words
384 * @param x input param
385 * @param x_size length of x
386 * @param y input param
387 * @param y_size length of y
388 */
389 inline int32_t
390 bigint_sub_abs(mp_word_t z[], const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept {
391 const int32_t relative_size = bigint_cmp(x, x_size, y, y_size);
392
393 // Swap if relative_size == -1
394 const bool need_swap = relative_size < 0;
395 CT::conditional_swap_ptr(need_swap, x, y);
396 CT::conditional_swap(need_swap, x_size, y_size);
397
398 /*
399 * We know at this point that x >= y so if y_size is larger than
400 * x_size, we are guaranteed they are just leading zeros which can
401 * be ignored
402 */
403 y_size = std::min(x_size, y_size);
404
405 bigint_sub3(z, x, x_size, y, y_size);
406
407 return relative_size;
408 }
409
410 /*
411 * Linear Multiply - returns the carry
412 */
413 [[nodiscard]] inline mp_word_t bigint_linmul2(mp_word_t x[], size_t x_size, mp_word_t y) noexcept {
414 const size_t blocks = x_size - (x_size % 8);
415
416 mp_word_t carry = 0;
417
418 for(size_t i = 0; i != blocks; i += 8) {
419 carry = word8_linmul2(x + i, y, carry);
420 }
421 for(size_t i = blocks; i != x_size; ++i) {
422 x[i] = word_madd2(x[i], y, carry);
423 }
424 return carry;
425 }
426
427 inline void bigint_linmul3(mp_word_t z[], const mp_word_t x[], size_t x_size, mp_word_t y) noexcept {
428 const size_t blocks = x_size - (x_size % 8);
429
430 mp_word_t carry = 0;
431
432 for(size_t i = 0; i != blocks; i += 8) {
433 carry = word8_linmul3(z + i, x + i, y, carry);
434 }
435 for(size_t i = blocks; i != x_size; ++i) {
436 z[i] = word_madd2(x[i], y, carry);
437 }
438 z[x_size] = carry;
439 }
440
441 inline void bigint_shl1(mp_word_t x[], size_t x_size, size_t x_words, size_t word_shift, size_t bit_shift) noexcept {
442 std::memmove(x + word_shift, x, sizeof(mp_word_t)*x_words);
443 std::memset(x, 0, sizeof(mp_word_t)*word_shift);
444
445 const auto carry_mask = CT::Mask<mp_word_t>::expand(bit_shift);
446 const size_t carry_shift = carry_mask.if_set_return(mp_word_bits - bit_shift);
447
448 mp_word_t carry = 0;
449 for(size_t i = word_shift; i != x_size; ++i) {
450 const mp_word_t w = x[i];
451 x[i] = (w << bit_shift) | carry;
452 carry = carry_mask.if_set_return(w >> carry_shift);
453 }
454 }
455
456 inline void bigint_shr1(mp_word_t x[], size_t x_size, size_t word_shift, size_t bit_shift) noexcept {
457 const size_t top = x_size >= word_shift ? (x_size - word_shift) : 0;
458
459 if(top > 0) {
460 std::memmove(x, x + word_shift, sizeof(mp_word_t)*top);
461 }
462 std::memset(x + top, 0, sizeof(mp_word_t)*jau::min(word_shift, x_size));
463
464 const auto carry_mask = CT::Mask<mp_word_t>::expand(bit_shift);
465 const size_t carry_shift = carry_mask.if_set_return(mp_word_bits - bit_shift);
466
467 mp_word_t carry = 0;
468 for(size_t i = 0; i != top; ++i) {
469 const mp_word_t w = x[top - i - 1];
470 x[top-i-1] = (w >> bit_shift) | carry;
471 carry = carry_mask.if_set_return(w << carry_shift);
472 }
473 }
474
475 inline void bigint_shl2(mp_word_t y[], const mp_word_t x[], size_t x_size, size_t word_shift, size_t bit_shift) noexcept {
476 std::memmove(y + word_shift, x, sizeof(mp_word_t)*x_size);
477
478 const auto carry_mask = CT::Mask<mp_word_t>::expand(bit_shift);
479 const size_t carry_shift = carry_mask.if_set_return(mp_word_bits - bit_shift);
480
481 mp_word_t carry = 0;
482 for(size_t i = word_shift; i != x_size + word_shift + 1; ++i) {
483 const mp_word_t w = y[i];
484 y[i] = (w << bit_shift) | carry;
485 carry = carry_mask.if_set_return(w >> carry_shift);
486 }
487 }
488 inline void bigint_shr2(mp_word_t y[], const mp_word_t x[], size_t x_size, size_t word_shift, size_t bit_shift) noexcept {
489 const size_t new_size = x_size < word_shift ? 0 : (x_size - word_shift);
490
491 if(new_size > 0) {
492 std::memmove(y, x + word_shift, sizeof(mp_word_t)*new_size);
493 }
494 const auto carry_mask = CT::Mask<mp_word_t>::expand(bit_shift);
495 const size_t carry_shift = carry_mask.if_set_return(mp_word_bits - bit_shift);
496
497 mp_word_t carry = 0;
498 for(size_t i = new_size; i > 0; --i) {
499 mp_word_t w = y[i-1];
500 y[i-1] = (w >> bit_shift) | carry;
501 carry = carry_mask.if_set_return(w << carry_shift);
502 }
503 }
504
505 /*
506 * O(n*n) multiplication
507 */
508 void basecase_mul(mp_word_t z[], size_t z_size,
509 const mp_word_t x[], size_t x_size,
510 const mp_word_t y[], size_t y_size) noexcept
511 {
512 assert(z_size >= x_size + y_size); // z_size too small
513
514 const size_t x_size_8 = x_size - (x_size % 8);
515
516 for(size_t i=0; i<z_size; ++i) { z[i]=0; }
517
518 for(size_t i = 0; i != y_size; ++i) {
519 const mp_word_t y_i = y[i];
520
521 mp_word_t carry = 0;
522
523 for(size_t j = 0; j != x_size_8; j += 8) {
524 carry = word8_madd3(z + i + j, x + j, y_i, carry);
525 }
526 for(size_t j = x_size_8; j != x_size; ++j) {
527 z[i+j] = word_madd3(x[j], y_i, z[i+j], carry);
528 }
529 z[x_size+i] = carry;
530 }
531 }
532
533 /** Computes ((n1<<bits) + n0) / d */
535 if(d == 0) {
537 }
538 if constexpr ( has_mp_dword ) {
539 return static_cast<mp_word_t>( ( ( static_cast<mp_dword_t>(n1) << mp_word_bits ) | n0 ) / d );
540 } else {
541 mp_word_t high = n1 % d;
542 mp_word_t quotient = 0;
543
544 for(size_t i = 0; i != mp_word_bits; ++i) {
545 const mp_word_t high_top_bit = high >> ( mp_word_bits - 1 );
546
547 high <<= 1;
548 high |= (n0 >> (mp_word_bits-1-i)) & 1;
549 quotient <<= 1;
550
551 if(high_top_bit || high >= d) {
552 high -= d;
553 quotient |= 1;
554 }
555 }
556 return quotient;
557 }
558 }
559
560 /** Compute ((n1<<bits) + n0) % d */
562 if(d == 0) {
564 }
565 if constexpr ( has_mp_dword ) {
566 return ( ( static_cast<mp_dword_t>(n1) << mp_word_bits) | n0 ) % d;
567 } else {
568 mp_word_t z = bigint_divop(n1, n0, d);
569 mp_word_t dummy = 0;
570 z = word_madd2(z, d, dummy);
571 return (n0-z);
572 }
573 }
574
576 bigint_ct_is_eq(const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept {
577 const size_t common_elems = std::min(x_size, y_size);
578 mp_word_t diff = 0;
579
580 for(size_t i = 0; i != common_elems; i++) {
581 diff |= (x[i] ^ y[i]);
582 }
583
584 // If any bits were set in high part of x/y, then they are not equal
585 if(x_size < y_size)
586 {
587 for(size_t i = x_size; i != y_size; i++) {
588 diff |= y[i];
589 }
590 } else if(y_size < x_size) {
591 for(size_t i = y_size; i != x_size; i++) {
592 diff |= x[i];
593 }
594 }
595 return CT::Mask<mp_word_t>::is_zero(diff);
596 }
597
598 /**
599 * Compare x and y
600 * Return ~0 if x[0:x_size] < y[0:y_size] or 0 otherwise
601 * If lt_or_equal is true, returns ~0 also for x == y
602 */
604 bigint_ct_is_lt(const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size, bool lt_or_equal = false) noexcept
605 {
606 const size_t common_elems = jau::min(x_size, y_size);
607
608 auto is_lt = CT::Mask<mp_word_t>::expand(lt_or_equal);
609
610 for(size_t i = 0; i != common_elems; i++)
611 {
612 const auto eq = CT::Mask<mp_word_t>::is_equal(x[i], y[i]);
613 const auto lt = CT::Mask<mp_word_t>::is_lt(x[i], y[i]);
614 is_lt = eq.select_mask(is_lt, lt);
615 }
616
617 if(x_size < y_size) {
618 mp_word_t mask = 0;
619 for(size_t i = x_size; i != y_size; i++) {
620 mask |= y[i];
621 }
622 // If any bits were set in high part of y, then is_lt should be forced true
623 is_lt |= CT::Mask<mp_word_t>::expand(mask);
624 } else if(y_size < x_size) {
625 mp_word_t mask = 0;
626 for(size_t i = y_size; i != x_size; i++) {
627 mask |= x[i];
628 }
629
630 // If any bits were set in high part of x, then is_lt should be false
631 is_lt &= CT::Mask<mp_word_t>::is_zero(mask);
632 }
633
634 return is_lt;
635 }
636
637 /**
638 * Compare unsigned x and y mp_word_t
639 *
640 * Returns
641 * - -1 if x < y
642 * - 0 if x == y
643 * - 1 if x > y
644 */
645 inline int bigint_cmp(const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
646 {
647 constexpr const mp_word_t LT = static_cast<mp_word_t>(-1);
648 constexpr const mp_word_t EQ = 0;
649 constexpr const mp_word_t GT = 1;
650 const size_t common_elems = jau::min(x_size, y_size);
651
652 mp_word_t result = EQ; // until found otherwise
653
654 for(size_t i = 0; i != common_elems; i++) {
655 const auto is_eq = CT::Mask<mp_word_t>::is_equal(x[i], y[i]);
656 const auto is_lt = CT::Mask<mp_word_t>::is_lt(x[i], y[i]);
657 result = is_eq.select(result, is_lt.select(LT, GT));
658 }
659 if(x_size < y_size) {
660 mp_word_t mask = 0;
661 for(size_t i = x_size; i != y_size; i++) {
662 mask |= y[i];
663 }
664 // If any bits were set in high part of y, then x < y
665 result = CT::Mask<mp_word_t>::is_zero(mask).select(result, LT);
666 } else if(y_size < x_size) {
667 mp_word_t mask = 0;
668 for(size_t i = y_size; i != x_size; i++) {
669 mask |= x[i];
670 }
671 // If any bits were set in high part of x, then x > y
672 result = CT::Mask<mp_word_t>::is_zero(mask).select(result, GT);
673 }
674 CT::unpoison(result);
675 return static_cast<int>(result);
676 }
677
678} // namespace jau::mp::ops
679
680#endif /* JAU_BIG_INT_OPS_HPP_ */
#define E_FILE_LINE
A Mask type used for constant-time operations.
Definition: ct_utils.hpp:81
static Mask< T > is_equal(T x, T y) noexcept
Return a Mask<T> which is set if x == y.
Definition: ct_utils.hpp:145
static Mask< T > expand(T v) noexcept
Return a Mask<T> which is set if v is != 0.
Definition: ct_utils.hpp:119
static Mask< T > is_zero(T x) noexcept
Return a Mask<T> which is set if v is == 0 or cleared otherwise.
Definition: ct_utils.hpp:137
static Mask< T > is_lt(T x, T y) noexcept
Return a Mask<T> which is set if x < y.
Definition: ct_utils.hpp:153
math_error_t::div_by_zero, i.e.
Definition: math_error.hpp:78
consteval_cxx20 bool is_builtin_int128_available() noexcept
constexpr T min(const T x, const T y) noexcept
Returns the minimum of two integrals (w/ branching) in O(1)
Definition: base_math.hpp:177
constexpr size_t pointer_bit_size() noexcept
Returns the compile time pointer architecture size in bits.
Definition: cpuid.hpp:45
void unpoison(const T *p, size_t n)
Definition: ct_utils.hpp:54
void conditional_swap(bool cnd, T &x, T &y) noexcept
Definition: ct_utils.hpp:370
void conditional_swap_ptr(bool cnd, T &x, T &y) noexcept
Definition: ct_utils.hpp:381
constexpr size_t best_word_byte_size()
Definition: big_int_ops.hpp:31
mp_word_t word8_madd3(mp_word_t z[8], const mp_word_t x[8], mp_word_t y, mp_word_t carry) noexcept
mp_word_t word8_sub2(mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept
CT::Mask< mp_word_t > bigint_ct_is_lt(const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size, bool lt_or_equal=false) noexcept
Compare x and y Return ~0 if x[0:x_size] < y[0:y_size] or 0 otherwise If lt_or_equal is true,...
CT::Mask< mp_word_t > bigint_ct_is_eq(const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
mp_word_t word8_sub2_rev(mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept
int bigint_cmp(const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
Compare unsigned x and y mp_word_t.
mp_word_t bigint_divop(mp_word_t n1, mp_word_t n0, mp_word_t d)
Computes ((n1<<bits) + n0) / d.
int32_t bigint_sub_abs(mp_word_t z[], const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
Set z to abs(x-y), ie if x >= y, then compute z = x - y Otherwise compute z = y - x No borrow is poss...
mp_word_t bigint_add2(mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
Two operand addition with carry out.
mp_word_t word8_linmul3(mp_word_t z[8], const mp_word_t x[8], mp_word_t y, mp_word_t carry) noexcept
mp_word_t word_sub(mp_word_t x, mp_word_t y, mp_word_t &carry) noexcept
mp_word_t word8_sub3(mp_word_t z[8], const mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept
void bigint_shr1(mp_word_t x[], size_t x_size, size_t word_shift, size_t bit_shift) noexcept
mp_word_t bigint_linmul2(mp_word_t x[], size_t x_size, mp_word_t y) noexcept
void bigint_linmul3(mp_word_t z[], const mp_word_t x[], size_t x_size, mp_word_t y) noexcept
mp_word_t bigint_sub3(mp_word_t z[], const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
Three operand subtraction.
mp_word_t bigint_add3_nc(mp_word_t z[], const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
Three operand addition with carry out.
void bigint_shl2(mp_word_t y[], const mp_word_t x[], size_t x_size, size_t word_shift, size_t bit_shift) noexcept
void bigint_add3(mp_word_t z[], const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
Three operand addition.
mp_word_t bigint_sub2(mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
Two operand subtraction.
void mul64x64_128(const uint64_t a, const uint64_t b, uint64_t &lo, uint64_t &hi) noexcept
64x64->128 bit multiplication
mp_word_t word8_linmul2(mp_word_t x[8], mp_word_t y, mp_word_t carry) noexcept
mp_word_t word8_add3(mp_word_t z[8], const mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept
Definition: big_int_ops.hpp:87
mp_word_t bigint_modop(mp_word_t n1, mp_word_t n0, mp_word_t d)
Compute ((n1<<bits) + n0) % d.
mp_word_t word_madd3(mp_word_t a, mp_word_t b, mp_word_t c, mp_word_t &d) noexcept
Word Multiply/Add.
mp_word_t word_madd2(mp_word_t a, mp_word_t b, mp_word_t &c) noexcept
Word Multiply/Add.
void bigint_shl1(mp_word_t x[], size_t x_size, size_t x_words, size_t word_shift, size_t bit_shift) noexcept
void basecase_mul(mp_word_t z[], size_t z_size, const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
mp_word_t word8_add2(mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept
Definition: big_int_ops.hpp:75
void bigint_shr2(mp_word_t y[], const mp_word_t x[], size_t x_size, size_t word_shift, size_t bit_shift) noexcept
mp_word_t word_add(const mp_word_t x, const mp_word_t y, mp_word_t &carry) noexcept
Definition: big_int_ops.hpp:67
void bigint_sub2_rev(mp_word_t x[], const mp_word_t y[], size_t y_size) noexcept
Two operand subtraction, x = y - x; assumes y >= x.
big_int_t (this file) (c) 2024 Gothel Software e.K.
Definition: big_int.hpp:26
constexpr const bool has_mp_dword
Definition: big_int_ops.hpp:44
jau::uint_bytes< impl::best_word_byte_size()>::type mp_word_t
Definition: big_int_ops.hpp:42
constexpr const size_t mp_word_bits
Definition: big_int_ops.hpp:41
jau::uint_bytes< impl::best_word_byte_size() *2 >::type mp_dword_t
Definition: big_int_ops.hpp:43
constexpr const mp_word_t mp_word_max
Definition: big_int_ops.hpp:60