Coverage Report

Created: 2026-05-30 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/botan/src/lib/math/mp/mp_monty.cpp
Line
Count
Source
1
/*
2
* Montgomery Reduction
3
* (C) 1999-2011,2025 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
#include <botan/internal/mp_core.h>
11
12
#include <botan/assert.h>
13
14
namespace Botan {
15
16
namespace {
17
18
443M
BOTAN_FORCE_INLINE void mul_rev_range(word3<word>& accum, const word ws[], const word p[], size_t bound) {
19
   /*
20
   Unrolled version of:
21
22
   for(size_t i = 0; i < bound; ++i) {
23
      accum.mul(ws[i], p[bound - i]);
24
   }
25
   */
26
27
443M
   size_t lower = 0;
28
1.54G
   while(lower < bound) {
29
1.10G
      const size_t upper = bound - lower;
30
31
1.10G
      if(upper >= 16) {
32
284M
         accum.mul(ws[lower], p[upper]);
33
284M
         accum.mul(ws[lower + 1], p[upper - 1]);
34
284M
         accum.mul(ws[lower + 2], p[upper - 2]);
35
284M
         accum.mul(ws[lower + 3], p[upper - 3]);
36
284M
         accum.mul(ws[lower + 4], p[upper - 4]);
37
284M
         accum.mul(ws[lower + 5], p[upper - 5]);
38
284M
         accum.mul(ws[lower + 6], p[upper - 6]);
39
284M
         accum.mul(ws[lower + 7], p[upper - 7]);
40
284M
         accum.mul(ws[lower + 8], p[upper - 8]);
41
284M
         accum.mul(ws[lower + 9], p[upper - 9]);
42
284M
         accum.mul(ws[lower + 10], p[upper - 10]);
43
284M
         accum.mul(ws[lower + 11], p[upper - 11]);
44
284M
         accum.mul(ws[lower + 12], p[upper - 12]);
45
284M
         accum.mul(ws[lower + 13], p[upper - 13]);
46
284M
         accum.mul(ws[lower + 14], p[upper - 14]);
47
284M
         accum.mul(ws[lower + 15], p[upper - 15]);
48
284M
         lower += 16;
49
817M
      } else if(upper >= 8) {
50
166M
         accum.mul(ws[lower], p[upper]);
51
166M
         accum.mul(ws[lower + 1], p[upper - 1]);
52
166M
         accum.mul(ws[lower + 2], p[upper - 2]);
53
166M
         accum.mul(ws[lower + 3], p[upper - 3]);
54
166M
         accum.mul(ws[lower + 4], p[upper - 4]);
55
166M
         accum.mul(ws[lower + 5], p[upper - 5]);
56
166M
         accum.mul(ws[lower + 6], p[upper - 6]);
57
166M
         accum.mul(ws[lower + 7], p[upper - 7]);
58
166M
         lower += 8;
59
650M
      } else if(upper >= 4) {
60
205M
         accum.mul(ws[lower], p[upper]);
61
205M
         accum.mul(ws[lower + 1], p[upper - 1]);
62
205M
         accum.mul(ws[lower + 2], p[upper - 2]);
63
205M
         accum.mul(ws[lower + 3], p[upper - 3]);
64
205M
         lower += 4;
65
444M
      } else if(upper >= 2) {
66
221M
         accum.mul(ws[lower], p[upper]);
67
221M
         accum.mul(ws[lower + 1], p[upper - 1]);
68
221M
         lower += 2;
69
223M
      } else {
70
223M
         accum.mul(ws[lower], p[upper]);
71
223M
         lower += 1;
72
223M
      }
73
1.10G
   }
74
443M
}
75
76
}  // namespace
77
78
/*
79
* Montgomery reduction - product scanning form
80
*
81
* Algorithm 5 from "Energy-Efficient Software Implementation of Long
82
* Integer Modular Arithmetic"
83
* (https://www.iacr.org/archive/ches2005/006.pdf)
84
*
85
* See also
86
*
87
* https://eprint.iacr.org/2013/882.pdf
88
* https://www.microsoft.com/en-us/research/wp-content/uploads/1996/01/j37acmon.pdf
89
*/
90
void bigint_monty_redc_generic(
91
14.7M
   word r[], const word z[], size_t z_size, const word p[], size_t p_size, word p_dash, word ws[]) {
92
14.7M
   BOTAN_ARG_CHECK(z_size >= 2 * p_size && p_size > 0, "Invalid sizes for bigint_monty_redc_generic");
93
94
14.7M
   word3<word> accum;
95
96
14.7M
   accum.add(z[0]);
97
98
14.7M
   ws[0] = accum.monty_step(p[0], p_dash);
99
100
236M
   for(size_t i = 1; i != p_size; ++i) {
101
221M
      mul_rev_range(accum, ws, p, i);
102
221M
      accum.add(z[i]);
103
221M
      ws[i] = accum.monty_step(p[0], p_dash);
104
221M
   }
105
106
236M
   for(size_t i = 0; i != p_size - 1; ++i) {
107
221M
      mul_rev_range(accum, &ws[i + 1], &p[i], p_size - (i + 1));
108
221M
      accum.add(z[p_size + i]);
109
221M
      ws[i] = accum.extract();
110
221M
   }
111
112
14.7M
   accum.add(z[2 * p_size - 1]);
113
114
14.7M
   ws[p_size - 1] = accum.extract();
115
   // w1 is the final part, which is not stored in the workspace
116
14.7M
   const word w1 = accum.extract();
117
118
   /*
119
   * The result might need to be reduced mod p. To avoid a timing
120
   * channel, always perform the subtraction. If in the computation
121
   * of x - p a borrow is required then x was already < p.
122
   *
123
   * x starts at ws[0] and is p_size bytes long plus a possible high
124
   * digit left over in w1.
125
   *
126
   * x - p starts at z[0] and is also p_size bytes long
127
   *
128
   * If borrow was set after the subtraction, then x was already less
129
   * than p and the subtraction was not needed. In that case overwrite
130
   * z[0:p_size] with the original x in ws[0:p_size].
131
   *
132
   * We only copy out p_size in the final step because we know
133
   * the Montgomery result is < P
134
   */
135
136
14.7M
   bigint_monty_maybe_sub(p_size, r, w1, ws, p);
137
14.7M
}
138
139
}  // namespace Botan