Coverage Report

Created: 2023-06-07 07:00

/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
663k
inline void bigint_cnd_swap(word cnd, word x[], word y[], size_t size) {
30
663k
   const auto mask = CT::Mask<word>::expand(cnd);
31
32
5.97M
   for(size_t i = 0; i != size; ++i) {
33
5.30M
      const word a = x[i];
34
5.30M
      const word b = y[i];
35
5.30M
      x[i] = mask.select(b, a);
36
5.30M
      y[i] = mask.select(a, b);
37
5.30M
   }
38
663k
}
39
40
65.7M
inline word bigint_cnd_add(word cnd, word x[], word x_size, const word y[], size_t y_size) {
41
65.7M
   BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
42
43
65.7M
   const auto mask = CT::Mask<word>::expand(cnd);
44
45
65.7M
   word carry = 0;
46
47
65.7M
   const size_t blocks = y_size - (y_size % 8);
48
65.7M
   word z[8] = {0};
49
50
65.7M
   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
460M
   for(size_t i = blocks; i != y_size; ++i) {
56
394M
      z[0] = word_add(x[i], y[i], &carry);
57
394M
      x[i] = mask.select(z[0], x[i]);
58
394M
   }
59
60
131M
   for(size_t i = y_size; i != x_size; ++i) {
61
65.7M
      z[0] = word_add(x[i], 0, &carry);
62
65.7M
      x[i] = mask.select(z[0], x[i]);
63
65.7M
   }
64
65
65.7M
   return mask.if_set_return(carry);
66
65.7M
}
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
83
0
   const auto mask = CT::Mask<word>::expand(cnd);
84
85
0
   word carry = 0;
86
87
0
   const size_t blocks = y_size - (y_size % 8);
88
0
   word z[8] = {0};
89
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
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
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
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
0
inline void bigint_cnd_add_or_sub(CT::Mask<word> mask, word x[], const word y[], size_t size) {
124
0
   const size_t blocks = size - (size % 8);
125
126
0
   word carry = 0;
127
0
   word borrow = 0;
128
129
0
   word t0[8] = {0};
130
0
   word t1[8] = {0};
131
132
0
   for(size_t i = 0; i != blocks; i += 8) {
133
0
      carry = word8_add3(t0, x + i, y + i, carry);
134
0
      borrow = word8_sub3(t1, x + i, y + i, borrow);
135
136
0
      for(size_t j = 0; j != 8; ++j)
137
0
         x[i + j] = mask.select(t0[j], t1[j]);
138
0
   }
139
140
0
   for(size_t i = blocks; i != size; ++i) {
141
0
      const word a = word_add(x[i], y[i], &carry);
142
0
      const word s = word_sub(x[i], y[i], &borrow);
143
144
0
      x[i] = mask.select(a, s);
145
0
   }
146
0
}
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
27.0M
inline word bigint_cnd_addsub(CT::Mask<word> mask, word x[], const word y[], const word z[], size_t size) {
158
27.0M
   const size_t blocks = size - (size % 8);
159
160
27.0M
   word carry = 0;
161
27.0M
   word borrow = 0;
162
163
27.0M
   word t0[8] = {0};
164
27.0M
   word t1[8] = {0};
165
166
27.0M
   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
189M
   for(size_t i = blocks; i != size; ++i) {
175
162M
      t0[0] = word_add(x[i], y[i], &carry);
176
162M
      t1[0] = word_sub(x[i], z[i], &borrow);
177
162M
      x[i] = mask.select(t0[0], t1[0]);
178
162M
   }
179
180
27.0M
   return mask.select(carry, borrow);
181
27.0M
}
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
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
141k
inline word bigint_add2_nc(word x[], size_t x_size, const word y[], size_t y_size) {
202
141k
   word carry = 0;
203
204
141k
   BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
205
206
141k
   const size_t blocks = y_size - (y_size % 8);
207
208
152k
   for(size_t i = 0; i != blocks; i += 8)
209
10.9k
      carry = word8_add2(x + i, y + i, carry);
210
211
157k
   for(size_t i = blocks; i != y_size; ++i)
212
15.5k
      x[i] = word_add(x[i], y[i], &carry);
213
214
1.18M
   for(size_t i = y_size; i != x_size; ++i)
215
1.04M
      x[i] = word_add(x[i], 0, &carry);
216
217
141k
   return carry;
218
141k
}
219
220
/**
221
* Three operand addition with carry out
222
*/
223
3.13M
inline word bigint_add3_nc(word z[], const word x[], size_t x_size, const word y[], size_t y_size) {
224
3.13M
   if(x_size < y_size) {
225
5.12k
      return bigint_add3_nc(z, y, y_size, x, x_size);
226
5.12k
   }
227
228
3.13M
   word carry = 0;
229
230
3.13M
   const size_t blocks = y_size - (y_size % 8);
231
232
3.13M
   for(size_t i = 0; i != blocks; i += 8)
233
0
      carry = word8_add3(z + i, x + i, y + i, carry);
234
235
21.8M
   for(size_t i = blocks; i != y_size; ++i)
236
18.7M
      z[i] = word_add(x[i], y[i], &carry);
237
238
3.17M
   for(size_t i = y_size; i != x_size; ++i)
239
41.9k
      z[i] = word_add(x[i], 0, &carry);
240
241
3.13M
   return carry;
242
3.13M
}
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
141k
inline void bigint_add2(word x[], size_t x_size, const word y[], size_t y_size) {
252
141k
   x[x_size] += bigint_add2_nc(x, x_size, y, y_size);
253
141k
}
254
255
/**
256
* Three operand addition
257
*/
258
7.20k
inline void bigint_add3(word z[], const word x[], size_t x_size, const word y[], size_t y_size) {
259
7.20k
   z[x_size > y_size ? x_size : y_size] += bigint_add3_nc(z, x, x_size, y, y_size);
260
7.20k
}
261
262
/**
263
* Two operand subtraction
264
*/
265
65.9M
inline word bigint_sub2(word x[], size_t x_size, const word y[], size_t y_size) {
266
65.9M
   word borrow = 0;
267
268
65.9M
   BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
269
270
65.9M
   const size_t blocks = y_size - (y_size % 8);
271
272
65.9M
   for(size_t i = 0; i != blocks; i += 8)
273
857
      borrow = word8_sub2(x + i, y + i, borrow);
274
275
461M
   for(size_t i = blocks; i != y_size; ++i)
276
395M
      x[i] = word_sub(x[i], y[i], &borrow);
277
278
131M
   for(size_t i = y_size; i != x_size; ++i)
279
65.7M
      x[i] = word_sub(x[i], 0, &borrow);
280
281
65.9M
   return borrow;
282
65.9M
}
283
284
/**
285
* Two operand subtraction, x = y - x; assumes y >= x
286
*/
287
68
inline void bigint_sub2_rev(word x[], const word y[], size_t y_size) {
288
68
   word borrow = 0;
289
290
68
   const size_t blocks = y_size - (y_size % 8);
291
292
149
   for(size_t i = 0; i != blocks; i += 8)
293
81
      borrow = word8_sub2_rev(x + i, y + i, borrow);
294
295
252
   for(size_t i = blocks; i != y_size; ++i)
296
184
      x[i] = word_sub(y[i], x[i], &borrow);
297
298
68
   BOTAN_ASSERT(borrow == 0, "y must be greater than x");
299
68
}
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
67.5M
inline word bigint_sub3(word z[], const word x[], size_t x_size, const word y[], size_t y_size) {
309
67.5M
   word borrow = 0;
310
311
67.5M
   BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
312
313
67.5M
   const size_t blocks = y_size - (y_size % 8);
314
315
67.5M
   for(size_t i = 0; i != blocks; i += 8)
316
398
      borrow = word8_sub3(z + i, x + i, y + i, borrow);
317
318
472M
   for(size_t i = blocks; i != y_size; ++i)
319
404M
      z[i] = word_sub(x[i], y[i], &borrow);
320
321
102M
   for(size_t i = y_size; i != x_size; ++i)
322
34.8M
      z[i] = word_sub(x[i], 0, &borrow);
323
324
67.5M
   return borrow;
325
67.5M
}
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
0
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
0
   word* ws0 = ws;
343
0
   word* ws1 = ws + N;
344
345
0
   word borrow0 = 0;
346
0
   word borrow1 = 0;
347
348
0
   const size_t blocks = N - (N % 8);
349
350
0
   for(size_t i = 0; i != blocks; i += 8) {
351
0
      borrow0 = word8_sub3(ws0 + i, x + i, y + i, borrow0);
352
0
      borrow1 = word8_sub3(ws1 + i, y + i, x + i, borrow1);
353
0
   }
354
355
0
   for(size_t i = blocks; i != N; ++i) {
356
0
      ws0[i] = word_sub(x[i], y[i], &borrow0);
357
0
      ws1[i] = word_sub(y[i], x[i], &borrow1);
358
0
   }
359
360
0
   return CT::conditional_copy_mem(borrow0, z, ws1, ws0, N);
361
0
}
362
363
/*
364
* Shift Operations
365
*/
366
254k
inline void bigint_shl1(word x[], size_t x_size, size_t x_words, size_t word_shift, size_t bit_shift) {
367
254k
   copy_mem(x + word_shift, x, x_words);
368
254k
   clear_mem(x, word_shift);
369
370
254k
   const auto carry_mask = CT::Mask<word>::expand(bit_shift);
371
254k
   const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift);
372
373
254k
   word carry = 0;
374
1.39M
   for(size_t i = word_shift; i != x_size; ++i) {
375
1.14M
      const word w = x[i];
376
1.14M
      x[i] = (w << bit_shift) | carry;
377
1.14M
      carry = carry_mask.if_set_return(w >> carry_shift);
378
1.14M
   }
379
254k
}
380
381
421k
inline void bigint_shr1(word x[], size_t x_size, size_t word_shift, size_t bit_shift) {
382
421k
   const size_t top = x_size >= word_shift ? (x_size - word_shift) : 0;
383
384
421k
   if(top > 0)
385
420k
      copy_mem(x, x + word_shift, top);
386
421k
   clear_mem(x + top, std::min(word_shift, x_size));
387
388
421k
   const auto carry_mask = CT::Mask<word>::expand(bit_shift);
389
421k
   const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift);
390
391
421k
   word carry = 0;
392
393
3.63M
   for(size_t i = 0; i != top; ++i) {
394
3.21M
      const word w = x[top - i - 1];
395
3.21M
      x[top - i - 1] = (w >> bit_shift) | carry;
396
3.21M
      carry = carry_mask.if_set_return(w << carry_shift);
397
3.21M
   }
398
421k
}
399
400
127k
inline void bigint_shl2(word y[], const word x[], size_t x_size, size_t word_shift, size_t bit_shift) {
401
127k
   copy_mem(y + word_shift, x, x_size);
402
403
127k
   const auto carry_mask = CT::Mask<word>::expand(bit_shift);
404
127k
   const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift);
405
406
127k
   word carry = 0;
407
761k
   for(size_t i = word_shift; i != x_size + word_shift + 1; ++i) {
408
634k
      const word w = y[i];
409
634k
      y[i] = (w << bit_shift) | carry;
410
634k
      carry = carry_mask.if_set_return(w >> carry_shift);
411
634k
   }
412
127k
}
413
414
853
inline void bigint_shr2(word y[], const word x[], size_t x_size, size_t word_shift, size_t bit_shift) {
415
853
   const size_t new_size = x_size < word_shift ? 0 : (x_size - word_shift);
416
417
853
   if(new_size > 0)
418
853
      copy_mem(y, x + word_shift, new_size);
419
420
853
   const auto carry_mask = CT::Mask<word>::expand(bit_shift);
421
853
   const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift);
422
423
853
   word carry = 0;
424
5.97k
   for(size_t i = new_size; i > 0; --i) {
425
5.11k
      word w = y[i - 1];
426
5.11k
      y[i - 1] = (w >> bit_shift) | carry;
427
5.11k
      carry = carry_mask.if_set_return(w << carry_shift);
428
5.11k
   }
429
853
}
430
431
/*
432
* Linear Multiply - returns the carry
433
*/
434
13.1M
[[nodiscard]] inline word bigint_linmul2(word x[], size_t x_size, word y) {
435
13.1M
   const size_t blocks = x_size - (x_size % 8);
436
437
13.1M
   word carry = 0;
438
439
34.7M
   for(size_t i = 0; i != blocks; i += 8)
440
21.6M
      carry = word8_linmul2(x + i, y, carry);
441
442
36.8M
   for(size_t i = blocks; i != x_size; ++i)
443
23.7M
      x[i] = word_madd2(x[i], y, &carry);
444
445
13.1M
   return carry;
446
13.1M
}
447
448
132k
inline void bigint_linmul3(word z[], const word x[], size_t x_size, word y) {
449
132k
   const size_t blocks = x_size - (x_size % 8);
450
451
132k
   word carry = 0;
452
453
133k
   for(size_t i = 0; i != blocks; i += 8)
454
610
      carry = word8_linmul3(z + i, x + i, y, carry);
455
456
661k
   for(size_t i = blocks; i != x_size; ++i)
457
528k
      z[i] = word_madd2(x[i], y, &carry);
458
459
132k
   z[x_size] = carry;
460
132k
}
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
262k
inline int32_t bigint_cmp(const word x[], size_t x_size, const word y[], size_t y_size) {
469
262k
   static_assert(sizeof(word) >= sizeof(uint32_t), "Size assumption");
470
471
262k
   const word LT = static_cast<word>(-1);
472
262k
   const word EQ = 0;
473
262k
   const word GT = 1;
474
475
262k
   const size_t common_elems = std::min(x_size, y_size);
476
477
262k
   word result = EQ;  // until found otherwise
478
479
1.38M
   for(size_t i = 0; i != common_elems; i++) {
480
1.12M
      const auto is_eq = CT::Mask<word>::is_equal(x[i], y[i]);
481
1.12M
      const auto is_lt = CT::Mask<word>::is_lt(x[i], y[i]);
482
483
1.12M
      result = is_eq.select(result, is_lt.select(LT, GT));
484
1.12M
   }
485
486
262k
   if(x_size < y_size) {
487
13.7k
      word mask = 0;
488
63.5k
      for(size_t i = x_size; i != y_size; i++)
489
49.7k
         mask |= y[i];
490
491
      // If any bits were set in high part of y, then x < y
492
13.7k
      result = CT::Mask<word>::is_zero(mask).select(result, LT);
493
249k
   } else if(y_size < x_size) {
494
1.18k
      word mask = 0;
495
6.96k
      for(size_t i = y_size; i != x_size; i++)
496
5.77k
         mask |= x[i];
497
498
      // If any bits were set in high part of x, then x > y
499
1.18k
      result = CT::Mask<word>::is_zero(mask).select(result, GT);
500
1.18k
   }
501
502
262k
   CT::unpoison(result);
503
262k
   BOTAN_DEBUG_ASSERT(result == LT || result == GT || result == EQ);
504
262k
   return static_cast<int32_t>(result);
505
262k
}
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
27.6M
   const word x[], size_t x_size, const word y[], size_t y_size, bool lt_or_equal = false) {
514
27.6M
   const size_t common_elems = std::min(x_size, y_size);
515
516
27.6M
   auto is_lt = CT::Mask<word>::expand(lt_or_equal);
517
518
192M
   for(size_t i = 0; i != common_elems; i++) {
519
164M
      const auto eq = CT::Mask<word>::is_equal(x[i], y[i]);
520
164M
      const auto lt = CT::Mask<word>::is_lt(x[i], y[i]);
521
164M
      is_lt = eq.select_mask(is_lt, lt);
522
164M
   }
523
524
27.6M
   if(x_size < y_size) {
525
1.33k
      word mask = 0;
526
6.92k
      for(size_t i = x_size; i != y_size; i++)
527
5.59k
         mask |= y[i];
528
      // If any bits were set in high part of y, then is_lt should be forced true
529
1.33k
      is_lt |= CT::Mask<word>::expand(mask);
530
27.6M
   } else if(y_size < x_size) {
531
18.7k
      word mask = 0;
532
74.7k
      for(size_t i = y_size; i != x_size; i++)
533
56.0k
         mask |= x[i];
534
535
      // If any bits were set in high part of x, then is_lt should be false
536
18.7k
      is_lt &= CT::Mask<word>::is_zero(mask);
537
18.7k
   }
538
539
27.6M
   return is_lt;
540
27.6M
}
541
542
21.9k
inline CT::Mask<word> bigint_ct_is_eq(const word x[], size_t x_size, const word y[], size_t y_size) {
543
21.9k
   const size_t common_elems = std::min(x_size, y_size);
544
545
21.9k
   word diff = 0;
546
547
153k
   for(size_t i = 0; i != common_elems; i++) {
548
131k
      diff |= (x[i] ^ y[i]);
549
131k
   }
550
551
   // If any bits were set in high part of x/y, then they are not equal
552
21.9k
   if(x_size < y_size) {
553
0
      for(size_t i = x_size; i != y_size; i++)
554
0
         diff |= y[i];
555
21.9k
   } else if(y_size < x_size) {
556
10
      for(size_t i = y_size; i != x_size; i++)
557
7
         diff |= x[i];
558
3
   }
559
560
21.9k
   return CT::Mask<word>::is_zero(diff);
561
21.9k
}
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
85.8k
inline int32_t bigint_sub_abs(word z[], const word x[], size_t x_size, const word y[], size_t y_size) {
577
85.8k
   const int32_t relative_size = bigint_cmp(x, x_size, y, y_size);
578
579
   // Swap if relative_size == -1
580
85.8k
   const bool need_swap = relative_size < 0;
581
85.8k
   CT::conditional_swap_ptr(need_swap, x, y);
582
85.8k
   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
85.8k
   y_size = std::min(x_size, y_size);
590
591
85.8k
   bigint_sub3(z, x, x_size, y, y_size);
592
593
85.8k
   return relative_size;
594
85.8k
}
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
27.0M
inline void bigint_mod_sub_n(word t[], const word s[], const word mod[], word ws[]) {
621
   // is t < s or not?
622
27.0M
   const auto is_lt = bigint_ct_is_lt(t, N, s, N);
623
624
   // ws = p - s
625
27.0M
   const word borrow = bigint_sub3(ws, mod, N, s, N);
626
627
   // Compute either (t - s) or (t + (p - s)) depending on mask
628
27.0M
   const word carry = bigint_cnd_addsub(is_lt, t, ws, s, N);
629
630
27.0M
   BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0);
631
27.0M
   BOTAN_UNUSED(carry, borrow);
632
27.0M
}
Unexecuted instantiation: void Botan::bigint_mod_sub_n<4ul>(unsigned long*, unsigned long const*, unsigned long const*, unsigned long*)
void Botan::bigint_mod_sub_n<6ul>(unsigned long*, unsigned long const*, unsigned long const*, unsigned long*)
Line
Count
Source
620
27.0M
inline void bigint_mod_sub_n(word t[], const word s[], const word mod[], word ws[]) {
621
   // is t < s or not?
622
27.0M
   const auto is_lt = bigint_ct_is_lt(t, N, s, N);
623
624
   // ws = p - s
625
27.0M
   const word borrow = bigint_sub3(ws, mod, N, s, N);
626
627
   // Compute either (t - s) or (t + (p - s)) depending on mask
628
27.0M
   const word carry = bigint_cnd_addsub(is_lt, t, ws, s, N);
629
630
27.0M
   BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0);
631
27.0M
   BOTAN_UNUSED(carry, borrow);
632
27.0M
}
633
634
/**
635
* Compute ((n1<<bits) + n0) / d
636
*/
637
128k
inline word bigint_divop(word n1, word n0, word d) {
638
128k
   if(d == 0)
639
0
      throw Invalid_Argument("bigint_divop divide by zero");
640
641
128k
#if defined(BOTAN_MP_DWORD)
642
128k
   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
128k
}
664
665
/**
666
* Compute ((n1<<bits) + n0) % d
667
*/
668
26.5k
inline word bigint_modop(word n1, word n0, word d) {
669
26.5k
   if(d == 0)
670
0
      throw Invalid_Argument("bigint_modop divide by zero");
671
672
26.5k
#if defined(BOTAN_MP_DWORD)
673
26.5k
   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
26.5k
}
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
400k
inline void bigint_monty_redc(word z[], const word p[], size_t p_size, word p_dash, word ws[], size_t ws_size) {
728
400k
   const size_t z_size = 2 * p_size;
729
730
400k
   BOTAN_ARG_CHECK(ws_size >= p_size + 1, "Montgomery workspace too small");
731
732
400k
   if(p_size == 4)
733
0
      bigint_monty_redc_4(z, p, p_dash, ws);
734
400k
   else if(p_size == 6)
735
400k
      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
400k
}
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