Coverage Report

Created: 2020-08-01 06:18

/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/monty.h>
15
16
namespace Botan {
17
18
class Montgomery_Exponentation_State
19
   {
20
   public:
21
      Montgomery_Exponentation_State(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
      bool m_const_time;
34
   };
35
36
Montgomery_Exponentation_State::Montgomery_Exponentation_State(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
   m_const_time(const_time)
43
91.5k
   {
44
91.5k
   BOTAN_ARG_CHECK(g < m_params->p(), "Montgomery base too big");
45
91.5k
46
91.5k
   if(m_window_bits < 1 || m_window_bits > 12) // really even 8 is too large ...
47
0
      throw Invalid_Argument("Invalid window bits for Montgomery exponentiation");
48
91.5k
49
91.5k
   const size_t window_size = (static_cast<size_t>(1) << m_window_bits);
50
91.5k
51
91.5k
   m_g.reserve(window_size);
52
91.5k
53
91.5k
   m_g.push_back(Montgomery_Int(m_params, m_params->R1(), false));
54
91.5k
55
91.5k
   m_g.push_back(Montgomery_Int(m_params, g));
56
91.5k
57
1.28M
   for(size_t i = 2; i != window_size; ++i)
58
1.19M
      {
59
1.19M
      m_g.push_back(m_g[1] * m_g[i - 1]);
60
1.19M
      }
61
91.5k
62
91.5k
   // Resize each element to exactly p words
63
1.46M
   for(size_t i = 0; i != window_size; ++i)
64
1.37M
      {
65
1.37M
      m_g[i].fix_size();
66
1.37M
      if(const_time)
67
1.36M
         m_g[i].const_time_poison();
68
1.37M
      }
69
91.5k
   }
70
71
namespace {
72
73
void const_time_lookup(secure_vector<word>& output,
74
                       const std::vector<Montgomery_Int>& g,
75
                       size_t nibble)
76
2.80M
   {
77
2.80M
   BOTAN_ASSERT_NOMSG(g.size() % 2 == 0); // actually a power of 2
78
2.80M
79
2.80M
   const size_t words = output.size();
80
2.80M
81
2.80M
   clear_mem(output.data(), output.size());
82
2.80M
83
25.2M
   for(size_t i = 0; i != g.size(); i += 2)
84
22.4M
      {
85
22.4M
      const secure_vector<word>& vec_0 = g[i  ].repr().get_word_vector();
86
22.4M
      const secure_vector<word>& vec_1 = g[i+1].repr().get_word_vector();
87
22.4M
88
22.4M
      BOTAN_ASSERT_NOMSG(vec_0.size() >= words && vec_1.size() >= words);
89
22.4M
90
22.4M
      const auto mask_0 = CT::Mask<word>::is_equal(nibble, i);
91
22.4M
      const auto mask_1 = CT::Mask<word>::is_equal(nibble, i+1);
92
22.4M
93
420M
      for(size_t w = 0; w != words; ++w)
94
398M
         {
95
398M
         output[w] |= mask_0.if_set_return(vec_0[w]);
96
398M
         output[w] |= mask_1.if_set_return(vec_1[w]);
97
398M
         }
98
22.4M
      }
99
2.80M
   }
100
101
}
102
103
BigInt Montgomery_Exponentation_State::exponentiation(const BigInt& scalar, size_t max_k_bits) const
104
84.9k
   {
105
84.9k
   BOTAN_DEBUG_ASSERT(scalar.bits() <= max_k_bits);
106
84.9k
   // TODO add a const-time implementation of above assert and use it in release builds
107
84.9k
108
84.9k
   const size_t exp_nibbles = (max_k_bits + m_window_bits - 1) / m_window_bits;
109
84.9k
110
84.9k
   if(exp_nibbles == 0)
111
8
      return 1;
112
84.8k
113
84.8k
   secure_vector<word> e_bits(m_params->p_words());
114
84.8k
   secure_vector<word> ws;
115
84.8k
116
84.8k
   const_time_lookup(e_bits, m_g, scalar.get_substring(m_window_bits*(exp_nibbles-1), m_window_bits));
117
84.8k
   Montgomery_Int x(m_params, e_bits.data(), e_bits.size(), false);
118
84.8k
119
2.80M
   for(size_t i = exp_nibbles - 1; i > 0; --i)
120
2.72M
      {
121
2.72M
      x.square_this_n_times(ws, m_window_bits);
122
2.72M
      const_time_lookup(e_bits, m_g, scalar.get_substring(m_window_bits*(i-1), m_window_bits));
123
2.72M
      x.mul_by(e_bits, ws);
124
2.72M
      }
125
84.8k
126
84.8k
   x.const_time_unpoison();
127
84.8k
   return x.value();
128
84.8k
   }
129
130
BigInt Montgomery_Exponentation_State::exponentiation_vartime(const BigInt& scalar) const
131
6.24k
   {
132
6.24k
   BOTAN_ASSERT_NOMSG(m_const_time == false);
133
6.24k
134
6.24k
   const size_t exp_nibbles = (scalar.bits() + m_window_bits - 1) / m_window_bits;
135
6.24k
136
6.24k
   secure_vector<word> ws;
137
6.24k
138
6.24k
   if(exp_nibbles == 0)
139
0
      return 1;
140
6.24k
141
6.24k
   Montgomery_Int x = m_g[scalar.get_substring(m_window_bits*(exp_nibbles-1), m_window_bits)];
142
6.24k
143
336k
   for(size_t i = exp_nibbles - 1; i > 0; --i)
144
330k
      {
145
330k
      x.square_this_n_times(ws, m_window_bits);
146
330k
147
330k
      const uint32_t nibble = scalar.get_substring(m_window_bits*(i-1), m_window_bits);
148
330k
      if(nibble > 0)
149
74.4k
         x.mul_by(m_g[nibble], ws);
150
330k
      }
151
6.24k
152
6.24k
   x.const_time_unpoison();
153
6.24k
   return x.value();
154
6.24k
   }
155
156
std::shared_ptr<const Montgomery_Exponentation_State>
157
monty_precompute(std::shared_ptr<const Montgomery_Params> params,
158
                 const BigInt& g,
159
                 size_t window_bits,
160
                 bool const_time)
161
91.5k
   {
162
91.5k
   return std::make_shared<const Montgomery_Exponentation_State>(params, g, window_bits, const_time);
163
91.5k
   }
164
165
BigInt monty_execute(const Montgomery_Exponentation_State& precomputed_state,
166
                     const BigInt& k, size_t max_k_bits)
167
84.9k
   {
168
84.9k
   return precomputed_state.exponentiation(k, max_k_bits);
169
84.9k
   }
170
171
BigInt monty_execute_vartime(const Montgomery_Exponentation_State& precomputed_state,
172
                             const BigInt& k)
173
6.24k
   {
174
6.24k
   return precomputed_state.exponentiation_vartime(k);
175
6.24k
   }
176
177
BigInt monty_multi_exp(std::shared_ptr<const Montgomery_Params> params_p,
178
                       const BigInt& x_bn,
179
                       const BigInt& z1,
180
                       const BigInt& y_bn,
181
                       const BigInt& z2)
182
94
   {
183
94
   if(z1.is_negative() || z2.is_negative())
184
0
      throw Invalid_Argument("multi_exponentiate exponents must be positive");
185
94
186
94
   const size_t z_bits = round_up(std::max(z1.bits(), z2.bits()), 2);
187
94
188
94
   secure_vector<word> ws;
189
94
190
94
   const Montgomery_Int one(params_p, params_p->R1(), false);
191
94
   //const Montgomery_Int one(params_p, 1);
192
94
193
94
   const Montgomery_Int x1(params_p, x_bn);
194
94
   const Montgomery_Int x2 = x1.square(ws);
195
94
   const Montgomery_Int x3 = x2.mul(x1, ws);
196
94
197
94
   const Montgomery_Int y1(params_p, y_bn);
198
94
   const Montgomery_Int y2 = y1.square(ws);
199
94
   const Montgomery_Int y3 = y2.mul(y1, ws);
200
94
201
94
   const Montgomery_Int y1x1 = y1.mul(x1, ws);
202
94
   const Montgomery_Int y1x2 = y1.mul(x2, ws);
203
94
   const Montgomery_Int y1x3 = y1.mul(x3, ws);
204
94
205
94
   const Montgomery_Int y2x1 = y2.mul(x1, ws);
206
94
   const Montgomery_Int y2x2 = y2.mul(x2, ws);
207
94
   const Montgomery_Int y2x3 = y2.mul(x3, ws);
208
94
209
94
   const Montgomery_Int y3x1 = y3.mul(x1, ws);
210
94
   const Montgomery_Int y3x2 = y3.mul(x2, ws);
211
94
   const Montgomery_Int y3x3 = y3.mul(x3, ws);
212
94
213
94
   const Montgomery_Int* M[16] = {
214
94
      &one,
215
94
      &x1,                    // 0001
216
94
      &x2,                    // 0010
217
94
      &x3,                    // 0011
218
94
      &y1,                    // 0100
219
94
      &y1x1,
220
94
      &y1x2,
221
94
      &y1x3,
222
94
      &y2,                    // 1000
223
94
      &y2x1,
224
94
      &y2x2,
225
94
      &y2x3,
226
94
      &y3,                    // 1100
227
94
      &y3x1,
228
94
      &y3x2,
229
94
      &y3x3
230
94
   };
231
94
232
94
   Montgomery_Int H = one;
233
94
234
33.7k
   for(size_t i = 0; i != z_bits; i += 2)
235
33.6k
      {
236
33.6k
      if(i > 0)
237
33.5k
         {
238
33.5k
         H.square_this(ws);
239
33.5k
         H.square_this(ws);
240
33.5k
         }
241
33.6k
242
33.6k
      const uint32_t z1_b = z1.get_substring(z_bits - i - 2, 2);
243
33.6k
      const uint32_t z2_b = z2.get_substring(z_bits - i - 2, 2);
244
33.6k
245
33.6k
      const uint32_t z12 = (4*z2_b) + z1_b;
246
33.6k
247
33.6k
      H.mul_by(*M[z12], ws);
248
33.6k
      }
249
94
250
94
   return H.value();
251
94
   }
252
253
}
254