Coverage Report

Created: 2023-06-07 07:00

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