/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 |