Coverage Report

Created: 2023-06-07 06:59

/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/exceptn.h>
14
#include <botan/mem_ops.h>
15
#include <botan/types.h>
16
#include <botan/internal/ct_utils.h>
17
#include <botan/internal/mp_asmi.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
2.33M
inline void bigint_cnd_swap(word cnd, word x[], word y[], size_t size) {
30
2.33M
   const auto mask = CT::Mask<word>::expand(cnd);
31
32
54.5M
   for(size_t i = 0; i != size; ++i) {
33
52.2M
      const word a = x[i];
34
52.2M
      const word b = y[i];
35
52.2M
      x[i] = mask.select(b, a);
36
52.2M
      y[i] = mask.select(a, b);
37
52.2M
   }
38
2.33M
}
39
40
0
inline word bigint_cnd_add(word cnd, word x[], word x_size, const word y[], size_t y_size) {
41
0
   BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
42
43
0
   const auto mask = CT::Mask<word>::expand(cnd);
44
45
0
   word carry = 0;
46
47
0
   const size_t blocks = y_size - (y_size % 8);
48
0
   word z[8] = {0};
49
50
0
   for(size_t i = 0; i != blocks; i += 8) {
51
0
      carry = word8_add3(z, x + i, y + i, carry);
52
0
      mask.select_n(x + i, z, x + i, 8);
53
0
   }
54
55
0
   for(size_t i = blocks; i != y_size; ++i) {
56
0
      z[0] = word_add(x[i], y[i], &carry);
57
0
      x[i] = mask.select(z[0], x[i]);
58
0
   }
59
60
0
   for(size_t i = y_size; i != x_size; ++i) {
61
0
      z[0] = word_add(x[i], 0, &carry);
62
0
      x[i] = mask.select(z[0], x[i]);
63
0
   }
64
65
0
   return mask.if_set_return(carry);
66
0
}
67
68
/*
69
* If cond > 0 adds x[0:size] and y[0:size] and returns carry
70
* Runs in constant time
71
*/
72
0
inline word bigint_cnd_add(word cnd, word x[], const word y[], size_t size) {
73
0
   return bigint_cnd_add(cnd, x, size, y, size);
74
0
}
75
76
/*
77
* If cond > 0 subtracts x[0:size] and y[0:size] and returns borrow
78
* Runs in constant time
79
*/
80
0
inline word bigint_cnd_sub(word cnd, word x[], size_t x_size, const word y[], size_t y_size) {
81
0
   BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
82
0
83
0
   const auto mask = CT::Mask<word>::expand(cnd);
84
0
85
0
   word carry = 0;
86
0
87
0
   const size_t blocks = y_size - (y_size % 8);
88
0
   word z[8] = {0};
89
0
90
0
   for(size_t i = 0; i != blocks; i += 8) {
91
0
      carry = word8_sub3(z, x + i, y + i, carry);
92
0
      mask.select_n(x + i, z, x + i, 8);
93
0
   }
94
0
95
0
   for(size_t i = blocks; i != y_size; ++i) {
96
0
      z[0] = word_sub(x[i], y[i], &carry);
97
0
      x[i] = mask.select(z[0], x[i]);
98
0
   }
99
0
100
0
   for(size_t i = y_size; i != x_size; ++i) {
101
0
      z[0] = word_sub(x[i], 0, &carry);
102
0
      x[i] = mask.select(z[0], x[i]);
103
0
   }
104
0
105
0
   return mask.if_set_return(carry);
106
0
}
107
108
/*
109
* If cond > 0 adds x[0:size] and y[0:size] and returns carry
110
* Runs in constant time
111
*/
112
0
inline word bigint_cnd_sub(word cnd, word x[], const word y[], size_t size) {
113
0
   return bigint_cnd_sub(cnd, x, size, y, size);
114
0
}
115
116
/*
117
* Equivalent to
118
*   bigint_cnd_add( mask, x, y, size);
119
*   bigint_cnd_sub(~mask, x, y, size);
120
*
121
* Mask must be either 0 or all 1 bits
122
*/
123
42
inline void bigint_cnd_add_or_sub(CT::Mask<word> mask, word x[], const word y[], size_t size) {
124
42
   const size_t blocks = size - (size % 8);
125
126
42
   word carry = 0;
127
42
   word borrow = 0;
128
129
42
   word t0[8] = {0};
130
42
   word t1[8] = {0};
131
132
325
   for(size_t i = 0; i != blocks; i += 8) {
133
283
      carry = word8_add3(t0, x + i, y + i, carry);
134
283
      borrow = word8_sub3(t1, x + i, y + i, borrow);
135
136
2.54k
      for(size_t j = 0; j != 8; ++j)
137
2.26k
         x[i + j] = mask.select(t0[j], t1[j]);
138
283
   }
139
140
166
   for(size_t i = blocks; i != size; ++i) {
141
124
      const word a = word_add(x[i], y[i], &carry);
142
124
      const word s = word_sub(x[i], y[i], &borrow);
143
144
124
      x[i] = mask.select(a, s);
145
124
   }
146
42
}
147
148
/*
149
* Equivalent to
150
*   bigint_cnd_add( mask, x, size, y, size);
151
*   bigint_cnd_sub(~mask, x, size, z, size);
152
*
153
* Mask must be either 0 or all 1 bits
154
*
155
* Returns the carry or borrow resp
156
*/
157
0
inline word bigint_cnd_addsub(CT::Mask<word> mask, word x[], const word y[], const word z[], size_t size) {
158
0
   const size_t blocks = size - (size % 8);
159
160
0
   word carry = 0;
161
0
   word borrow = 0;
162
163
0
   word t0[8] = {0};
164
0
   word t1[8] = {0};
165
166
0
   for(size_t i = 0; i != blocks; i += 8) {
167
0
      carry = word8_add3(t0, x + i, y + i, carry);
168
0
      borrow = word8_sub3(t1, x + i, z + i, borrow);
169
170
0
      for(size_t j = 0; j != 8; ++j)
171
0
         x[i + j] = mask.select(t0[j], t1[j]);
172
0
   }
173
174
0
   for(size_t i = blocks; i != size; ++i) {
175
0
      t0[0] = word_add(x[i], y[i], &carry);
176
0
      t1[0] = word_sub(x[i], z[i], &borrow);
177
0
      x[i] = mask.select(t0[0], t1[0]);
178
0
   }
179
180
0
   return mask.select(carry, borrow);
181
0
}
182
183
/*
184
* 2s complement absolute value
185
* If cond > 0 sets x to ~x + 1
186
* Runs in constant time
187
*/
188
0
inline void bigint_cnd_abs(word cnd, word x[], size_t size) {
189
0
   const auto mask = CT::Mask<word>::expand(cnd);
190
0
191
0
   word carry = mask.if_set_return(1);
192
0
   for(size_t i = 0; i != size; ++i) {
193
0
      const word z = word_add(~x[i], 0, &carry);
194
0
      x[i] = mask.select(z, x[i]);
195
0
   }
196
0
}
197
198
/**
199
* Two operand addition with carry out
200
*/
201
10.1k
inline word bigint_add2_nc(word x[], size_t x_size, const word y[], size_t y_size) {
202
10.1k
   word carry = 0;
203
204
10.1k
   BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
205
206
10.1k
   const size_t blocks = y_size - (y_size % 8);
207
208
10.8k
   for(size_t i = 0; i != blocks; i += 8)
209
708
      carry = word8_add2(x + i, y + i, carry);
210
211
16.0k
   for(size_t i = blocks; i != y_size; ++i)
212
5.87k
      x[i] = word_add(x[i], y[i], &carry);
213
214
410k
   for(size_t i = y_size; i != x_size; ++i)
215
400k
      x[i] = word_add(x[i], 0, &carry);
216
217
10.1k
   return carry;
218
10.1k
}
219
220
/**
221
* Three operand addition with carry out
222
*/
223
42
inline word bigint_add3_nc(word z[], const word x[], size_t x_size, const word y[], size_t y_size) {
224
42
   if(x_size < y_size) {
225
0
      return bigint_add3_nc(z, y, y_size, x, x_size);
226
0
   }
227
228
42
   word carry = 0;
229
230
42
   const size_t blocks = y_size - (y_size % 8);
231
232
229
   for(size_t i = 0; i != blocks; i += 8)
233
187
      carry = word8_add3(z + i, x + i, y + i, carry);
234
235
138
   for(size_t i = blocks; i != y_size; ++i)
236
96
      z[i] = word_add(x[i], y[i], &carry);
237
238
42
   for(size_t i = y_size; i != x_size; ++i)
239
0
      z[i] = word_add(x[i], 0, &carry);
240
241
42
   return carry;
242
42
}
243
244
/**
245
* Two operand addition
246
* @param x the first operand (and output)
247
* @param x_size size of x
248
* @param y the second operand
249
* @param y_size size of y (must be <= x_size)
250
*/
251
10.0k
inline void bigint_add2(word x[], size_t x_size, const word y[], size_t y_size) {
252
10.0k
   x[x_size] += bigint_add2_nc(x, x_size, y, y_size);
253
10.0k
}
254
255
/**
256
* Three operand addition
257
*/
258
0
inline void bigint_add3(word z[], const word x[], size_t x_size, const word y[], size_t y_size) {
259
0
   z[x_size > y_size ? x_size : y_size] += bigint_add3_nc(z, x, x_size, y, y_size);
260
0
}
261
262
/**
263
* Two operand subtraction
264
*/
265
7.95k
inline word bigint_sub2(word x[], size_t x_size, const word y[], size_t y_size) {
266
7.95k
   word borrow = 0;
267
268
7.95k
   BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
269
270
7.95k
   const size_t blocks = y_size - (y_size % 8);
271
272
30.5k
   for(size_t i = 0; i != blocks; i += 8)
273
22.6k
      borrow = word8_sub2(x + i, y + i, borrow);
274
275
30.5k
   for(size_t i = blocks; i != y_size; ++i)
276
22.5k
      x[i] = word_sub(x[i], y[i], &borrow);
277
278
39.2k
   for(size_t i = y_size; i != x_size; ++i)
279
31.3k
      x[i] = word_sub(x[i], 0, &borrow);
280
281
7.95k
   return borrow;
282
7.95k
}
283
284
/**
285
* Two operand subtraction, x = y - x; assumes y >= x
286
*/
287
1.05k
inline void bigint_sub2_rev(word x[], const word y[], size_t y_size) {
288
1.05k
   word borrow = 0;
289
290
1.05k
   const size_t blocks = y_size - (y_size % 8);
291
292
3.37k
   for(size_t i = 0; i != blocks; i += 8)
293
2.32k
      borrow = word8_sub2_rev(x + i, y + i, borrow);
294
295
4.66k
   for(size_t i = blocks; i != y_size; ++i)
296
3.60k
      x[i] = word_sub(y[i], x[i], &borrow);
297
298
1.05k
   BOTAN_ASSERT(borrow == 0, "y must be greater than x");
299
1.05k
}
300
301
/**
302
* Three operand subtraction
303
*
304
* Expects that x_size >= y_size
305
*
306
* Writes to z[0:x_size] and returns borrow
307
*/
308
2.34M
inline word bigint_sub3(word z[], const word x[], size_t x_size, const word y[], size_t y_size) {
309
2.34M
   word borrow = 0;
310
311
2.34M
   BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
312
313
2.34M
   const size_t blocks = y_size - (y_size % 8);
314
315
6.54M
   for(size_t i = 0; i != blocks; i += 8)
316
4.19M
      borrow = word8_sub3(z + i, x + i, y + i, borrow);
317
318
8.86M
   for(size_t i = blocks; i != y_size; ++i)
319
6.51M
      z[i] = word_sub(x[i], y[i], &borrow);
320
321
14.5M
   for(size_t i = y_size; i != x_size; ++i)
322
12.2M
      z[i] = word_sub(x[i], 0, &borrow);
323
324
2.34M
   return borrow;
325
2.34M
}
326
327
/**
328
* Return abs(x-y), ie if x >= y, then compute z = x - y
329
* Otherwise compute z = y - x
330
* No borrow is possible since the result is always >= 0
331
*
332
* Returns ~0 if x >= y or 0 if x < y
333
* @param z output array of at least N words
334
* @param x input array of N words
335
* @param y input array of N words
336
* @param N length of x and y
337
* @param ws array of at least 2*N words
338
*/
339
84
inline CT::Mask<word> bigint_sub_abs(word z[], const word x[], const word y[], size_t N, word ws[]) {
340
   // Subtract in both direction then conditional copy out the result
341
342
84
   word* ws0 = ws;
343
84
   word* ws1 = ws + N;
344
345
84
   word borrow0 = 0;
346
84
   word borrow1 = 0;
347
348
84
   const size_t blocks = N - (N % 8);
349
350
252
   for(size_t i = 0; i != blocks; i += 8) {
351
168
      borrow0 = word8_sub3(ws0 + i, x + i, y + i, borrow0);
352
168
      borrow1 = word8_sub3(ws1 + i, y + i, x + i, borrow1);
353
168
   }
354
355
332
   for(size_t i = blocks; i != N; ++i) {
356
248
      ws0[i] = word_sub(x[i], y[i], &borrow0);
357
248
      ws1[i] = word_sub(y[i], x[i], &borrow1);
358
248
   }
359
360
84
   return CT::conditional_copy_mem(borrow0, z, ws1, ws0, N);
361
84
}
362
363
/*
364
* Shift Operations
365
*/
366
1.74k
inline void bigint_shl1(word x[], size_t x_size, size_t x_words, size_t word_shift, size_t bit_shift) {
367
1.74k
   copy_mem(x + word_shift, x, x_words);
368
1.74k
   clear_mem(x, word_shift);
369
370
1.74k
   const auto carry_mask = CT::Mask<word>::expand(bit_shift);
371
1.74k
   const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift);
372
373
1.74k
   word carry = 0;
374
23.3k
   for(size_t i = word_shift; i != x_size; ++i) {
375
21.6k
      const word w = x[i];
376
21.6k
      x[i] = (w << bit_shift) | carry;
377
21.6k
      carry = carry_mask.if_set_return(w >> carry_shift);
378
21.6k
   }
379
1.74k
}
380
381
12.5k
inline void bigint_shr1(word x[], size_t x_size, size_t word_shift, size_t bit_shift) {
382
12.5k
   const size_t top = x_size >= word_shift ? (x_size - word_shift) : 0;
383
384
12.5k
   if(top > 0)
385
12.5k
      copy_mem(x, x + word_shift, top);
386
12.5k
   clear_mem(x + top, std::min(word_shift, x_size));
387
388
12.5k
   const auto carry_mask = CT::Mask<word>::expand(bit_shift);
389
12.5k
   const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift);
390
391
12.5k
   word carry = 0;
392
393
468k
   for(size_t i = 0; i != top; ++i) {
394
455k
      const word w = x[top - i - 1];
395
455k
      x[top - i - 1] = (w >> bit_shift) | carry;
396
455k
      carry = carry_mask.if_set_return(w << carry_shift);
397
455k
   }
398
12.5k
}
399
400
872
inline void bigint_shl2(word y[], const word x[], size_t x_size, size_t word_shift, size_t bit_shift) {
401
872
   copy_mem(y + word_shift, x, x_size);
402
403
872
   const auto carry_mask = CT::Mask<word>::expand(bit_shift);
404
872
   const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift);
405
406
872
   word carry = 0;
407
8.34k
   for(size_t i = word_shift; i != x_size + word_shift + 1; ++i) {
408
7.47k
      const word w = y[i];
409
7.47k
      y[i] = (w << bit_shift) | carry;
410
7.47k
      carry = carry_mask.if_set_return(w >> carry_shift);
411
7.47k
   }
412
872
}
413
414
0
inline void bigint_shr2(word y[], const word x[], size_t x_size, size_t word_shift, size_t bit_shift) {
415
0
   const size_t new_size = x_size < word_shift ? 0 : (x_size - word_shift);
416
417
0
   if(new_size > 0)
418
0
      copy_mem(y, x + word_shift, new_size);
419
420
0
   const auto carry_mask = CT::Mask<word>::expand(bit_shift);
421
0
   const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift);
422
423
0
   word carry = 0;
424
0
   for(size_t i = new_size; i > 0; --i) {
425
0
      word w = y[i - 1];
426
0
      y[i - 1] = (w >> bit_shift) | carry;
427
0
      carry = carry_mask.if_set_return(w << carry_shift);
428
0
   }
429
0
}
430
431
/*
432
* Linear Multiply - returns the carry
433
*/
434
2.33M
[[nodiscard]] inline word bigint_linmul2(word x[], size_t x_size, word y) {
435
2.33M
   const size_t blocks = x_size - (x_size % 8);
436
437
2.33M
   word carry = 0;
438
439
8.86M
   for(size_t i = 0; i != blocks; i += 8)
440
6.52M
      carry = word8_linmul2(x + i, y, carry);
441
442
2.33M
   for(size_t i = blocks; i != x_size; ++i)
443
246
      x[i] = word_madd2(x[i], y, &carry);
444
445
2.33M
   return carry;
446
2.33M
}
447
448
8.46k
inline void bigint_linmul3(word z[], const word x[], size_t x_size, word y) {
449
8.46k
   const size_t blocks = x_size - (x_size % 8);
450
451
8.46k
   word carry = 0;
452
453
32.5k
   for(size_t i = 0; i != blocks; i += 8)
454
24.1k
      carry = word8_linmul3(z + i, x + i, y, carry);
455
456
35.5k
   for(size_t i = blocks; i != x_size; ++i)
457
27.0k
      z[i] = word_madd2(x[i], y, &carry);
458
459
8.46k
   z[x_size] = carry;
460
8.46k
}
461
462
/**
463
* Compare x and y
464
* Return -1 if x < y
465
* Return 0 if x == y
466
* Return 1 if x > y
467
*/
468
15.5k
inline int32_t bigint_cmp(const word x[], size_t x_size, const word y[], size_t y_size) {
469
15.5k
   static_assert(sizeof(word) >= sizeof(uint32_t), "Size assumption");
470
471
15.5k
   const word LT = static_cast<word>(-1);
472
15.5k
   const word EQ = 0;
473
15.5k
   const word GT = 1;
474
475
15.5k
   const size_t common_elems = std::min(x_size, y_size);
476
477
15.5k
   word result = EQ;  // until found otherwise
478
479
259k
   for(size_t i = 0; i != common_elems; i++) {
480
244k
      const auto is_eq = CT::Mask<word>::is_equal(x[i], y[i]);
481
244k
      const auto is_lt = CT::Mask<word>::is_lt(x[i], y[i]);
482
483
244k
      result = is_eq.select(result, is_lt.select(LT, GT));
484
244k
   }
485
486
15.5k
   if(x_size < y_size) {
487
2.30k
      word mask = 0;
488
15.3k
      for(size_t i = x_size; i != y_size; i++)
489
13.0k
         mask |= y[i];
490
491
      // If any bits were set in high part of y, then x < y
492
2.30k
      result = CT::Mask<word>::is_zero(mask).select(result, LT);
493
13.2k
   } else if(y_size < x_size) {
494
1.81k
      word mask = 0;
495
34.2k
      for(size_t i = y_size; i != x_size; i++)
496
32.4k
         mask |= x[i];
497
498
      // If any bits were set in high part of x, then x > y
499
1.81k
      result = CT::Mask<word>::is_zero(mask).select(result, GT);
500
1.81k
   }
501
502
15.5k
   CT::unpoison(result);
503
15.5k
   BOTAN_DEBUG_ASSERT(result == LT || result == GT || result == EQ);
504
15.5k
   return static_cast<int32_t>(result);
505
15.5k
}
506
507
/**
508
* Compare x and y
509
* Return ~0 if x[0:x_size] < y[0:y_size] or 0 otherwise
510
* If lt_or_equal is true, returns ~0 also for x == y
511
*/
512
inline CT::Mask<word> bigint_ct_is_lt(
513
17.8k
   const word x[], size_t x_size, const word y[], size_t y_size, bool lt_or_equal = false) {
514
17.8k
   const size_t common_elems = std::min(x_size, y_size);
515
516
17.8k
   auto is_lt = CT::Mask<word>::expand(lt_or_equal);
517
518
72.8k
   for(size_t i = 0; i != common_elems; i++) {
519
55.0k
      const auto eq = CT::Mask<word>::is_equal(x[i], y[i]);
520
55.0k
      const auto lt = CT::Mask<word>::is_lt(x[i], y[i]);
521
55.0k
      is_lt = eq.select_mask(is_lt, lt);
522
55.0k
   }
523
524
17.8k
   if(x_size < y_size) {
525
110
      word mask = 0;
526
576
      for(size_t i = x_size; i != y_size; i++)
527
466
         mask |= y[i];
528
      // If any bits were set in high part of y, then is_lt should be forced true
529
110
      is_lt |= CT::Mask<word>::expand(mask);
530
17.7k
   } else if(y_size < x_size) {
531
569
      word mask = 0;
532
4.69k
      for(size_t i = y_size; i != x_size; i++)
533
4.12k
         mask |= x[i];
534
535
      // If any bits were set in high part of x, then is_lt should be false
536
569
      is_lt &= CT::Mask<word>::is_zero(mask);
537
569
   }
538
539
17.8k
   return is_lt;
540
17.8k
}
541
542
3.69k
inline CT::Mask<word> bigint_ct_is_eq(const word x[], size_t x_size, const word y[], size_t y_size) {
543
3.69k
   const size_t common_elems = std::min(x_size, y_size);
544
545
3.69k
   word diff = 0;
546
547
17.4k
   for(size_t i = 0; i != common_elems; i++) {
548
13.7k
      diff |= (x[i] ^ y[i]);
549
13.7k
   }
550
551
   // If any bits were set in high part of x/y, then they are not equal
552
3.69k
   if(x_size < y_size) {
553
0
      for(size_t i = x_size; i != y_size; i++)
554
0
         diff |= y[i];
555
3.69k
   } else if(y_size < x_size) {
556
0
      for(size_t i = y_size; i != x_size; i++)
557
0
         diff |= x[i];
558
0
   }
559
560
3.69k
   return CT::Mask<word>::is_zero(diff);
561
3.69k
}
562
563
/**
564
* Set z to abs(x-y), ie if x >= y, then compute z = x - y
565
* Otherwise compute z = y - x
566
* No borrow is possible since the result is always >= 0
567
*
568
* Return the relative size of x vs y (-1, 0, 1)
569
*
570
* @param z output array of max(x_size,y_size) words
571
* @param x input param
572
* @param x_size length of x
573
* @param y input param
574
* @param y_size length of y
575
*/
576
4.72k
inline int32_t bigint_sub_abs(word z[], const word x[], size_t x_size, const word y[], size_t y_size) {
577
4.72k
   const int32_t relative_size = bigint_cmp(x, x_size, y, y_size);
578
579
   // Swap if relative_size == -1
580
4.72k
   const bool need_swap = relative_size < 0;
581
4.72k
   CT::conditional_swap_ptr(need_swap, x, y);
582
4.72k
   CT::conditional_swap(need_swap, x_size, y_size);
583
584
   /*
585
   * We know at this point that x >= y so if y_size is larger than
586
   * x_size, we are guaranteed they are just leading zeros which can
587
   * be ignored
588
   */
589
4.72k
   y_size = std::min(x_size, y_size);
590
591
4.72k
   bigint_sub3(z, x, x_size, y, y_size);
592
593
4.72k
   return relative_size;
594
4.72k
}
595
596
/**
597
* Set t to t-s modulo mod
598
*
599
* @param t first integer
600
* @param s second integer
601
* @param mod the modulus
602
* @param mod_sw size of t, s, and mod
603
* @param ws workspace of size mod_sw
604
*/
605
0
inline void bigint_mod_sub(word t[], const word s[], const word mod[], size_t mod_sw, word ws[]) {
606
   // is t < s or not?
607
0
   const auto is_lt = bigint_ct_is_lt(t, mod_sw, s, mod_sw);
608
609
   // ws = p - s
610
0
   const word borrow = bigint_sub3(ws, mod, mod_sw, s, mod_sw);
611
612
   // Compute either (t - s) or (t + (p - s)) depending on mask
613
0
   const word carry = bigint_cnd_addsub(is_lt, t, ws, s, mod_sw);
614
615
0
   BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0);
616
0
   BOTAN_UNUSED(carry, borrow);
617
0
}
618
619
template <size_t N>
620
0
inline void bigint_mod_sub_n(word t[], const word s[], const word mod[], word ws[]) {
621
   // is t < s or not?
622
0
   const auto is_lt = bigint_ct_is_lt(t, N, s, N);
623
624
   // ws = p - s
625
0
   const word borrow = bigint_sub3(ws, mod, N, s, N);
626
627
   // Compute either (t - s) or (t + (p - s)) depending on mask
628
0
   const word carry = bigint_cnd_addsub(is_lt, t, ws, s, N);
629
630
0
   BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0);
631
0
   BOTAN_UNUSED(carry, borrow);
632
0
}
Unexecuted instantiation: void Botan::bigint_mod_sub_n<4ul>(unsigned long*, unsigned long const*, unsigned long const*, unsigned long*)
Unexecuted instantiation: void Botan::bigint_mod_sub_n<6ul>(unsigned long*, unsigned long const*, unsigned long const*, unsigned long*)
633
634
/**
635
* Compute ((n1<<bits) + n0) / d
636
*/
637
8.44k
inline word bigint_divop(word n1, word n0, word d) {
638
8.44k
   if(d == 0)
639
0
      throw Invalid_Argument("bigint_divop divide by zero");
640
641
8.44k
#if defined(BOTAN_MP_DWORD)
642
8.44k
   return static_cast<word>(((static_cast<BOTAN_MP_DWORD>(n1) << BOTAN_MP_WORD_BITS) | n0) / d);
643
#else
644
645
   word high = n1 % d;
646
   word quotient = 0;
647
648
   for(size_t i = 0; i != BOTAN_MP_WORD_BITS; ++i) {
649
      const word high_top_bit = high >> (BOTAN_MP_WORD_BITS - 1);
650
651
      high <<= 1;
652
      high |= (n0 >> (BOTAN_MP_WORD_BITS - 1 - i)) & 1;
653
      quotient <<= 1;
654
655
      if(high_top_bit || high >= d) {
656
         high -= d;
657
         quotient |= 1;
658
      }
659
   }
660
661
   return quotient;
662
#endif
663
8.44k
}
664
665
/**
666
* Compute ((n1<<bits) + n0) % d
667
*/
668
1.81k
inline word bigint_modop(word n1, word n0, word d) {
669
1.81k
   if(d == 0)
670
0
      throw Invalid_Argument("bigint_modop divide by zero");
671
672
1.81k
#if defined(BOTAN_MP_DWORD)
673
1.81k
   return ((static_cast<BOTAN_MP_DWORD>(n1) << BOTAN_MP_WORD_BITS) | n0) % d;
674
#else
675
   word z = bigint_divop(n1, n0, d);
676
   word dummy = 0;
677
   z = word_madd2(z, d, &dummy);
678
   return (n0 - z);
679
#endif
680
1.81k
}
681
682
/*
683
* Comba Multiplication / Squaring
684
*/
685
BOTAN_FUZZER_API void bigint_comba_mul4(word z[8], const word x[4], const word y[4]);
686
BOTAN_FUZZER_API void bigint_comba_mul6(word z[12], const word x[6], const word y[6]);
687
BOTAN_FUZZER_API void bigint_comba_mul8(word z[16], const word x[8], const word y[8]);
688
BOTAN_FUZZER_API void bigint_comba_mul9(word z[18], const word x[9], const word y[9]);
689
BOTAN_FUZZER_API void bigint_comba_mul16(word z[32], const word x[16], const word y[16]);
690
BOTAN_FUZZER_API void bigint_comba_mul24(word z[48], const word x[24], const word y[24]);
691
692
BOTAN_FUZZER_API void bigint_comba_sqr4(word out[8], const word in[4]);
693
BOTAN_FUZZER_API void bigint_comba_sqr6(word out[12], const word in[6]);
694
BOTAN_FUZZER_API void bigint_comba_sqr8(word out[16], const word in[8]);
695
BOTAN_FUZZER_API void bigint_comba_sqr9(word out[18], const word in[9]);
696
BOTAN_FUZZER_API void bigint_comba_sqr16(word out[32], const word in[16]);
697
BOTAN_FUZZER_API void bigint_comba_sqr24(word out[48], const word in[24]);
698
699
/*
700
* Montgomery reduction
701
*
702
* Each of these functions makes the following assumptions:
703
*
704
* z_size == 2*p_size
705
* ws_size >= p_size + 1
706
*/
707
BOTAN_FUZZER_API void bigint_monty_redc_4(word z[8], const word p[4], word p_dash, word ws[]);
708
BOTAN_FUZZER_API void bigint_monty_redc_6(word z[12], const word p[6], word p_dash, word ws[]);
709
BOTAN_FUZZER_API void bigint_monty_redc_8(word z[16], const word p[8], word p_dash, word ws[]);
710
BOTAN_FUZZER_API void bigint_monty_redc_16(word z[32], const word p[16], word p_dash, word ws[]);
711
BOTAN_FUZZER_API void bigint_monty_redc_24(word z[48], const word p[24], word p_dash, word ws[]);
712
BOTAN_FUZZER_API void bigint_monty_redc_32(word z[64], const word p[32], word p_dash, word ws[]);
713
714
BOTAN_FUZZER_API
715
void bigint_monty_redc_generic(word z[], size_t z_size, const word p[], size_t p_size, word p_dash, word ws[]);
716
717
/**
718
* Montgomery Reduction
719
* @param z integer to reduce, of size exactly 2*p_size. Output is in
720
* the first p_size+1 words, higher words are set to zero.
721
* @param p modulus
722
* @param p_size size of p
723
* @param p_dash Montgomery value
724
* @param ws array of at least p_size+1 words
725
* @param ws_size size of ws in words
726
*/
727
0
inline void bigint_monty_redc(word z[], const word p[], size_t p_size, word p_dash, word ws[], size_t ws_size) {
728
0
   const size_t z_size = 2 * p_size;
729
0
730
0
   BOTAN_ARG_CHECK(ws_size >= p_size + 1, "Montgomery workspace too small");
731
0
732
0
   if(p_size == 4)
733
0
      bigint_monty_redc_4(z, p, p_dash, ws);
734
0
   else if(p_size == 6)
735
0
      bigint_monty_redc_6(z, p, p_dash, ws);
736
0
   else if(p_size == 8)
737
0
      bigint_monty_redc_8(z, p, p_dash, ws);
738
0
   else if(p_size == 16)
739
0
      bigint_monty_redc_16(z, p, p_dash, ws);
740
0
   else if(p_size == 24)
741
0
      bigint_monty_redc_24(z, p, p_dash, ws);
742
0
   else if(p_size == 32)
743
0
      bigint_monty_redc_32(z, p, p_dash, ws);
744
0
   else
745
0
      bigint_monty_redc_generic(z, z_size, p, p_size, p_dash, ws);
746
0
}
747
748
/**
749
* Basecase O(N^2) multiplication
750
*/
751
BOTAN_FUZZER_API
752
void basecase_mul(word z[], size_t z_size, const word x[], size_t x_size, const word y[], size_t y_size);
753
754
/**
755
* Basecase O(N^2) squaring
756
*/
757
BOTAN_FUZZER_API
758
void basecase_sqr(word z[], size_t z_size, const word x[], size_t x_size);
759
760
/*
761
* High Level Multiplication/Squaring Interfaces
762
*/
763
void bigint_mul(word z[],
764
                size_t z_size,
765
                const word x[],
766
                size_t x_size,
767
                size_t x_sw,
768
                const word y[],
769
                size_t y_size,
770
                size_t y_sw,
771
                word workspace[],
772
                size_t ws_size);
773
774
void bigint_sqr(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, word workspace[], size_t ws_size);
775
776
}  // namespace Botan
777
778
#endif