Coverage Report

Created: 2023-02-22 06:39

/src/botan/build/include/botan/internal/mp_core.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
* MPI Algorithms
3
* (C) 1999-2010,2018 Jack Lloyd
4
*     2006 Luca Piccarreta
5
*     2016 Matthias Gierlings
6
*
7
* Botan is released under the Simplified BSD License (see license.txt)
8
*/
9
10
#ifndef BOTAN_MP_CORE_OPS_H_
11
#define BOTAN_MP_CORE_OPS_H_
12
13
#include <botan/types.h>
14
#include <botan/exceptn.h>
15
#include <botan/mem_ops.h>
16
#include <botan/internal/mp_asmi.h>
17
#include <botan/internal/ct_utils.h>
18
#include <algorithm>
19
20
namespace Botan {
21
22
const word MP_WORD_MAX = ~static_cast<word>(0);
23
24
/*
25
* If cond == 0, does nothing.
26
* If cond > 0, swaps x[0:size] with y[0:size]
27
* Runs in constant time
28
*/
29
inline void bigint_cnd_swap(word cnd, word x[], word y[], size_t size)
30
13.8M
   {
31
13.8M
   const auto mask = CT::Mask<word>::expand(cnd);
32
33
1.61G
   for(size_t i = 0; i != size; ++i)
34
1.60G
      {
35
1.60G
      const word a = x[i];
36
1.60G
      const word b = y[i];
37
1.60G
      x[i] = mask.select(b, a);
38
1.60G
      y[i] = mask.select(a, b);
39
1.60G
      }
40
13.8M
   }
41
42
inline word bigint_cnd_add(word cnd, word x[], word x_size,
43
                           const word y[], size_t y_size)
44
21.7M
   {
45
21.7M
   BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
46
47
21.7M
   const auto mask = CT::Mask<word>::expand(cnd);
48
49
21.7M
   word carry = 0;
50
51
21.7M
   const size_t blocks = y_size - (y_size % 8);
52
21.7M
   word z[8] = { 0 };
53
54
289M
   for(size_t i = 0; i != blocks; i += 8)
55
267M
      {
56
267M
      carry = word8_add3(z, x + i, y + i, carry);
57
267M
      mask.select_n(x + i, z, x + i, 8);
58
267M
      }
59
60
96.2M
   for(size_t i = blocks; i != y_size; ++i)
61
74.5M
      {
62
74.5M
      z[0] = word_add(x[i], y[i], &carry);
63
74.5M
      x[i] = mask.select(z[0], x[i]);
64
74.5M
      }
65
66
225M
   for(size_t i = y_size; i != x_size; ++i)
67
204M
      {
68
204M
      z[0] = word_add(x[i], 0, &carry);
69
204M
      x[i] = mask.select(z[0], x[i]);
70
204M
      }
71
72
21.7M
   return mask.if_set_return(carry);
73
21.7M
   }
74
75
/*
76
* If cond > 0 adds x[0:size] and y[0:size] and returns carry
77
* Runs in constant time
78
*/
79
inline word bigint_cnd_add(word cnd, word x[], const word y[], size_t size)
80
17.2M
   {
81
17.2M
   return bigint_cnd_add(cnd, x, size, y, size);
82
17.2M
   }
83
84
/*
85
* If cond > 0 subtracts x[0:size] and y[0:size] and returns borrow
86
* Runs in constant time
87
*/
88
inline word bigint_cnd_sub(word cnd,
89
                           word x[], size_t x_size,
90
                           const word y[], size_t y_size)
91
12.1M
   {
92
12.1M
   BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
93
94
12.1M
   const auto mask = CT::Mask<word>::expand(cnd);
95
96
12.1M
   word carry = 0;
97
98
12.1M
   const size_t blocks = y_size - (y_size % 8);
99
12.1M
   word z[8] = { 0 };
100
101
183M
   for(size_t i = 0; i != blocks; i += 8)
102
171M
      {
103
171M
      carry = word8_sub3(z, x + i, y + i, carry);
104
171M
      mask.select_n(x + i, z, x + i, 8);
105
171M
      }
106
107
51.8M
   for(size_t i = blocks; i != y_size; ++i)
108
39.7M
      {
109
39.7M
      z[0] = word_sub(x[i], y[i], &carry);
110
39.7M
      x[i] = mask.select(z[0], x[i]);
111
39.7M
      }
112
113
12.1M
   for(size_t i = y_size; i != x_size; ++i)
114
0
      {
115
0
      z[0] = word_sub(x[i], 0, &carry);
116
0
      x[i] = mask.select(z[0], x[i]);
117
0
      }
118
119
12.1M
   return mask.if_set_return(carry);
120
12.1M
   }
121
122
/*
123
* If cond > 0 adds x[0:size] and y[0:size] and returns carry
124
* Runs in constant time
125
*/
126
inline word bigint_cnd_sub(word cnd, word x[], const word y[], size_t size)
127
12.1M
   {
128
12.1M
   return bigint_cnd_sub(cnd, x, size, y, size);
129
12.1M
   }
130
131
132
/*
133
* Equivalent to
134
*   bigint_cnd_add( mask, x, y, size);
135
*   bigint_cnd_sub(~mask, x, y, size);
136
*
137
* Mask must be either 0 or all 1 bits
138
*/
139
inline void bigint_cnd_add_or_sub(CT::Mask<word> mask, word x[], const word y[], size_t size)
140
69
   {
141
69
   const size_t blocks = size - (size % 8);
142
143
69
   word carry = 0;
144
69
   word borrow = 0;
145
146
69
   word t0[8] = { 0 };
147
69
   word t1[8] = { 0 };
148
149
735
   for(size_t i = 0; i != blocks; i += 8)
150
666
      {
151
666
      carry = word8_add3(t0, x + i, y + i, carry);
152
666
      borrow = word8_sub3(t1, x + i, y + i, borrow);
153
154
5.99k
      for(size_t j = 0; j != 8; ++j)
155
5.32k
         x[i+j] = mask.select(t0[j], t1[j]);
156
666
      }
157
158
180
   for(size_t i = blocks; i != size; ++i)
159
111
      {
160
111
      const word a = word_add(x[i], y[i], &carry);
161
111
      const word s = word_sub(x[i], y[i], &borrow);
162
163
111
      x[i] = mask.select(a, s);
164
111
      }
165
69
   }
166
167
/*
168
* Equivalent to
169
*   bigint_cnd_add( mask, x, size, y, size);
170
*   bigint_cnd_sub(~mask, x, size, z, size);
171
*
172
* Mask must be either 0 or all 1 bits
173
*
174
* Returns the carry or borrow resp
175
*/
176
inline word bigint_cnd_addsub(CT::Mask<word> mask, word x[],
177
                              const word y[], const word z[],
178
                              size_t size)
179
2.32M
   {
180
2.32M
   const size_t blocks = size - (size % 8);
181
182
2.32M
   word carry = 0;
183
2.32M
   word borrow = 0;
184
185
2.32M
   word t0[8] = { 0 };
186
2.32M
   word t1[8] = { 0 };
187
188
2.88M
   for(size_t i = 0; i != blocks; i += 8)
189
557k
      {
190
557k
      carry = word8_add3(t0, x + i, y + i, carry);
191
557k
      borrow = word8_sub3(t1, x + i, z + i, borrow);
192
193
5.01M
      for(size_t j = 0; j != 8; ++j)
194
4.45M
         x[i+j] = mask.select(t0[j], t1[j]);
195
557k
      }
196
197
11.0M
   for(size_t i = blocks; i != size; ++i)
198
8.77M
      {
199
8.77M
      t0[0] = word_add(x[i], y[i], &carry);
200
8.77M
      t1[0] = word_sub(x[i], z[i], &borrow);
201
8.77M
      x[i] = mask.select(t0[0], t1[0]);
202
8.77M
      }
203
204
2.32M
   return mask.select(carry, borrow);
205
2.32M
   }
206
207
/*
208
* 2s complement absolute value
209
* If cond > 0 sets x to ~x + 1
210
* Runs in constant time
211
*/
212
inline void bigint_cnd_abs(word cnd, word x[], size_t size)
213
5.76M
   {
214
5.76M
   const auto mask = CT::Mask<word>::expand(cnd);
215
216
5.76M
   word carry = mask.if_set_return(1);
217
708M
   for(size_t i = 0; i != size; ++i)
218
702M
      {
219
702M
      const word z = word_add(~x[i], 0, &carry);
220
702M
      x[i] = mask.select(z, x[i]);
221
702M
      }
222
5.76M
   }
223
224
/**
225
* Two operand addition with carry out
226
*/
227
inline word bigint_add2_nc(word x[], size_t x_size, const word y[], size_t y_size)
228
6.49M
   {
229
6.49M
   word carry = 0;
230
231
6.49M
   BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
232
233
6.49M
   const size_t blocks = y_size - (y_size % 8);
234
235
6.50M
   for(size_t i = 0; i != blocks; i += 8)
236
8.88k
      carry = word8_add2(x + i, y + i, carry);
237
238
13.0M
   for(size_t i = blocks; i != y_size; ++i)
239
6.50M
      x[i] = word_add(x[i], y[i], &carry);
240
241
430M
   for(size_t i = y_size; i != x_size; ++i)
242
424M
      x[i] = word_add(x[i], 0, &carry);
243
244
6.49M
   return carry;
245
6.49M
   }
246
247
/**
248
* Three operand addition with carry out
249
*/
250
inline word bigint_add3_nc(word z[],
251
                           const word x[], size_t x_size,
252
                           const word y[], size_t y_size)
253
993k
   {
254
993k
   if(x_size < y_size)
255
15.9k
      { return bigint_add3_nc(z, y, y_size, x, x_size); }
256
257
977k
   word carry = 0;
258
259
977k
   const size_t blocks = y_size - (y_size % 8);
260
261
1.99M
   for(size_t i = 0; i != blocks; i += 8)
262
1.01M
      carry = word8_add3(z + i, x + i, y + i, carry);
263
264
2.67M
   for(size_t i = blocks; i != y_size; ++i)
265
1.70M
      z[i] = word_add(x[i], y[i], &carry);
266
267
1.10M
   for(size_t i = y_size; i != x_size; ++i)
268
128k
      z[i] = word_add(x[i], 0, &carry);
269
270
977k
   return carry;
271
993k
   }
272
273
/**
274
* Two operand addition
275
* @param x the first operand (and output)
276
* @param x_size size of x
277
* @param y the second operand
278
* @param y_size size of y (must be <= x_size)
279
*/
280
inline void bigint_add2(word x[], size_t x_size,
281
                        const word y[], size_t y_size)
282
6.49M
   {
283
6.49M
   x[x_size] += bigint_add2_nc(x, x_size, y, y_size);
284
6.49M
   }
285
286
/**
287
* Three operand addition
288
*/
289
inline void bigint_add3(word z[],
290
                        const word x[], size_t x_size,
291
                        const word y[], size_t y_size)
292
168k
   {
293
168k
   z[x_size > y_size ? x_size : y_size] +=
294
168k
      bigint_add3_nc(z, x, x_size, y, y_size);
295
168k
   }
296
297
/**
298
* Two operand subtraction
299
*/
300
inline word bigint_sub2(word x[], size_t x_size,
301
                        const word y[], size_t y_size)
302
1.86M
   {
303
1.86M
   word borrow = 0;
304
305
1.86M
   BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
306
307
1.86M
   const size_t blocks = y_size - (y_size % 8);
308
309
1.89M
   for(size_t i = 0; i != blocks; i += 8)
310
35.2k
      borrow = word8_sub2(x + i, y + i, borrow);
311
312
10.6M
   for(size_t i = blocks; i != y_size; ++i)
313
8.78M
      x[i] = word_sub(x[i], y[i], &borrow);
314
315
3.74M
   for(size_t i = y_size; i != x_size; ++i)
316
1.87M
      x[i] = word_sub(x[i], 0, &borrow);
317
318
1.86M
   return borrow;
319
1.86M
   }
320
321
/**
322
* Two operand subtraction, x = y - x; assumes y >= x
323
*/
324
inline void bigint_sub2_rev(word x[], const word y[], size_t y_size)
325
112
   {
326
112
   word borrow = 0;
327
328
112
   const size_t blocks = y_size - (y_size % 8);
329
330
281
   for(size_t i = 0; i != blocks; i += 8)
331
169
      borrow = word8_sub2_rev(x + i, y + i, borrow);
332
333
399
   for(size_t i = blocks; i != y_size; ++i)
334
287
      x[i] = word_sub(y[i], x[i], &borrow);
335
336
112
   BOTAN_ASSERT(borrow == 0, "y must be greater than x");
337
112
   }
338
339
/**
340
* Three operand subtraction
341
*
342
* Expects that x_size >= y_size
343
*
344
* Writes to z[0:x_size] and returns borrow
345
*/
346
inline word bigint_sub3(word z[],
347
                        const word x[], size_t x_size,
348
                        const word y[], size_t y_size)
349
12.4M
   {
350
12.4M
   word borrow = 0;
351
352
12.4M
   BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
353
354
12.4M
   const size_t blocks = y_size - (y_size % 8);
355
356
59.2M
   for(size_t i = 0; i != blocks; i += 8)
357
46.8M
      borrow = word8_sub3(z + i, x + i, y + i, borrow);
358
359
55.6M
   for(size_t i = blocks; i != y_size; ++i)
360
43.1M
      z[i] = word_sub(x[i], y[i], &borrow);
361
362
32.1M
   for(size_t i = y_size; i != x_size; ++i)
363
19.7M
      z[i] = word_sub(x[i], 0, &borrow);
364
365
12.4M
   return borrow;
366
12.4M
   }
367
368
/**
369
* Return abs(x-y), ie if x >= y, then compute z = x - y
370
* Otherwise compute z = y - x
371
* No borrow is possible since the result is always >= 0
372
*
373
* Returns ~0 if x >= y or 0 if x < y
374
* @param z output array of at least N words
375
* @param x input array of N words
376
* @param y input array of N words
377
* @param N length of x and y
378
* @param ws array of at least 2*N words
379
*/
380
inline CT::Mask<word>
381
bigint_sub_abs(word z[],
382
               const word x[], const word y[], size_t N,
383
               word ws[])
384
570
   {
385
   // Subtract in both direction then conditional copy out the result
386
387
570
   word* ws0 = ws;
388
570
   word* ws1 = ws + N;
389
390
570
   word borrow0 = 0;
391
570
   word borrow1 = 0;
392
393
570
   const size_t blocks = N - (N % 8);
394
395
3.09k
   for(size_t i = 0; i != blocks; i += 8)
396
2.52k
      {
397
2.52k
      borrow0 = word8_sub3(ws0 + i, x + i, y + i, borrow0);
398
2.52k
      borrow1 = word8_sub3(ws1 + i, y + i, x + i, borrow1);
399
2.52k
      }
400
401
1.99k
   for(size_t i = blocks; i != N; ++i)
402
1.42k
      {
403
1.42k
      ws0[i] = word_sub(x[i], y[i], &borrow0);
404
1.42k
      ws1[i] = word_sub(y[i], x[i], &borrow1);
405
1.42k
      }
406
407
570
   return CT::conditional_copy_mem(borrow0, z, ws1, ws0, N);
408
570
   }
409
410
/*
411
* Shift Operations
412
*/
413
inline void bigint_shl1(word x[], size_t x_size, size_t x_words,
414
                        size_t word_shift, size_t bit_shift)
415
1.28k
   {
416
1.28k
   copy_mem(x + word_shift, x, x_words);
417
1.28k
   clear_mem(x, word_shift);
418
419
1.28k
   const auto carry_mask = CT::Mask<word>::expand(bit_shift);
420
1.28k
   const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift);
421
422
1.28k
   word carry = 0;
423
13.6k
   for(size_t i = word_shift; i != x_size; ++i)
424
12.3k
      {
425
12.3k
      const word w = x[i];
426
12.3k
      x[i] = (w << bit_shift) | carry;
427
12.3k
      carry = carry_mask.if_set_return(w >> carry_shift);
428
12.3k
      }
429
1.28k
   }
430
431
inline void bigint_shr1(word x[], size_t x_size,
432
                        size_t word_shift, size_t bit_shift)
433
14.3M
   {
434
14.3M
   const size_t top = x_size >= word_shift ? (x_size - word_shift) : 0;
435
436
14.3M
   if(top > 0)
437
14.2M
      copy_mem(x, x + word_shift, top);
438
14.3M
   clear_mem(x + top, std::min(word_shift, x_size));
439
440
14.3M
   const auto carry_mask = CT::Mask<word>::expand(bit_shift);
441
14.3M
   const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift);
442
443
14.3M
   word carry = 0;
444
445
1.72G
   for(size_t i = 0; i != top; ++i)
446
1.71G
      {
447
1.71G
      const word w = x[top - i - 1];
448
1.71G
      x[top-i-1] = (w >> bit_shift) | carry;
449
1.71G
      carry = carry_mask.if_set_return(w << carry_shift);
450
1.71G
      }
451
14.3M
   }
452
453
inline void bigint_shl2(word y[], const word x[], size_t x_size,
454
                        size_t word_shift, size_t bit_shift)
455
375
   {
456
375
   copy_mem(y + word_shift, x, x_size);
457
458
375
   const auto carry_mask = CT::Mask<word>::expand(bit_shift);
459
375
   const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift);
460
461
375
   word carry = 0;
462
5.70k
   for(size_t i = word_shift; i != x_size + word_shift + 1; ++i)
463
5.33k
      {
464
5.33k
      const word w = y[i];
465
5.33k
      y[i] = (w << bit_shift) | carry;
466
5.33k
      carry = carry_mask.if_set_return(w >> carry_shift);
467
5.33k
      }
468
375
   }
469
470
inline void bigint_shr2(word y[], const word x[], size_t x_size,
471
                        size_t word_shift, size_t bit_shift)
472
639k
   {
473
639k
   const size_t new_size = x_size < word_shift ? 0 : (x_size - word_shift);
474
475
639k
   if(new_size > 0)
476
639k
      copy_mem(y, x + word_shift, new_size);
477
478
639k
   const auto carry_mask = CT::Mask<word>::expand(bit_shift);
479
639k
   const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift);
480
481
639k
   word carry = 0;
482
7.05M
   for(size_t i = new_size; i > 0; --i)
483
6.41M
      {
484
6.41M
      word w = y[i-1];
485
6.41M
      y[i-1] = (w >> bit_shift) | carry;
486
6.41M
      carry = carry_mask.if_set_return(w << carry_shift);
487
6.41M
      }
488
639k
   }
489
490
/*
491
* Linear Multiply - returns the carry
492
*/
493
[[nodiscard]] inline word bigint_linmul2(word x[], size_t x_size, word y)
494
10.1M
   {
495
10.1M
   const size_t blocks = x_size - (x_size % 8);
496
497
10.1M
   word carry = 0;
498
499
100M
   for(size_t i = 0; i != blocks; i += 8)
500
90.7M
      carry = word8_linmul2(x + i, y, carry);
501
502
24.4M
   for(size_t i = blocks; i != x_size; ++i)
503
14.3M
      x[i] = word_madd2(x[i], y, &carry);
504
505
10.1M
   return carry;
506
10.1M
   }
507
508
inline void bigint_linmul3(word z[], const word x[], size_t x_size, word y)
509
6.87k
   {
510
6.87k
   const size_t blocks = x_size - (x_size % 8);
511
512
6.87k
   word carry = 0;
513
514
39.8k
   for(size_t i = 0; i != blocks; i += 8)
515
32.9k
      carry = word8_linmul3(z + i, x + i, y, carry);
516
517
31.4k
   for(size_t i = blocks; i != x_size; ++i)
518
24.5k
      z[i] = word_madd2(x[i], y, &carry);
519
520
6.87k
   z[x_size] = carry;
521
6.87k
   }
522
523
/**
524
* Compare x and y
525
* Return -1 if x < y
526
* Return 0 if x == y
527
* Return 1 if x > y
528
*/
529
inline int32_t bigint_cmp(const word x[], size_t x_size,
530
                          const word y[], size_t y_size)
531
2.62M
   {
532
2.62M
   static_assert(sizeof(word) >= sizeof(uint32_t), "Size assumption");
533
534
2.62M
   const word LT = static_cast<word>(-1);
535
2.62M
   const word EQ = 0;
536
2.62M
   const word GT = 1;
537
538
2.62M
   const size_t common_elems = std::min(x_size, y_size);
539
540
2.62M
   word result = EQ; // until found otherwise
541
542
101M
   for(size_t i = 0; i != common_elems; i++)
543
99.0M
      {
544
99.0M
      const auto is_eq = CT::Mask<word>::is_equal(x[i], y[i]);
545
99.0M
      const auto is_lt = CT::Mask<word>::is_lt(x[i], y[i]);
546
547
99.0M
      result = is_eq.select(result, is_lt.select(LT, GT));
548
99.0M
      }
549
550
2.62M
   if(x_size < y_size)
551
85.8k
      {
552
85.8k
      word mask = 0;
553
864k
      for(size_t i = x_size; i != y_size; i++)
554
778k
         mask |= y[i];
555
556
      // If any bits were set in high part of y, then x < y
557
85.8k
      result = CT::Mask<word>::is_zero(mask).select(result, LT);
558
85.8k
      }
559
2.53M
   else if(y_size < x_size)
560
724k
      {
561
724k
      word mask = 0;
562
2.68M
      for(size_t i = y_size; i != x_size; i++)
563
1.95M
         mask |= x[i];
564
565
      // If any bits were set in high part of x, then x > y
566
724k
      result = CT::Mask<word>::is_zero(mask).select(result, GT);
567
724k
      }
568
569
2.62M
   CT::unpoison(result);
570
2.62M
   BOTAN_DEBUG_ASSERT(result == LT || result == GT || result == EQ);
571
2.62M
   return static_cast<int32_t>(result);
572
2.62M
   }
573
574
/**
575
* Compare x and y
576
* Return ~0 if x[0:x_size] < y[0:y_size] or 0 otherwise
577
* If lt_or_equal is true, returns ~0 also for x == y
578
*/
579
inline CT::Mask<word>
580
bigint_ct_is_lt(const word x[], size_t x_size,
581
                const word y[], size_t y_size,
582
                bool lt_or_equal = false)
583
2.34M
   {
584
2.34M
   const size_t common_elems = std::min(x_size, y_size);
585
586
2.34M
   auto is_lt = CT::Mask<word>::expand(lt_or_equal);
587
588
15.6M
   for(size_t i = 0; i != common_elems; i++)
589
13.2M
      {
590
13.2M
      const auto eq = CT::Mask<word>::is_equal(x[i], y[i]);
591
13.2M
      const auto lt = CT::Mask<word>::is_lt(x[i], y[i]);
592
13.2M
      is_lt = eq.select_mask(is_lt, lt);
593
13.2M
      }
594
595
2.34M
   if(x_size < y_size)
596
229
      {
597
229
      word mask = 0;
598
2.65k
      for(size_t i = x_size; i != y_size; i++)
599
2.42k
         mask |= y[i];
600
      // If any bits were set in high part of y, then is_lt should be forced true
601
229
      is_lt |= CT::Mask<word>::expand(mask);
602
229
      }
603
2.34M
   else if(y_size < x_size)
604
1.24k
      {
605
1.24k
      word mask = 0;
606
10.6k
      for(size_t i = y_size; i != x_size; i++)
607
9.43k
         mask |= x[i];
608
609
      // If any bits were set in high part of x, then is_lt should be false
610
1.24k
      is_lt &= CT::Mask<word>::is_zero(mask);
611
1.24k
      }
612
613
2.34M
   return is_lt;
614
2.34M
   }
615
616
inline CT::Mask<word>
617
bigint_ct_is_eq(const word x[], size_t x_size,
618
                const word y[], size_t y_size)
619
5.31k
   {
620
5.31k
   const size_t common_elems = std::min(x_size, y_size);
621
622
5.31k
   word diff = 0;
623
624
27.1k
   for(size_t i = 0; i != common_elems; i++)
625
21.8k
      {
626
21.8k
      diff |= (x[i] ^ y[i]);
627
21.8k
      }
628
629
   // If any bits were set in high part of x/y, then they are not equal
630
5.31k
   if(x_size < y_size)
631
325
      {
632
1.92k
      for(size_t i = x_size; i != y_size; i++)
633
1.59k
         diff |= y[i];
634
325
      }
635
4.98k
   else if(y_size < x_size)
636
281
      {
637
1.09k
      for(size_t i = y_size; i != x_size; i++)
638
813
         diff |= x[i];
639
281
      }
640
641
5.31k
   return CT::Mask<word>::is_zero(diff);
642
5.31k
   }
643
644
/**
645
* Set z to abs(x-y), ie if x >= y, then compute z = x - y
646
* Otherwise compute z = y - x
647
* No borrow is possible since the result is always >= 0
648
*
649
* Return the relative size of x vs y (-1, 0, 1)
650
*
651
* @param z output array of max(x_size,y_size) words
652
* @param x input param
653
* @param x_size length of x
654
* @param y input param
655
* @param y_size length of y
656
*/
657
inline int32_t
658
bigint_sub_abs(word z[],
659
               const word x[], size_t x_size,
660
               const word y[], size_t y_size)
661
2.60M
   {
662
2.60M
   const int32_t relative_size = bigint_cmp(x, x_size, y, y_size);
663
664
   // Swap if relative_size == -1
665
2.60M
   const bool need_swap = relative_size < 0;
666
2.60M
   CT::conditional_swap_ptr(need_swap, x, y);
667
2.60M
   CT::conditional_swap(need_swap, x_size, y_size);
668
669
   /*
670
   * We know at this point that x >= y so if y_size is larger than
671
   * x_size, we are guaranteed they are just leading zeros which can
672
   * be ignored
673
   */
674
2.60M
   y_size = std::min(x_size, y_size);
675
676
2.60M
   bigint_sub3(z, x, x_size, y, y_size);
677
678
2.60M
   return relative_size;
679
2.60M
   }
680
681
/**
682
* Set t to t-s modulo mod
683
*
684
* @param t first integer
685
* @param s second integer
686
* @param mod the modulus
687
* @param mod_sw size of t, s, and mod
688
* @param ws workspace of size mod_sw
689
*/
690
inline void
691
bigint_mod_sub(word t[], const word s[], const word mod[], size_t mod_sw, word ws[])
692
752k
   {
693
   // is t < s or not?
694
752k
   const auto is_lt = bigint_ct_is_lt(t, mod_sw, s, mod_sw);
695
696
   // ws = p - s
697
752k
   const word borrow = bigint_sub3(ws, mod, mod_sw, s, mod_sw);
698
699
   // Compute either (t - s) or (t + (p - s)) depending on mask
700
752k
   const word carry = bigint_cnd_addsub(is_lt, t, ws, s, mod_sw);
701
702
752k
   BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0);
703
752k
   BOTAN_UNUSED(carry, borrow);
704
752k
   }
705
706
template<size_t N>
707
inline void bigint_mod_sub_n(word t[], const word s[], const word mod[], word ws[])
708
1.57M
   {
709
   // is t < s or not?
710
1.57M
   const auto is_lt = bigint_ct_is_lt(t, N, s, N);
711
712
   // ws = p - s
713
1.57M
   const word borrow = bigint_sub3(ws, mod, N, s, N);
714
715
   // Compute either (t - s) or (t + (p - s)) depending on mask
716
1.57M
   const word carry = bigint_cnd_addsub(is_lt, t, ws, s, N);
717
718
1.57M
   BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0);
719
1.57M
   BOTAN_UNUSED(carry, borrow);
720
1.57M
   }
void Botan::bigint_mod_sub_n<4ul>(unsigned long*, unsigned long const*, unsigned long const*, unsigned long*)
Line
Count
Source
708
784k
   {
709
   // is t < s or not?
710
784k
   const auto is_lt = bigint_ct_is_lt(t, N, s, N);
711
712
   // ws = p - s
713
784k
   const word borrow = bigint_sub3(ws, mod, N, s, N);
714
715
   // Compute either (t - s) or (t + (p - s)) depending on mask
716
784k
   const word carry = bigint_cnd_addsub(is_lt, t, ws, s, N);
717
718
784k
   BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0);
719
784k
   BOTAN_UNUSED(carry, borrow);
720
784k
   }
void Botan::bigint_mod_sub_n<6ul>(unsigned long*, unsigned long const*, unsigned long const*, unsigned long*)
Line
Count
Source
708
790k
   {
709
   // is t < s or not?
710
790k
   const auto is_lt = bigint_ct_is_lt(t, N, s, N);
711
712
   // ws = p - s
713
790k
   const word borrow = bigint_sub3(ws, mod, N, s, N);
714
715
   // Compute either (t - s) or (t + (p - s)) depending on mask
716
790k
   const word carry = bigint_cnd_addsub(is_lt, t, ws, s, N);
717
718
790k
   BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0);
719
790k
   BOTAN_UNUSED(carry, borrow);
720
790k
   }
721
722
/**
723
* Compute ((n1<<bits) + n0) / d
724
*/
725
inline word bigint_divop(word n1, word n0, word d)
726
5.02k
   {
727
5.02k
   if(d == 0)
728
0
      throw Invalid_Argument("bigint_divop divide by zero");
729
730
5.02k
#if defined(BOTAN_HAS_MP_DWORD)
731
5.02k
   return static_cast<word>(((static_cast<dword>(n1) << BOTAN_MP_WORD_BITS) | n0) / d);
732
#else
733
734
   word high = n1 % d;
735
   word quotient = 0;
736
737
   for(size_t i = 0; i != BOTAN_MP_WORD_BITS; ++i)
738
      {
739
      const word high_top_bit = high >> (BOTAN_MP_WORD_BITS-1);
740
741
      high <<= 1;
742
      high |= (n0 >> (BOTAN_MP_WORD_BITS-1-i)) & 1;
743
      quotient <<= 1;
744
745
      if(high_top_bit || high >= d)
746
         {
747
         high -= d;
748
         quotient |= 1;
749
         }
750
      }
751
752
   return quotient;
753
#endif
754
5.02k
   }
755
756
/**
757
* Compute ((n1<<bits) + n0) % d
758
*/
759
inline word bigint_modop(word n1, word n0, word d)
760
1.01k
   {
761
1.01k
   if(d == 0)
762
0
      throw Invalid_Argument("bigint_modop divide by zero");
763
764
1.01k
#if defined(BOTAN_HAS_MP_DWORD)
765
1.01k
   return ((static_cast<dword>(n1) << BOTAN_MP_WORD_BITS) | n0) % d;
766
#else
767
   word z = bigint_divop(n1, n0, d);
768
   word dummy = 0;
769
   z = word_madd2(z, d, &dummy);
770
   return (n0-z);
771
#endif
772
1.01k
   }
773
774
/*
775
* Comba Multiplication / Squaring
776
*/
777
BOTAN_FUZZER_API void bigint_comba_mul4(word z[8], const word x[4], const word y[4]);
778
BOTAN_FUZZER_API void bigint_comba_mul6(word z[12], const word x[6], const word y[6]);
779
BOTAN_FUZZER_API void bigint_comba_mul8(word z[16], const word x[8], const word y[8]);
780
BOTAN_FUZZER_API void bigint_comba_mul9(word z[18], const word x[9], const word y[9]);
781
BOTAN_FUZZER_API void bigint_comba_mul16(word z[32], const word x[16], const word y[16]);
782
BOTAN_FUZZER_API void bigint_comba_mul24(word z[48], const word x[24], const word y[24]);
783
784
BOTAN_FUZZER_API void bigint_comba_sqr4(word out[8], const word in[4]);
785
BOTAN_FUZZER_API void bigint_comba_sqr6(word out[12], const word in[6]);
786
BOTAN_FUZZER_API void bigint_comba_sqr8(word out[16], const word in[8]);
787
BOTAN_FUZZER_API void bigint_comba_sqr9(word out[18], const word in[9]);
788
BOTAN_FUZZER_API void bigint_comba_sqr16(word out[32], const word in[16]);
789
BOTAN_FUZZER_API void bigint_comba_sqr24(word out[48], const word in[24]);
790
791
/*
792
* Montgomery reduction
793
*
794
* Each of these functions makes the following assumptions:
795
*
796
* z_size == 2*p_size
797
* ws_size >= p_size + 1
798
*/
799
BOTAN_FUZZER_API void bigint_monty_redc_4(word z[8], const word p[4], word p_dash, word ws[]);
800
BOTAN_FUZZER_API void bigint_monty_redc_6(word z[12], const word p[6], word p_dash, word ws[]);
801
BOTAN_FUZZER_API void bigint_monty_redc_8(word z[16], const word p[8], word p_dash, word ws[]);
802
BOTAN_FUZZER_API void bigint_monty_redc_16(word z[32], const word p[16], word p_dash, word ws[]);
803
BOTAN_FUZZER_API void bigint_monty_redc_24(word z[48], const word p[24], word p_dash, word ws[]);
804
BOTAN_FUZZER_API void bigint_monty_redc_32(word z[64], const word p[32], word p_dash, word ws[]);
805
806
BOTAN_FUZZER_API
807
void bigint_monty_redc_generic(word z[], size_t z_size,
808
                               const word p[], size_t p_size, word p_dash,
809
                               word ws[]);
810
811
812
/**
813
* Montgomery Reduction
814
* @param z integer to reduce, of size exactly 2*p_size.
815
           Output is in the first p_size+1 words, higher
816
           words are set to zero.
817
* @param p modulus
818
* @param p_size size of p
819
* @param p_dash Montgomery value
820
* @param ws array of at least p_size+1 words
821
* @param ws_size size of ws in words
822
*/
823
inline void bigint_monty_redc(word z[],
824
                              const word p[], size_t p_size,
825
                              word p_dash,
826
                              word ws[],
827
                              size_t ws_size)
828
2.21M
   {
829
2.21M
   const size_t z_size = 2*p_size;
830
831
2.21M
   BOTAN_ARG_CHECK(ws_size >= p_size + 1,
832
2.21M
                   "Montgomery workspace too small");
833
834
2.21M
   if(p_size == 4)
835
915k
      bigint_monty_redc_4(z, p, p_dash, ws);
836
1.29M
   else if(p_size == 6)
837
773k
      bigint_monty_redc_6(z, p, p_dash, ws);
838
525k
   else if(p_size == 8)
839
525k
      bigint_monty_redc_8(z, p, p_dash, ws);
840
0
   else if(p_size == 16)
841
0
      bigint_monty_redc_16(z, p, p_dash, ws);
842
0
   else if(p_size == 24)
843
0
      bigint_monty_redc_24(z, p, p_dash, ws);
844
0
   else if(p_size == 32)
845
0
      bigint_monty_redc_32(z, p, p_dash, ws);
846
0
   else
847
0
      bigint_monty_redc_generic(z, z_size, p, p_size, p_dash, ws);
848
2.21M
   }
849
850
/**
851
* Basecase O(N^2) multiplication
852
*/
853
BOTAN_FUZZER_API
854
void basecase_mul(word z[], size_t z_size,
855
                  const word x[], size_t x_size,
856
                  const word y[], size_t y_size);
857
858
/**
859
* Basecase O(N^2) squaring
860
*/
861
BOTAN_FUZZER_API
862
void basecase_sqr(word z[], size_t z_size,
863
                  const word x[], size_t x_size);
864
865
866
/*
867
* High Level Multiplication/Squaring Interfaces
868
*/
869
void bigint_mul(word z[], size_t z_size,
870
                const word x[], size_t x_size, size_t x_sw,
871
                const word y[], size_t y_size, size_t y_sw,
872
                word workspace[], size_t ws_size);
873
874
void bigint_sqr(word z[], size_t z_size,
875
                const word x[], size_t x_size, size_t x_sw,
876
                word workspace[], size_t ws_size);
877
878
}
879
880
#endif