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