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