Botan 3.7.1
Crypto and TLS for C&
mp_core.h
Go to the documentation of this file.
1/*
2* MPI Algorithms
3* (C) 1999-2010,2018,2024 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/assert.h>
14#include <botan/exceptn.h>
15#include <botan/mem_ops.h>
16#include <botan/types.h>
17#include <botan/internal/ct_utils.h>
18#include <botan/internal/mp_asmi.h>
19#include <algorithm>
20#include <array>
21#include <span>
22
23namespace Botan {
24
25/*
26* If cond == 0, does nothing.
27* If cond > 0, swaps x[0:size] with y[0:size]
28* Runs in constant time
29*/
30template <WordType W>
31inline constexpr void bigint_cnd_swap(W cnd, W x[], W y[], size_t size) {
32 const auto mask = CT::Mask<W>::expand(cnd);
33
34 for(size_t i = 0; i != size; ++i) {
35 const W a = x[i];
36 const W b = y[i];
37 x[i] = mask.select(b, a);
38 y[i] = mask.select(a, b);
39 }
40}
41
42template <WordType W>
43inline constexpr W bigint_cnd_add(W cnd, W x[], size_t x_size, const W y[], size_t y_size) {
44 BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
45
46 const auto mask = CT::Mask<W>::expand(cnd).value();
47
48 W carry = 0;
49
50 for(size_t i = 0; i != y_size; ++i) {
51 x[i] = word_add(x[i], y[i] & mask, &carry);
52 }
53
54 for(size_t i = y_size; i != x_size; ++i) {
55 x[i] = word_add(x[i], static_cast<W>(0), &carry);
56 }
57
58 return (mask & carry);
59}
60
61/*
62* If cond > 0 adds x[0:size] and y[0:size] and returns carry
63* Runs in constant time
64*/
65template <WordType W>
66inline constexpr W bigint_cnd_add(W cnd, W x[], const W y[], size_t size) {
67 return bigint_cnd_add(cnd, x, size, y, size);
68}
69
70/*
71* If cond > 0 subtracts x[0:size] and y[0:size] and returns borrow
72* Runs in constant time
73*/
74template <WordType W>
75inline constexpr auto bigint_cnd_sub(W cnd, W x[], size_t x_size, const W y[], size_t y_size) -> W {
76 BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
77
78 const auto mask = CT::Mask<W>::expand(cnd).value();
79
80 W carry = 0;
81
82 for(size_t i = 0; i != y_size; ++i) {
83 x[i] = word_sub(x[i], y[i] & mask, &carry);
84 }
85
86 for(size_t i = y_size; i != x_size; ++i) {
87 x[i] = word_sub(x[i], static_cast<W>(0), &carry);
88 }
89
90 return (mask & carry);
91}
92
93/*
94* If cond > 0 adds x[0:size] and y[0:size] and returns carry
95* Runs in constant time
96*/
97template <WordType W>
98inline constexpr auto bigint_cnd_sub(W cnd, W x[], const W y[], size_t size) -> W {
99 return bigint_cnd_sub(cnd, x, size, y, size);
100}
101
102/*
103* Equivalent to
104* bigint_cnd_add( mask, x, y, size);
105* bigint_cnd_sub(~mask, x, y, size);
106*
107* Mask must be either 0 or all 1 bits
108*/
109template <WordType W>
110inline constexpr void bigint_cnd_add_or_sub(CT::Mask<W> mask, W x[], const W y[], size_t size) {
111 const size_t blocks = size - (size % 8);
112
113 W carry = 0;
114 W borrow = 0;
115
116 W t0[8] = {0};
117 W t1[8] = {0};
118
119 for(size_t i = 0; i != blocks; i += 8) {
120 carry = word8_add3(t0, x + i, y + i, carry);
121 borrow = word8_sub3(t1, x + i, y + i, borrow);
122 mask.select_n(x + i, t0, t1, 8);
123 }
124
125 for(size_t i = blocks; i != size; ++i) {
126 const W a = word_add(x[i], y[i], &carry);
127 const W s = word_sub(x[i], y[i], &borrow);
128
129 x[i] = mask.select(a, s);
130 }
131}
132
133/*
134* Equivalent to
135* bigint_cnd_add( mask, x, size, y, size);
136* bigint_cnd_sub(~mask, x, size, z, size);
137*
138* Mask must be either 0 or all 1 bits
139*
140* Returns the carry or borrow resp
141*/
142template <WordType W>
143inline constexpr auto bigint_cnd_addsub(CT::Mask<W> mask, W x[], const W y[], const W z[], size_t size) -> W {
144 const size_t blocks = size - (size % 8);
145
146 W carry = 0;
147 W borrow = 0;
148
149 W t0[8] = {0};
150 W t1[8] = {0};
151
152 for(size_t i = 0; i != blocks; i += 8) {
153 carry = word8_add3(t0, x + i, y + i, carry);
154 borrow = word8_sub3(t1, x + i, z + i, borrow);
155 mask.select_n(x + i, t0, t1, 8);
156 }
157
158 for(size_t i = blocks; i != size; ++i) {
159 t0[0] = word_add(x[i], y[i], &carry);
160 t1[0] = word_sub(x[i], z[i], &borrow);
161 x[i] = mask.select(t0[0], t1[0]);
162 }
163
164 return mask.select(carry, borrow);
165}
166
167/*
168* 2s complement absolute value
169* If cond > 0 sets x to ~x + 1
170* Runs in constant time
171*/
172template <WordType W>
173inline constexpr void bigint_cnd_abs(W cnd, W x[], size_t size) {
174 const auto mask = CT::Mask<W>::expand(cnd);
175
176 W carry = mask.if_set_return(1);
177 for(size_t i = 0; i != size; ++i) {
178 const W z = word_add(~x[i], static_cast<W>(0), &carry);
179 x[i] = mask.select(z, x[i]);
180 }
181}
182
183/**
184* Two operand addition with carry out
185*/
186template <WordType W>
187inline constexpr auto bigint_add2_nc(W x[], size_t x_size, const W y[], size_t y_size) -> W {
188 W carry = 0;
189
190 BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
191
192 const size_t blocks = y_size - (y_size % 8);
193
194 for(size_t i = 0; i != blocks; i += 8) {
195 carry = word8_add2(x + i, y + i, carry);
196 }
197
198 for(size_t i = blocks; i != y_size; ++i) {
199 x[i] = word_add(x[i], y[i], &carry);
200 }
201
202 for(size_t i = y_size; i != x_size; ++i) {
203 x[i] = word_add(x[i], static_cast<W>(0), &carry);
204 }
205
206 return carry;
207}
208
209/**
210* Three operand addition with carry out
211*/
212template <WordType W>
213inline constexpr auto bigint_add3_nc(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W {
214 if(x_size < y_size) {
215 return bigint_add3_nc(z, y, y_size, x, x_size);
216 }
217
218 W carry = 0;
219
220 const size_t blocks = y_size - (y_size % 8);
221
222 for(size_t i = 0; i != blocks; i += 8) {
223 carry = word8_add3(z + i, x + i, y + i, carry);
224 }
225
226 for(size_t i = blocks; i != y_size; ++i) {
227 z[i] = word_add(x[i], y[i], &carry);
228 }
229
230 for(size_t i = y_size; i != x_size; ++i) {
231 z[i] = word_add(x[i], static_cast<W>(0), &carry);
232 }
233
234 return carry;
235}
236
237template <WordType W, size_t N>
238inline constexpr auto bigint_add(std::span<W, N> z, std::span<const W, N> x, std::span<const W, N> y) -> W {
239 if constexpr(N == 4) {
240 return word4_add3<W>(z.data(), x.data(), y.data(), 0);
241 } else if constexpr(N == 8) {
242 return word8_add3<W>(z.data(), x.data(), y.data(), 0);
243 } else {
244 return bigint_add3_nc(z.data(), x.data(), N, y.data(), N);
245 }
246}
247
248/**
249* Two operand addition
250* @param x the first operand (and output)
251* @param x_size size of x
252* @param y the second operand
253* @param y_size size of y (must be <= x_size)
254*/
255template <WordType W>
256inline constexpr void bigint_add2(W x[], size_t x_size, const W y[], size_t y_size) {
257 x[x_size] += bigint_add2_nc(x, x_size, y, y_size);
258}
259
260/**
261* Three operand addition
262*/
263template <WordType W>
264inline constexpr void bigint_add3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) {
265 z[x_size > y_size ? x_size : y_size] += bigint_add3_nc(z, x, x_size, y, y_size);
266}
267
268/**
269* Two operand subtraction
270*/
271template <WordType W>
272inline constexpr auto bigint_sub2(W x[], size_t x_size, const W y[], size_t y_size) -> W {
273 W borrow = 0;
274
275 BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
276
277 const size_t blocks = y_size - (y_size % 8);
278
279 for(size_t i = 0; i != blocks; i += 8) {
280 borrow = word8_sub2(x + i, y + i, borrow);
281 }
282
283 for(size_t i = blocks; i != y_size; ++i) {
284 x[i] = word_sub(x[i], y[i], &borrow);
285 }
286
287 for(size_t i = y_size; i != x_size; ++i) {
288 x[i] = word_sub(x[i], static_cast<W>(0), &borrow);
289 }
290
291 return borrow;
292}
293
294/**
295* Two operand subtraction, x = y - x; assumes y >= x
296*/
297template <WordType W>
298inline constexpr void bigint_sub2_rev(W x[], const W y[], size_t y_size) {
299 W borrow = 0;
300
301 const size_t blocks = y_size - (y_size % 8);
302
303 for(size_t i = 0; i != blocks; i += 8) {
304 borrow = word8_sub2_rev(x + i, y + i, borrow);
305 }
306
307 for(size_t i = blocks; i != y_size; ++i) {
308 x[i] = word_sub(y[i], x[i], &borrow);
309 }
310
311 BOTAN_ASSERT(borrow == 0, "y must be greater than x");
312}
313
314/**
315* Three operand subtraction
316*
317* Expects that x_size >= y_size
318*
319* Writes to z[0:x_size] and returns borrow
320*/
321template <WordType W>
322inline constexpr auto bigint_sub3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W {
323 W borrow = 0;
324
325 BOTAN_ASSERT(x_size >= y_size, "Expected sizes");
326
327 const size_t blocks = y_size - (y_size % 8);
328
329 for(size_t i = 0; i != blocks; i += 8) {
330 borrow = word8_sub3(z + i, x + i, y + i, borrow);
331 }
332
333 for(size_t i = blocks; i != y_size; ++i) {
334 z[i] = word_sub(x[i], y[i], &borrow);
335 }
336
337 for(size_t i = y_size; i != x_size; ++i) {
338 z[i] = word_sub(x[i], static_cast<W>(0), &borrow);
339 }
340
341 return borrow;
342}
343
344/**
345* Conditional subtraction for Montgomery reduction
346*
347* This function assumes that (x0 || x) is less than 2*p
348*
349* Computes z[0:N] = (x0 || x[0:N]) - p[0:N]
350*
351* If z would be positive, returns z[0:N]
352* Otherwise returns original input x
353*/
354template <WordType W>
355inline constexpr void bigint_monty_maybe_sub(size_t N, W z[], W x0, const W x[], const W p[]) {
356 W borrow = 0;
357
358 const size_t blocks = N - (N % 8);
359
360 for(size_t i = 0; i != blocks; i += 8) {
361 borrow = word8_sub3(z + i, x + i, p + i, borrow);
362 }
363
364 for(size_t i = blocks; i != N; ++i) {
365 z[i] = word_sub(x[i], p[i], &borrow);
366 }
367
368 borrow = (x0 - borrow) > x0;
369
370 CT::conditional_assign_mem(borrow, z, x, N);
371}
372
373/**
374* Conditional subtraction for Montgomery reduction
375*
376* This function assumes that (x0 || x) is less than 2*p
377*
378* Computes z[0:N] = (x0 || x[0:N]) - p[0:N]
379*
380* If z would be positive, returns z[0:N]
381* Otherwise returns original input x
382*/
383template <size_t N, WordType W>
384inline constexpr void bigint_monty_maybe_sub(W z[N], W x0, const W x[N], const W y[N]) {
385 W borrow = 0;
386
387 if constexpr(N == 4) {
388 borrow = word4_sub3(z, x, y, borrow);
389 } else if constexpr(N == 8) {
390 borrow = word8_sub3(z, x, y, borrow);
391 } else {
392 const constexpr size_t blocks = N - (N % 8);
393 for(size_t i = 0; i != blocks; i += 8) {
394 borrow = word8_sub3(z + i, x + i, y + i, borrow);
395 }
396
397 for(size_t i = blocks; i != N; ++i) {
398 z[i] = word_sub(x[i], y[i], &borrow);
399 }
400 }
401
402 borrow = (x0 - borrow) > x0;
403
404 CT::conditional_assign_mem(borrow, z, x, N);
405}
406
407/**
408* Return abs(x-y), ie if x >= y, then compute z = x - y
409* Otherwise compute z = y - x
410* No borrow is possible since the result is always >= 0
411*
412* Returns ~0 if x >= y or 0 if x < y
413* @param z output array of at least N words
414* @param x input array of N words
415* @param y input array of N words
416* @param N length of x and y
417* @param ws array of at least 2*N words
418*/
419template <WordType W>
420inline constexpr auto bigint_sub_abs(W z[], const W x[], const W y[], size_t N, W ws[]) -> CT::Mask<W> {
421 // Subtract in both direction then conditional copy out the result
422
423 W* ws0 = ws;
424 W* ws1 = ws + N;
425
426 W borrow0 = 0;
427 W borrow1 = 0;
428
429 const size_t blocks = N - (N % 8);
430
431 for(size_t i = 0; i != blocks; i += 8) {
432 borrow0 = word8_sub3(ws0 + i, x + i, y + i, borrow0);
433 borrow1 = word8_sub3(ws1 + i, y + i, x + i, borrow1);
434 }
435
436 for(size_t i = blocks; i != N; ++i) {
437 ws0[i] = word_sub(x[i], y[i], &borrow0);
438 ws1[i] = word_sub(y[i], x[i], &borrow1);
439 }
440
441 return CT::conditional_copy_mem(borrow0, z, ws1, ws0, N);
442}
443
444/*
445* Shift Operations
446*/
447template <WordType W>
448inline constexpr void bigint_shl1(W x[], size_t x_size, size_t x_words, size_t shift) {
449 const size_t word_shift = shift / WordInfo<W>::bits;
450 const size_t bit_shift = shift % WordInfo<W>::bits;
451
452 copy_mem(x + word_shift, x, x_words);
453 clear_mem(x, word_shift);
454
455 const auto carry_mask = CT::Mask<W>::expand(bit_shift);
456 const W carry_shift = carry_mask.if_set_return(WordInfo<W>::bits - bit_shift);
457
458 W carry = 0;
459 for(size_t i = word_shift; i != x_size; ++i) {
460 const W w = x[i];
461 x[i] = (w << bit_shift) | carry;
462 carry = carry_mask.if_set_return(w >> carry_shift);
463 }
464}
465
466template <WordType W>
467inline constexpr void bigint_shr1(W x[], size_t x_size, size_t shift) {
468 const size_t word_shift = shift / WordInfo<W>::bits;
469 const size_t bit_shift = shift % WordInfo<W>::bits;
470
471 const size_t top = x_size >= word_shift ? (x_size - word_shift) : 0;
472
473 if(top > 0) {
474 copy_mem(x, x + word_shift, top);
475 }
476 clear_mem(x + top, std::min(word_shift, x_size));
477
478 const auto carry_mask = CT::Mask<W>::expand(bit_shift);
479 const W carry_shift = carry_mask.if_set_return(WordInfo<W>::bits - bit_shift);
480
481 W carry = 0;
482
483 for(size_t i = 0; i != top; ++i) {
484 const W w = x[top - i - 1];
485 x[top - i - 1] = (w >> bit_shift) | carry;
486 carry = carry_mask.if_set_return(w << carry_shift);
487 }
488}
489
490template <WordType W>
491inline constexpr void bigint_shl2(W y[], const W x[], size_t x_size, size_t shift) {
492 const size_t word_shift = shift / WordInfo<W>::bits;
493 const size_t bit_shift = shift % WordInfo<W>::bits;
494
495 copy_mem(y + word_shift, x, x_size);
496
497 const auto carry_mask = CT::Mask<W>::expand(bit_shift);
498 const W carry_shift = carry_mask.if_set_return(WordInfo<W>::bits - bit_shift);
499
500 W carry = 0;
501 for(size_t i = word_shift; i != x_size + word_shift + 1; ++i) {
502 const W w = y[i];
503 y[i] = (w << bit_shift) | carry;
504 carry = carry_mask.if_set_return(w >> carry_shift);
505 }
506}
507
508template <WordType W>
509inline constexpr void bigint_shr2(W y[], const W x[], size_t x_size, size_t shift) {
510 const size_t word_shift = shift / WordInfo<W>::bits;
511 const size_t bit_shift = shift % WordInfo<W>::bits;
512 const size_t new_size = x_size < word_shift ? 0 : (x_size - word_shift);
513
514 if(new_size > 0) {
515 copy_mem(y, x + word_shift, new_size);
516 }
517
518 const auto carry_mask = CT::Mask<W>::expand(bit_shift);
519 const W carry_shift = carry_mask.if_set_return(WordInfo<W>::bits - bit_shift);
520
521 W carry = 0;
522 for(size_t i = new_size; i > 0; --i) {
523 W w = y[i - 1];
524 y[i - 1] = (w >> bit_shift) | carry;
525 carry = carry_mask.if_set_return(w << carry_shift);
526 }
527}
528
529/*
530* Linear Multiply - returns the carry
531*/
532template <WordType W>
533[[nodiscard]] inline constexpr auto bigint_linmul2(W x[], size_t x_size, W y) -> W {
534 const size_t blocks = x_size - (x_size % 8);
535
536 W carry = 0;
537
538 for(size_t i = 0; i != blocks; i += 8) {
539 carry = word8_linmul2(x + i, y, carry);
540 }
541
542 for(size_t i = blocks; i != x_size; ++i) {
543 x[i] = word_madd2(x[i], y, &carry);
544 }
545
546 return carry;
547}
548
549template <WordType W>
550inline constexpr void bigint_linmul3(W z[], const W x[], size_t x_size, W y) {
551 const size_t blocks = x_size - (x_size % 8);
552
553 W carry = 0;
554
555 for(size_t i = 0; i != blocks; i += 8) {
556 carry = word8_linmul3(z + i, x + i, y, carry);
557 }
558
559 for(size_t i = blocks; i != x_size; ++i) {
560 z[i] = word_madd2(x[i], y, &carry);
561 }
562
563 z[x_size] = carry;
564}
565
566/**
567* Compare x and y
568* Return -1 if x < y
569* Return 0 if x == y
570* Return 1 if x > y
571*/
572template <WordType W>
573inline constexpr int32_t bigint_cmp(const W x[], size_t x_size, const W y[], size_t y_size) {
574 static_assert(sizeof(W) >= sizeof(uint32_t), "Size assumption");
575
576 const W LT = static_cast<W>(-1);
577 const W EQ = 0;
578 const W GT = 1;
579
580 const size_t common_elems = std::min(x_size, y_size);
581
582 W result = EQ; // until found otherwise
583
584 for(size_t i = 0; i != common_elems; i++) {
585 const auto is_eq = CT::Mask<W>::is_equal(x[i], y[i]);
586 const auto is_lt = CT::Mask<W>::is_lt(x[i], y[i]);
587
588 result = is_eq.select(result, is_lt.select(LT, GT));
589 }
590
591 if(x_size < y_size) {
592 W mask = 0;
593 for(size_t i = x_size; i != y_size; i++) {
594 mask |= y[i];
595 }
596
597 // If any bits were set in high part of y, then x < y
598 result = CT::Mask<W>::is_zero(mask).select(result, LT);
599 } else if(y_size < x_size) {
600 W mask = 0;
601 for(size_t i = y_size; i != x_size; i++) {
602 mask |= x[i];
603 }
604
605 // If any bits were set in high part of x, then x > y
606 result = CT::Mask<W>::is_zero(mask).select(result, GT);
607 }
608
609 CT::unpoison(result);
610 BOTAN_DEBUG_ASSERT(result == LT || result == GT || result == EQ);
611 return static_cast<int32_t>(result);
612}
613
614/**
615* Compare x and y
616* Return ~0 if x[0:x_size] < y[0:y_size] or 0 otherwise
617* If lt_or_equal is true, returns ~0 also for x == y
618*/
619template <WordType W>
620inline constexpr auto bigint_ct_is_lt(const W x[], size_t x_size, const W y[], size_t y_size, bool lt_or_equal = false)
621 -> CT::Mask<W> {
622 const size_t common_elems = std::min(x_size, y_size);
623
624 auto is_lt = CT::Mask<W>::expand(lt_or_equal);
625
626 for(size_t i = 0; i != common_elems; i++) {
627 const auto eq = CT::Mask<W>::is_equal(x[i], y[i]);
628 const auto lt = CT::Mask<W>::is_lt(x[i], y[i]);
629 is_lt = eq.select_mask(is_lt, lt);
630 }
631
632 if(x_size < y_size) {
633 W mask = 0;
634 for(size_t i = x_size; i != y_size; i++) {
635 mask |= y[i];
636 }
637 // If any bits were set in high part of y, then is_lt should be forced true
638 is_lt |= CT::Mask<W>::expand(mask);
639 } else if(y_size < x_size) {
640 W mask = 0;
641 for(size_t i = y_size; i != x_size; i++) {
642 mask |= x[i];
643 }
644
645 // If any bits were set in high part of x, then is_lt should be false
646 is_lt &= CT::Mask<W>::is_zero(mask);
647 }
648
649 return is_lt;
650}
651
652template <WordType W>
653inline constexpr auto bigint_ct_is_eq(const W x[], size_t x_size, const W y[], size_t y_size) -> CT::Mask<W> {
654 const size_t common_elems = std::min(x_size, y_size);
655
656 W diff = 0;
657
658 for(size_t i = 0; i != common_elems; i++) {
659 diff |= (x[i] ^ y[i]);
660 }
661
662 // If any bits were set in high part of x/y, then they are not equal
663 if(x_size < y_size) {
664 for(size_t i = x_size; i != y_size; i++) {
665 diff |= y[i];
666 }
667 } else if(y_size < x_size) {
668 for(size_t i = y_size; i != x_size; i++) {
669 diff |= x[i];
670 }
671 }
672
673 return CT::Mask<W>::is_zero(diff);
674}
675
676/**
677* Set z to abs(x-y), ie if x >= y, then compute z = x - y
678* Otherwise compute z = y - x
679* No borrow is possible since the result is always >= 0
680*
681* Return the relative size of x vs y (-1, 0, 1)
682*
683* @param z output array of max(x_size,y_size) words
684* @param x input param
685* @param x_size length of x
686* @param y input param
687* @param y_size length of y
688*/
689template <WordType W>
690inline constexpr int32_t bigint_sub_abs(W z[], const W x[], size_t x_size, const W y[], size_t y_size) {
691 const int32_t relative_size = bigint_cmp(x, x_size, y, y_size);
692
693 // Swap if relative_size == -1
694 const bool need_swap = relative_size < 0;
695 CT::conditional_swap_ptr(need_swap, x, y);
696 CT::conditional_swap(need_swap, x_size, y_size);
697
698 /*
699 * We know at this point that x >= y so if y_size is larger than
700 * x_size, we are guaranteed they are just leading zeros which can
701 * be ignored
702 */
703 y_size = std::min(x_size, y_size);
704
705 bigint_sub3(z, x, x_size, y, y_size);
706
707 return relative_size;
708}
709
710/**
711* Set t to t-s modulo mod
712*
713* @param t first integer
714* @param s second integer
715* @param mod the modulus
716* @param mod_sw size of t, s, and mod
717* @param ws workspace of size mod_sw
718*/
719template <WordType W>
720inline constexpr void bigint_mod_sub(W t[], const W s[], const W mod[], size_t mod_sw, W ws[]) {
721 // ws = t - s
722 const W borrow = bigint_sub3(ws, t, mod_sw, s, mod_sw);
723
724 // Conditionally add back the modulus
725 bigint_cnd_add(borrow, ws, mod, mod_sw);
726
727 copy_mem(t, ws, mod_sw);
728}
729
730/**
731* Compute ((n1<<bits) + n0) / d
732*/
733template <WordType W>
734inline constexpr auto bigint_divop_vartime(W n1, W n0, W d) -> W {
735 if(d == 0) {
736 throw Invalid_Argument("bigint_divop_vartime divide by zero");
737 }
738
739 if constexpr(WordInfo<W>::dword_is_native) {
740 typename WordInfo<W>::dword n = n1;
741 n <<= WordInfo<W>::bits;
742 n |= n0;
743 return static_cast<W>(n / d);
744 } else {
745 W high = n1 % d;
746 W quotient = 0;
747
748 for(size_t i = 0; i != WordInfo<W>::bits; ++i) {
749 const W high_top_bit = high >> (WordInfo<W>::bits - 1);
750
751 high <<= 1;
752 high |= (n0 >> (WordInfo<W>::bits - 1 - i)) & 1;
753 quotient <<= 1;
754
755 if(high_top_bit || high >= d) {
756 high -= d;
757 quotient |= 1;
758 }
759 }
760
761 return quotient;
762 }
763}
764
765/**
766* Compute ((n1<<bits) + n0) % d
767*/
768template <WordType W>
769inline constexpr auto bigint_modop_vartime(W n1, W n0, W d) -> W {
770 if(d == 0) {
771 throw Invalid_Argument("bigint_modop_vartime divide by zero");
772 }
773
774 W z = bigint_divop_vartime(n1, n0, d);
775 W carry = 0;
776 z = word_madd2(z, d, &carry);
777 return (n0 - z);
778}
779
780/*
781* Compute an integer x such that (a*x) == -1 (mod 2^n)
782*
783* Throws an exception if input is even, since in that case no inverse
784* exists. If input is odd, then input and 2^n are relatively prime and
785* the inverse exists.
786*/
787template <WordType W>
788inline constexpr auto monty_inverse(W a) -> W {
789 if(a % 2 == 0) {
790 throw Invalid_Argument("monty_inverse only valid for odd integers");
791 }
792
793 /*
794 * From "A New Algorithm for Inversion mod p^k" by Çetin Kaya Koç
795 * https://eprint.iacr.org/2017/411.pdf sections 5 and 7.
796 */
797
798 W b = 1;
799 W r = 0;
800
801 for(size_t i = 0; i != WordInfo<W>::bits; ++i) {
802 const W bi = b % 2;
803 r >>= 1;
804 r += bi << (WordInfo<W>::bits - 1);
805
806 b -= a * bi;
807 b >>= 1;
808 }
809
810 // Now invert in addition space
811 r = (WordInfo<W>::max - r) + 1;
812
813 return r;
814}
815
816template <size_t S, WordType W, size_t N>
817inline constexpr W shift_left(std::array<W, N>& x) {
818 static_assert(S < WordInfo<W>::bits, "Shift too large");
819
820 W carry = 0;
821 for(size_t i = 0; i != N; ++i) {
822 const W w = x[i];
823 x[i] = (w << S) | carry;
824 carry = w >> (WordInfo<W>::bits - S);
825 }
826
827 return carry;
828}
829
830template <size_t S, WordType W, size_t N>
831inline constexpr W shift_right(std::array<W, N>& x) {
832 static_assert(S < WordInfo<W>::bits, "Shift too large");
833
834 W carry = 0;
835 for(size_t i = 0; i != N; ++i) {
836 const W w = x[N - 1 - i];
837 x[N - 1 - i] = (w >> S) | carry;
838 carry = w << (WordInfo<W>::bits - S);
839 }
840
841 return carry;
842}
843
844// Should be consteval but this triggers a bug in Clang 14
845template <WordType W, size_t N>
846constexpr auto hex_to_words(const char (&s)[N]) {
847 // Char count includes null terminator which we ignore
848 const constexpr size_t C = N - 1;
849
850 // Number of nibbles that a word can hold
851 const constexpr size_t NPW = (WordInfo<W>::bits / 4);
852
853 // Round up to the next number of words that will fit the input
854 const constexpr size_t S = (C + NPW - 1) / NPW;
855
856 auto hex2int = [](char c) -> int8_t {
857 if(c >= '0' && c <= '9') {
858 return static_cast<int8_t>(c - '0');
859 } else if(c >= 'a' && c <= 'f') {
860 return static_cast<int8_t>(c - 'a' + 10);
861 } else if(c >= 'A' && c <= 'F') {
862 return static_cast<int8_t>(c - 'A' + 10);
863 } else {
864 return -1;
865 }
866 };
867
868 std::array<W, S> r = {0};
869
870 for(size_t i = 0; i != C; ++i) {
871 const int8_t c = hex2int(s[i]);
872 if(c >= 0) {
873 shift_left<4>(r);
874 r[0] += c;
875 }
876 }
877
878 return r;
879}
880
881/*
882* Comba Multiplication / Squaring
883*/
884BOTAN_FUZZER_API void bigint_comba_mul4(word z[8], const word x[4], const word y[4]);
885BOTAN_FUZZER_API void bigint_comba_mul6(word z[12], const word x[6], const word y[6]);
886BOTAN_FUZZER_API void bigint_comba_mul7(word z[14], const word x[7], const word y[7]);
887BOTAN_FUZZER_API void bigint_comba_mul8(word z[16], const word x[8], const word y[8]);
888BOTAN_FUZZER_API void bigint_comba_mul9(word z[18], const word x[9], const word y[9]);
889BOTAN_FUZZER_API void bigint_comba_mul16(word z[32], const word x[16], const word y[16]);
890BOTAN_FUZZER_API void bigint_comba_mul24(word z[48], const word x[24], const word y[24]);
891
892BOTAN_FUZZER_API void bigint_comba_sqr4(word out[8], const word in[4]);
893BOTAN_FUZZER_API void bigint_comba_sqr6(word out[12], const word in[6]);
894BOTAN_FUZZER_API void bigint_comba_sqr7(word out[14], const word x[7]);
895BOTAN_FUZZER_API void bigint_comba_sqr8(word out[16], const word in[8]);
896BOTAN_FUZZER_API void bigint_comba_sqr9(word out[18], const word in[9]);
897BOTAN_FUZZER_API void bigint_comba_sqr16(word out[32], const word in[16]);
898BOTAN_FUZZER_API void bigint_comba_sqr24(word out[48], const word in[24]);
899
900/*
901* Comba Fixed Length Multiplication
902*/
903template <size_t N, WordType W>
904constexpr inline void comba_mul(W z[2 * N], const W x[N], const W y[N]) {
905 if(!std::is_constant_evaluated()) {
906 if constexpr(std::same_as<W, word> && N == 4) {
907 return bigint_comba_mul4(z, x, y);
908 }
909 if constexpr(std::same_as<W, word> && N == 6) {
910 return bigint_comba_mul6(z, x, y);
911 }
912 if constexpr(std::same_as<W, word> && N == 7) {
913 return bigint_comba_mul7(z, x, y);
914 }
915 if constexpr(std::same_as<W, word> && N == 8) {
916 return bigint_comba_mul8(z, x, y);
917 }
918 if constexpr(std::same_as<W, word> && N == 9) {
919 return bigint_comba_mul9(z, x, y);
920 }
921 if constexpr(std::same_as<W, word> && N == 16) {
922 return bigint_comba_mul16(z, x, y);
923 }
924 }
925
926 word3<W> accum;
927
928 for(size_t i = 0; i != 2 * N; ++i) {
929 const size_t start = i + 1 < N ? 0 : i + 1 - N;
930 const size_t end = std::min(N, i + 1);
931
932 for(size_t j = start; j != end; ++j) {
933 accum.mul(x[j], y[i - j]);
934 }
935 z[i] = accum.extract();
936 }
937}
938
939template <size_t N, WordType W>
940constexpr inline void comba_sqr(W z[2 * N], const W x[N]) {
941 if(!std::is_constant_evaluated()) {
942 if constexpr(std::same_as<W, word> && N == 4) {
943 return bigint_comba_sqr4(z, x);
944 }
945 if constexpr(std::same_as<W, word> && N == 6) {
946 return bigint_comba_sqr6(z, x);
947 }
948 if constexpr(std::same_as<W, word> && N == 7) {
949 return bigint_comba_sqr7(z, x);
950 }
951 if constexpr(std::same_as<W, word> && N == 8) {
952 return bigint_comba_sqr8(z, x);
953 }
954 if constexpr(std::same_as<W, word> && N == 9) {
955 return bigint_comba_sqr9(z, x);
956 }
957 if constexpr(std::same_as<W, word> && N == 16) {
958 return bigint_comba_sqr16(z, x);
959 }
960 }
961
962 word3<W> accum;
963
964 for(size_t i = 0; i != 2 * N; ++i) {
965 const size_t start = i + 1 < N ? 0 : i + 1 - N;
966 const size_t end = std::min(N, i + 1);
967
968 for(size_t j = start; j != end; ++j) {
969 accum.mul(x[j], x[i - j]);
970 }
971 z[i] = accum.extract();
972 }
973}
974
975/*
976* Montgomery reduction
977*
978* Each of these functions makes the following assumptions:
979*
980* z_size == 2*p_size
981* ws_size >= p_size
982*/
983BOTAN_FUZZER_API void bigint_monty_redc_4(word z[8], const word p[4], word p_dash, word ws[]);
984BOTAN_FUZZER_API void bigint_monty_redc_6(word z[12], const word p[6], word p_dash, word ws[]);
985BOTAN_FUZZER_API void bigint_monty_redc_8(word z[16], const word p[8], word p_dash, word ws[]);
986BOTAN_FUZZER_API void bigint_monty_redc_16(word z[32], const word p[16], word p_dash, word ws[]);
987BOTAN_FUZZER_API void bigint_monty_redc_24(word z[48], const word p[24], word p_dash, word ws[]);
988BOTAN_FUZZER_API void bigint_monty_redc_32(word z[64], const word p[32], word p_dash, word ws[]);
989
991void bigint_monty_redc_generic(word z[], size_t z_size, const word p[], size_t p_size, word p_dash, word ws[]);
992
993/**
994* Montgomery Reduction
995* @param z integer to reduce, of size exactly 2*p_size. Output is in
996* the first p_size words, higher words are set to zero.
997* @param p modulus
998* @param p_size size of p
999* @param p_dash Montgomery value
1000* @param ws array of at least p_size words
1001* @param ws_size size of ws in words
1002*/
1003inline void bigint_monty_redc(word z[], const word p[], size_t p_size, word p_dash, word ws[], size_t ws_size) {
1004 const size_t z_size = 2 * p_size;
1005
1006 BOTAN_ARG_CHECK(ws_size >= p_size, "Montgomery reduction workspace too small");
1007
1008 if(p_size == 4) {
1009 bigint_monty_redc_4(z, p, p_dash, ws);
1010 } else if(p_size == 6) {
1011 bigint_monty_redc_6(z, p, p_dash, ws);
1012 } else if(p_size == 8) {
1013 bigint_monty_redc_8(z, p, p_dash, ws);
1014 } else if(p_size == 16) {
1015 bigint_monty_redc_16(z, p, p_dash, ws);
1016 } else if(p_size == 24) {
1017 bigint_monty_redc_24(z, p, p_dash, ws);
1018 } else if(p_size == 32) {
1019 bigint_monty_redc_32(z, p, p_dash, ws);
1020 } else {
1021 bigint_monty_redc_generic(z, z_size, p, p_size, p_dash, ws);
1022 }
1023}
1024
1025/**
1026* Basecase O(N^2) multiplication
1027*/
1029void basecase_mul(word z[], size_t z_size, const word x[], size_t x_size, const word y[], size_t y_size);
1030
1031/**
1032* Basecase O(N^2) squaring
1033*/
1035void basecase_sqr(word z[], size_t z_size, const word x[], size_t x_size);
1036
1037/*
1038* High Level Multiplication/Squaring Interfaces
1039*/
1040void bigint_mul(word z[],
1041 size_t z_size,
1042 const word x[],
1043 size_t x_size,
1044 size_t x_sw,
1045 const word y[],
1046 size_t y_size,
1047 size_t y_sw,
1048 word workspace[],
1049 size_t ws_size);
1050
1051void 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);
1052
1053/**
1054* Return 2**B - C
1055*/
1056template <WordType W, size_t N, W C>
1057consteval std::array<W, N> crandall_p() {
1058 static_assert(C % 2 == 1);
1059 std::array<W, N> P;
1060 for(size_t i = 0; i != N; ++i) {
1061 P[i] = WordInfo<W>::max;
1062 }
1063 P[0] = WordInfo<W>::max - (C - 1);
1064 return P;
1065}
1066
1067/**
1068* Reduce z modulo p = 2**B - C where C is small
1069*
1070* z is assumed to be at most (p-1)**2
1071*
1072* For details on the algorithm see
1073* - Handbook of Applied Cryptography, Algorithm 14.47
1074* - Guide to Elliptic Curve Cryptography, Algorithm 2.54 and Note 2.55
1075*
1076*/
1077template <WordType W, size_t N, W C>
1078constexpr std::array<W, N> redc_crandall(std::span<const W, 2 * N> z) {
1079 static_assert(N >= 2);
1080
1081 std::array<W, N> hi = {};
1082
1083 // hi = hi * c + lo
1084
1085 W carry = 0;
1086 for(size_t i = 0; i != N; ++i) {
1087 hi[i] = word_madd3(z[i + N], C, z[i], &carry);
1088 }
1089
1090 // hi += carry * C
1091 word carry_c[2] = {0};
1092 carry_c[0] = word_madd2(carry, C, &carry_c[1]);
1093
1094 carry = bigint_add2_nc(hi.data(), N, carry_c, 2);
1095
1096 constexpr auto P = crandall_p<W, N, C>();
1097
1098 std::array<W, N> r = {};
1099 bigint_monty_maybe_sub<N, W>(r.data(), carry, hi.data(), P.data());
1100
1101 return r;
1102}
1103
1104/**
1105* Set r to r - C. Then if r < 0, add P to r
1106*/
1107template <size_t N, WordType W>
1108constexpr inline void bigint_correct_redc(std::array<W, N>& r, const std::array<W, N>& P, const std::array<W, N>& C) {
1109 // TODO look into combining the two operations for important values of N
1110 W borrow = bigint_sub2(r.data(), N, C.data(), N);
1111 bigint_cnd_add(borrow, r.data(), N, P.data(), N);
1112}
1113
1114} // namespace Botan
1115
1116#endif
#define BOTAN_FUZZER_API
Definition api.h:51
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:98
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:50
constexpr void select_n(T output[], const T x[], const T y[], size_t len) const
Definition ct_utils.h:576
static constexpr Mask< T > expand(T v)
Definition ct_utils.h:408
constexpr T select(T x, T y) const
Definition ct_utils.h:559
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:453
static constexpr Mask< T > is_lt(T x, T y)
Definition ct_utils.h:461
static constexpr Mask< T > is_zero(T x)
Definition ct_utils.h:448
constexpr W extract()
Definition mp_asmi.h:648
constexpr void mul(W x, W y)
Definition mp_asmi.h:642
constexpr void conditional_swap_ptr(bool cnd, T &x, T &y)
Definition ct_utils.h:764
constexpr void conditional_swap(bool cnd, T &x, T &y)
Definition ct_utils.h:758
constexpr Mask< T > conditional_assign_mem(T cnd, T *sink, const T *src, size_t elems)
Definition ct_utils.h:744
constexpr Mask< T > conditional_copy_mem(Mask< T > mask, T *to, const T *from0, const T *from1, size_t elems)
Definition ct_utils.h:732
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:64
constexpr void bigint_cnd_abs(W cnd, W x[], size_t size)
Definition mp_core.h:173
constexpr void bigint_linmul3(W z[], const W x[], size_t x_size, W y)
Definition mp_core.h:550
constexpr auto bigint_add(std::span< W, N > z, std::span< const W, N > x, std::span< const W, N > y) -> W
Definition mp_core.h:238
constexpr void bigint_cnd_swap(W cnd, W x[], W y[], size_t size)
Definition mp_core.h:31
constexpr auto word8_sub3(W z[8], const W x[8], const W y[8], W carry) -> W
Definition mp_asmi.h:367
constexpr W shift_left(std::array< W, N > &x)
Definition mp_core.h:817
constexpr auto word_sub(W x, W y, W *carry) -> W
Definition mp_asmi.h:282
void bigint_monty_redc(word z[], const word p[], size_t p_size, word p_dash, word ws[], size_t ws_size)
Definition mp_core.h:1003
constexpr auto word_add(W x, W y, W *carry) -> W
Definition mp_asmi.h:178
constexpr void comba_sqr(W z[2 *N], const W x[N])
Definition mp_core.h:940
constexpr uint64_t carry_shift(const donna128 &a, size_t shift)
Definition donna128.h:133
constexpr void bigint_shr2(W y[], const W x[], size_t x_size, size_t shift)
Definition mp_core.h:509
BOTAN_FUZZER_API void basecase_sqr(word z[], size_t z_size, const word x[], size_t x_size)
Definition mp_karat.cpp:46
void bigint_comba_sqr4(word z[8], const word x[4])
Definition mp_comba.cpp:16
void bigint_comba_sqr6(word z[12], const word x[6])
Definition mp_comba.cpp:74
BOTAN_FUZZER_API void bigint_monty_redc_24(word z[48], const word p[24], word p_dash, word ws[])
constexpr void bigint_shr1(W x[], size_t x_size, size_t shift)
Definition mp_core.h:467
constexpr auto word8_add3(W z[8], const W x[8], const W y[8], W carry) -> W
Definition mp_asmi.h:237
constexpr auto word4_sub3(W z[4], const W x[4], const W y[4], W carry) -> W
Definition mp_asmi.h:390
constexpr void comba_mul(W z[2 *N], const W x[N], const W y[N])
Definition mp_core.h:904
constexpr auto word8_sub2(W x[8], const W y[8], W carry) -> W
Definition mp_asmi.h:315
void bigint_comba_sqr7(word z[14], const word x[7])
Definition mp_comba.cpp:171
void bigint_comba_mul4(word z[8], const word x[4], const word y[4])
Definition mp_comba.cpp:42
constexpr auto word_madd2(W a, W b, W *c) -> W
Definition mp_asmi.h:67
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)
Definition mp_karat.cpp:326
void bigint_comba_mul16(word z[32], const word x[16], const word y[16])
Definition mp_comba.cpp:794
constexpr auto word8_sub2_rev(W x[8], const W y[8], W carry) -> W
Definition mp_asmi.h:341
constexpr auto bigint_sub3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:322
constexpr auto monty_inverse(W a) -> W
Definition mp_core.h:788
void bigint_mul(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, const word y[], size_t y_size, size_t y_sw, word workspace[], size_t ws_size)
Definition mp_karat.cpp:282
constexpr auto bigint_cnd_addsub(CT::Mask< W > mask, W x[], const W y[], const W z[], size_t size) -> W
Definition mp_core.h:143
void bigint_comba_mul6(word z[12], const word x[6], const word y[6])
Definition mp_comba.cpp:115
BOTAN_FUZZER_API void bigint_monty_redc_4(word z[8], const word p[4], word p_dash, word ws[])
constexpr void bigint_shl1(W x[], size_t x_size, size_t x_words, size_t shift)
Definition mp_core.h:448
constexpr auto word4_add3(W z[4], const W x[4], const W y[4], W carry) -> W
Definition mp_asmi.h:260
consteval std::array< W, N > crandall_p()
Definition mp_core.h:1057
constexpr auto bigint_ct_is_eq(const W x[], size_t x_size, const W y[], size_t y_size) -> CT::Mask< W >
Definition mp_core.h:653
constexpr int32_t bigint_cmp(const W x[], size_t x_size, const W y[], size_t y_size)
Definition mp_core.h:573
void bigint_comba_mul7(word z[14], const word x[7], const word y[7])
Definition mp_comba.cpp:221
constexpr auto bigint_cnd_sub(W cnd, W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:75
constexpr void bigint_monty_maybe_sub(size_t N, W z[], W x0, const W x[], const W p[])
Definition mp_core.h:355
constexpr void bigint_shl2(W y[], const W x[], size_t x_size, size_t shift)
Definition mp_core.h:491
void bigint_comba_mul9(word z[18], const word x[9], const word y[9])
Definition mp_comba.cpp:511
constexpr W bigint_cnd_add(W cnd, W x[], size_t x_size, const W y[], size_t y_size)
Definition mp_core.h:43
void carry(int64_t &h0, int64_t &h1)
constexpr auto word8_linmul2(W x[8], W y, W carry) -> W
Definition mp_asmi.h:412
void bigint_comba_mul24(word z[48], const word x[24], const word y[24])
constexpr auto bigint_modop_vartime(W n1, W n0, W d) -> W
Definition mp_core.h:769
constexpr auto bigint_sub_abs(W z[], const W x[], const W y[], size_t N, W ws[]) -> CT::Mask< W >
Definition mp_core.h:420
BOTAN_FUZZER_API void bigint_monty_redc_6(word z[12], const word p[6], word p_dash, word ws[])
constexpr void bigint_add2(W x[], size_t x_size, const W y[], size_t y_size)
Definition mp_core.h:256
constexpr auto bigint_ct_is_lt(const W x[], size_t x_size, const W y[], size_t y_size, bool lt_or_equal=false) -> CT::Mask< W >
Definition mp_core.h:620
constexpr std::array< W, N > redc_crandall(std::span< const W, 2 *N > z)
Definition mp_core.h:1078
constexpr void bigint_correct_redc(std::array< W, N > &r, const std::array< W, N > &P, const std::array< W, N > &C)
Definition mp_core.h:1108
const SIMD_8x32 & b
constexpr auto word8_add2(W x[8], const W y[8], W carry) -> W
Definition mp_asmi.h:211
constexpr auto bigint_sub2(W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:272
void bigint_comba_sqr8(word z[16], const word x[8])
Definition mp_comba.cpp:292
constexpr auto hex_to_words(const char(&s)[N])
Definition mp_core.h:846
void bigint_comba_sqr16(word z[32], const word x[16])
Definition mp_comba.cpp:618
constexpr void bigint_cnd_add_or_sub(CT::Mask< W > mask, W x[], const W y[], size_t size)
Definition mp_core.h:110
constexpr void bigint_sub2_rev(W x[], const W y[], size_t y_size)
Definition mp_core.h:298
void bigint_comba_sqr9(word z[18], const word x[9])
Definition mp_comba.cpp:440
constexpr auto bigint_add2_nc(W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:187
constexpr auto word8_linmul3(W z[8], const W x[8], W y, W carry) -> W
Definition mp_asmi.h:438
BOTAN_FUZZER_API void basecase_mul(word z[], size_t z_size, const word x[], size_t x_size, const word y[], size_t y_size)
Definition mp_karat.cpp:20
constexpr void bigint_add3(W z[], const W x[], size_t x_size, const W y[], size_t y_size)
Definition mp_core.h:264
BOTAN_FUZZER_API void bigint_monty_redc_generic(word z[], size_t z_size, const word p[], size_t p_size, word p_dash, word ws[])
Definition mp_monty.cpp:31
void bigint_comba_sqr24(word z[48], const word x[24])
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:147
BOTAN_FUZZER_API void bigint_monty_redc_32(word z[64], const word p[32], word p_dash, word ws[])
void bigint_comba_mul8(word z[16], const word x[8], const word y[8])
Definition mp_comba.cpp:352
BOTAN_FUZZER_API void bigint_monty_redc_16(word z[32], const word p[16], word p_dash, word ws[])
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:121
constexpr auto bigint_divop_vartime(W n1, W n0, W d) -> W
Definition mp_core.h:734
constexpr W shift_right(std::array< W, N > &x)
Definition mp_core.h:831
BOTAN_FUZZER_API void bigint_monty_redc_8(word z[16], const word p[8], word p_dash, word ws[])
constexpr void bigint_mod_sub(W t[], const W s[], const W mod[], size_t mod_sw, W ws[])
Definition mp_core.h:720
constexpr auto word_madd3(W a, W b, W c, W *d) -> W
Definition mp_asmi.h:93
constexpr auto bigint_add3_nc(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:213
constexpr auto bigint_linmul2(W x[], size_t x_size, W y) -> W
Definition mp_core.h:533