Coverage Report

Created: 2022-09-23 06:05

/src/botan/src/lib/math/numbertheory/monty_exp.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* Montgomery Exponentiation
3
* (C) 1999-2010,2012,2018 Jack Lloyd
4
*     2016 Matthias Gierlings
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8
9
#include <botan/internal/monty_exp.h>
10
#include <botan/internal/ct_utils.h>
11
#include <botan/internal/rounding.h>
12
#include <botan/numthry.h>
13
#include <botan/reducer.h>
14
#include <botan/internal/monty.h>
15
16
namespace Botan {
17
18
class Montgomery_Exponentation_State
19
   {
20
   public:
21
      Montgomery_Exponentation_State(const std::shared_ptr<const Montgomery_Params>& params,
22
                                     const BigInt& g,
23
                                     size_t window_bits,
24
                                     bool const_time);
25
26
      BigInt exponentiation(const BigInt& k, size_t max_k_bits) const;
27
28
      BigInt exponentiation_vartime(const BigInt& k) const;
29
   private:
30
      std::shared_ptr<const Montgomery_Params> m_params;
31
      std::vector<Montgomery_Int> m_g;
32
      size_t m_window_bits;
33
   };
34
35
Montgomery_Exponentation_State::Montgomery_Exponentation_State(
36
   const std::shared_ptr<const Montgomery_Params>& params,
37
   const BigInt& g,
38
   size_t window_bits,
39
   bool const_time) :
40
   m_params(params),
41
   m_window_bits(window_bits == 0 ? 4 : window_bits)
42
96.3k
   {
43
96.3k
   BOTAN_ARG_CHECK(g < m_params->p(), "Montgomery base too big");
44
45
96.3k
   if(m_window_bits < 1 || m_window_bits > 12) // really even 8 is too large ...
46
0
      throw Invalid_Argument("Invalid window bits for Montgomery exponentiation");
47
48
96.3k
   const size_t window_size = (static_cast<size_t>(1) << m_window_bits);
49
50
96.3k
   m_g.reserve(window_size);
51
52
96.3k
   m_g.push_back(Montgomery_Int(m_params, m_params->R1(), false));
53
54
96.3k
   m_g.push_back(Montgomery_Int(m_params, g));
55
56
1.34M
   for(size_t i = 2; i != window_size; ++i)
57
1.24M
      {
58
1.24M
      m_g.push_back(m_g[1] * m_g[i - 1]);
59
1.24M
      }
60
61
   // Resize each element to exactly p words
62
1.53M
   for(size_t i = 0; i != window_size; ++i)
63
1.43M
      {
64
1.43M
      m_g[i].fix_size();
65
1.43M
      if(const_time)
66
53.8k
         m_g[i].const_time_poison();
67
1.43M
      }
68
96.3k
   }
69
70
namespace {
71
72
void const_time_lookup(secure_vector<word>& output,
73
                       const std::vector<Montgomery_Int>& g,
74
                       size_t nibble)
75
245k
   {
76
245k
   BOTAN_ASSERT_NOMSG(g.size() % 2 == 0); // actually a power of 2
77
78
245k
   const size_t words = output.size();
79
80
245k
   clear_mem(output.data(), output.size());
81
82
2.20M
   for(size_t i = 0; i != g.size(); i += 2)
83
1.96M
      {
84
1.96M
      const secure_vector<word>& vec_0 = g[i  ].repr().get_word_vector();
85
1.96M
      const secure_vector<word>& vec_1 = g[i+1].repr().get_word_vector();
86
87
1.96M
      BOTAN_ASSERT_NOMSG(vec_0.size() >= words && vec_1.size() >= words);
88
89
1.96M
      const auto mask_0 = CT::Mask<word>::is_equal(nibble, i);
90
1.96M
      const auto mask_1 = CT::Mask<word>::is_equal(nibble, i+1);
91
92
27.9M
      for(size_t w = 0; w != words; ++w)
93
25.9M
         {
94
25.9M
         output[w] |= mask_0.if_set_return(vec_0[w]);
95
25.9M
         output[w] |= mask_1.if_set_return(vec_1[w]);
96
25.9M
         }
97
1.96M
      }
98
245k
   }
99
100
}
101
102
BigInt Montgomery_Exponentation_State::exponentiation(const BigInt& scalar, size_t max_k_bits) const
103
2.83k
   {
104
2.83k
   BOTAN_DEBUG_ASSERT(scalar.bits() <= max_k_bits);
105
   // TODO add a const-time implementation of above assert and use it in release builds
106
107
2.83k
   const size_t exp_nibbles = (max_k_bits + m_window_bits - 1) / m_window_bits;
108
109
2.83k
   if(exp_nibbles == 0)
110
8
      return BigInt::one();
111
112
2.82k
   secure_vector<word> e_bits(m_params->p_words());
113
2.82k
   secure_vector<word> ws;
114
115
2.82k
   const_time_lookup(e_bits, m_g, scalar.get_substring(m_window_bits*(exp_nibbles-1), m_window_bits));
116
2.82k
   Montgomery_Int x(m_params, e_bits.data(), e_bits.size(), false);
117
118
245k
   for(size_t i = exp_nibbles - 1; i > 0; --i)
119
242k
      {
120
242k
      x.square_this_n_times(ws, m_window_bits);
121
242k
      const_time_lookup(e_bits, m_g, scalar.get_substring(m_window_bits*(i-1), m_window_bits));
122
242k
      x.mul_by(e_bits, ws);
123
242k
      }
124
125
2.82k
   x.const_time_unpoison();
126
2.82k
   return x.value();
127
2.83k
   }
128
129
BigInt Montgomery_Exponentation_State::exponentiation_vartime(const BigInt& scalar) const
130
92.9k
   {
131
92.9k
   const size_t exp_nibbles = (scalar.bits() + m_window_bits - 1) / m_window_bits;
132
133
92.9k
   secure_vector<word> ws;
134
135
92.9k
   if(exp_nibbles == 0)
136
0
      return BigInt::one();
137
138
92.9k
   Montgomery_Int x = m_g[scalar.get_substring(m_window_bits*(exp_nibbles-1), m_window_bits)];
139
140
2.95M
   for(size_t i = exp_nibbles - 1; i > 0; --i)
141
2.86M
      {
142
2.86M
      x.square_this_n_times(ws, m_window_bits);
143
144
2.86M
      const uint32_t nibble = scalar.get_substring(m_window_bits*(i-1), m_window_bits);
145
2.86M
      if(nibble > 0)
146
1.22M
         x.mul_by(m_g[nibble], ws);
147
2.86M
      }
148
149
92.9k
   x.const_time_unpoison();
150
92.9k
   return x.value();
151
92.9k
   }
152
153
std::shared_ptr<const Montgomery_Exponentation_State>
154
monty_precompute(const std::shared_ptr<const Montgomery_Params>& params,
155
                 const BigInt& g,
156
                 size_t window_bits,
157
                 bool const_time)
158
96.3k
   {
159
96.3k
   return std::make_shared<const Montgomery_Exponentation_State>(params, g, window_bits, const_time);
160
96.3k
   }
161
162
BigInt monty_execute(const Montgomery_Exponentation_State& precomputed_state,
163
                     const BigInt& k, size_t max_k_bits)
164
2.83k
   {
165
2.83k
   return precomputed_state.exponentiation(k, max_k_bits);
166
2.83k
   }
167
168
BigInt monty_execute_vartime(const Montgomery_Exponentation_State& precomputed_state,
169
                             const BigInt& k)
170
92.9k
   {
171
92.9k
   return precomputed_state.exponentiation_vartime(k);
172
92.9k
   }
173
174
BigInt monty_multi_exp(const std::shared_ptr<const Montgomery_Params>& params_p,
175
                       const BigInt& x_bn,
176
                       const BigInt& z1,
177
                       const BigInt& y_bn,
178
                       const BigInt& z2)
179
177
   {
180
177
   if(z1.is_negative() || z2.is_negative())
181
0
      throw Invalid_Argument("multi_exponentiate exponents must be positive");
182
183
177
   const size_t z_bits = round_up(std::max(z1.bits(), z2.bits()), 2);
184
185
177
   secure_vector<word> ws;
186
187
177
   const Montgomery_Int one(params_p, params_p->R1(), false);
188
   //const Montgomery_Int one(params_p, 1);
189
190
177
   const Montgomery_Int x1(params_p, x_bn);
191
177
   const Montgomery_Int x2 = x1.square(ws);
192
177
   const Montgomery_Int x3 = x2.mul(x1, ws);
193
194
177
   const Montgomery_Int y1(params_p, y_bn);
195
177
   const Montgomery_Int y2 = y1.square(ws);
196
177
   const Montgomery_Int y3 = y2.mul(y1, ws);
197
198
177
   const Montgomery_Int y1x1 = y1.mul(x1, ws);
199
177
   const Montgomery_Int y1x2 = y1.mul(x2, ws);
200
177
   const Montgomery_Int y1x3 = y1.mul(x3, ws);
201
202
177
   const Montgomery_Int y2x1 = y2.mul(x1, ws);
203
177
   const Montgomery_Int y2x2 = y2.mul(x2, ws);
204
177
   const Montgomery_Int y2x3 = y2.mul(x3, ws);
205
206
177
   const Montgomery_Int y3x1 = y3.mul(x1, ws);
207
177
   const Montgomery_Int y3x2 = y3.mul(x2, ws);
208
177
   const Montgomery_Int y3x3 = y3.mul(x3, ws);
209
210
177
   const Montgomery_Int* M[16] = {
211
177
      &one,
212
177
      &x1,                    // 0001
213
177
      &x2,                    // 0010
214
177
      &x3,                    // 0011
215
177
      &y1,                    // 0100
216
177
      &y1x1,
217
177
      &y1x2,
218
177
      &y1x3,
219
177
      &y2,                    // 1000
220
177
      &y2x1,
221
177
      &y2x2,
222
177
      &y2x3,
223
177
      &y3,                    // 1100
224
177
      &y3x1,
225
177
      &y3x2,
226
177
      &y3x3
227
177
   };
228
229
177
   Montgomery_Int H = one;
230
231
64.6k
   for(size_t i = 0; i != z_bits; i += 2)
232
64.4k
      {
233
64.4k
      if(i > 0)
234
64.3k
         {
235
64.3k
         H.square_this(ws);
236
64.3k
         H.square_this(ws);
237
64.3k
         }
238
239
64.4k
      const uint32_t z1_b = z1.get_substring(z_bits - i - 2, 2);
240
64.4k
      const uint32_t z2_b = z2.get_substring(z_bits - i - 2, 2);
241
242
64.4k
      const uint32_t z12 = (4*z2_b) + z1_b;
243
244
64.4k
      H.mul_by(*M[z12], ws);
245
64.4k
      }
246
247
177
   return H.value();
248
177
   }
249
250
}
251