Coverage Report

Created: 2022-06-23 06:44

/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
83.3k
   {
43
83.3k
   BOTAN_ARG_CHECK(g < m_params->p(), "Montgomery base too big");
44
45
83.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
83.3k
   const size_t window_size = (static_cast<size_t>(1) << m_window_bits);
49
50
83.3k
   m_g.reserve(window_size);
51
52
83.3k
   m_g.push_back(Montgomery_Int(m_params, m_params->R1(), false));
53
54
83.3k
   m_g.push_back(Montgomery_Int(m_params, g));
55
56
1.16M
   for(size_t i = 2; i != window_size; ++i)
57
1.08M
      {
58
1.08M
      m_g.push_back(m_g[1] * m_g[i - 1]);
59
1.08M
      }
60
61
   // Resize each element to exactly p words
62
1.33M
   for(size_t i = 0; i != window_size; ++i)
63
1.24M
      {
64
1.24M
      m_g[i].fix_size();
65
1.24M
      if(const_time)
66
42.8k
         m_g[i].const_time_poison();
67
1.24M
      }
68
83.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
196k
   {
76
196k
   BOTAN_ASSERT_NOMSG(g.size() % 2 == 0); // actually a power of 2
77
78
196k
   const size_t words = output.size();
79
80
196k
   clear_mem(output.data(), output.size());
81
82
1.77M
   for(size_t i = 0; i != g.size(); i += 2)
83
1.57M
      {
84
1.57M
      const secure_vector<word>& vec_0 = g[i  ].repr().get_word_vector();
85
1.57M
      const secure_vector<word>& vec_1 = g[i+1].repr().get_word_vector();
86
87
1.57M
      BOTAN_ASSERT_NOMSG(vec_0.size() >= words && vec_1.size() >= words);
88
89
1.57M
      const auto mask_0 = CT::Mask<word>::is_equal(nibble, i);
90
1.57M
      const auto mask_1 = CT::Mask<word>::is_equal(nibble, i+1);
91
92
21.6M
      for(size_t w = 0; w != words; ++w)
93
20.1M
         {
94
20.1M
         output[w] |= mask_0.if_set_return(vec_0[w]);
95
20.1M
         output[w] |= mask_1.if_set_return(vec_1[w]);
96
20.1M
         }
97
1.57M
      }
98
196k
   }
99
100
}
101
102
BigInt Montgomery_Exponentation_State::exponentiation(const BigInt& scalar, size_t max_k_bits) const
103
2.25k
   {
104
2.25k
   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.25k
   const size_t exp_nibbles = (max_k_bits + m_window_bits - 1) / m_window_bits;
108
109
2.25k
   if(exp_nibbles == 0)
110
12
      return BigInt::one();
111
112
2.24k
   secure_vector<word> e_bits(m_params->p_words());
113
2.24k
   secure_vector<word> ws;
114
115
2.24k
   const_time_lookup(e_bits, m_g, scalar.get_substring(m_window_bits*(exp_nibbles-1), m_window_bits));
116
2.24k
   Montgomery_Int x(m_params, e_bits.data(), e_bits.size(), false);
117
118
196k
   for(size_t i = exp_nibbles - 1; i > 0; --i)
119
194k
      {
120
194k
      x.square_this_n_times(ws, m_window_bits);
121
194k
      const_time_lookup(e_bits, m_g, scalar.get_substring(m_window_bits*(i-1), m_window_bits));
122
194k
      x.mul_by(e_bits, ws);
123
194k
      }
124
125
2.24k
   x.const_time_unpoison();
126
2.24k
   return x.value();
127
2.25k
   }
128
129
BigInt Montgomery_Exponentation_State::exponentiation_vartime(const BigInt& scalar) const
130
80.6k
   {
131
80.6k
   const size_t exp_nibbles = (scalar.bits() + m_window_bits - 1) / m_window_bits;
132
133
80.6k
   secure_vector<word> ws;
134
135
80.6k
   if(exp_nibbles == 0)
136
0
      return BigInt::one();
137
138
80.6k
   Montgomery_Int x = m_g[scalar.get_substring(m_window_bits*(exp_nibbles-1), m_window_bits)];
139
140
2.66M
   for(size_t i = exp_nibbles - 1; i > 0; --i)
141
2.58M
      {
142
2.58M
      x.square_this_n_times(ws, m_window_bits);
143
144
2.58M
      const uint32_t nibble = scalar.get_substring(m_window_bits*(i-1), m_window_bits);
145
2.58M
      if(nibble > 0)
146
1.14M
         x.mul_by(m_g[nibble], ws);
147
2.58M
      }
148
149
80.6k
   x.const_time_unpoison();
150
80.6k
   return x.value();
151
80.6k
   }
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
83.3k
   {
159
83.3k
   return std::make_shared<const Montgomery_Exponentation_State>(params, g, window_bits, const_time);
160
83.3k
   }
161
162
BigInt monty_execute(const Montgomery_Exponentation_State& precomputed_state,
163
                     const BigInt& k, size_t max_k_bits)
164
2.25k
   {
165
2.25k
   return precomputed_state.exponentiation(k, max_k_bits);
166
2.25k
   }
167
168
BigInt monty_execute_vartime(const Montgomery_Exponentation_State& precomputed_state,
169
                             const BigInt& k)
170
80.6k
   {
171
80.6k
   return precomputed_state.exponentiation_vartime(k);
172
80.6k
   }
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
86
   {
180
86
   if(z1.is_negative() || z2.is_negative())
181
0
      throw Invalid_Argument("multi_exponentiate exponents must be positive");
182
183
86
   const size_t z_bits = round_up(std::max(z1.bits(), z2.bits()), 2);
184
185
86
   secure_vector<word> ws;
186
187
86
   const Montgomery_Int one(params_p, params_p->R1(), false);
188
   //const Montgomery_Int one(params_p, 1);
189
190
86
   const Montgomery_Int x1(params_p, x_bn);
191
86
   const Montgomery_Int x2 = x1.square(ws);
192
86
   const Montgomery_Int x3 = x2.mul(x1, ws);
193
194
86
   const Montgomery_Int y1(params_p, y_bn);
195
86
   const Montgomery_Int y2 = y1.square(ws);
196
86
   const Montgomery_Int y3 = y2.mul(y1, ws);
197
198
86
   const Montgomery_Int y1x1 = y1.mul(x1, ws);
199
86
   const Montgomery_Int y1x2 = y1.mul(x2, ws);
200
86
   const Montgomery_Int y1x3 = y1.mul(x3, ws);
201
202
86
   const Montgomery_Int y2x1 = y2.mul(x1, ws);
203
86
   const Montgomery_Int y2x2 = y2.mul(x2, ws);
204
86
   const Montgomery_Int y2x3 = y2.mul(x3, ws);
205
206
86
   const Montgomery_Int y3x1 = y3.mul(x1, ws);
207
86
   const Montgomery_Int y3x2 = y3.mul(x2, ws);
208
86
   const Montgomery_Int y3x3 = y3.mul(x3, ws);
209
210
86
   const Montgomery_Int* M[16] = {
211
86
      &one,
212
86
      &x1,                    // 0001
213
86
      &x2,                    // 0010
214
86
      &x3,                    // 0011
215
86
      &y1,                    // 0100
216
86
      &y1x1,
217
86
      &y1x2,
218
86
      &y1x3,
219
86
      &y2,                    // 1000
220
86
      &y2x1,
221
86
      &y2x2,
222
86
      &y2x3,
223
86
      &y3,                    // 1100
224
86
      &y3x1,
225
86
      &y3x2,
226
86
      &y3x3
227
86
   };
228
229
86
   Montgomery_Int H = one;
230
231
42.0k
   for(size_t i = 0; i != z_bits; i += 2)
232
41.9k
      {
233
41.9k
      if(i > 0)
234
41.8k
         {
235
41.8k
         H.square_this(ws);
236
41.8k
         H.square_this(ws);
237
41.8k
         }
238
239
41.9k
      const uint32_t z1_b = z1.get_substring(z_bits - i - 2, 2);
240
41.9k
      const uint32_t z2_b = z2.get_substring(z_bits - i - 2, 2);
241
242
41.9k
      const uint32_t z12 = (4*z2_b) + z1_b;
243
244
41.9k
      H.mul_by(*M[z12], ws);
245
41.9k
      }
246
247
86
   return H.value();
248
86
   }
249
250
}
251