Botan 3.9.0
Crypto and TLS for C&
monty.cpp
Go to the documentation of this file.
1/*
2* (C) 2018,2024,2025 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/internal/monty.h>
8
9#include <botan/numthry.h>
10#include <botan/internal/barrett.h>
11#include <botan/internal/mp_core.h>
12#include <array>
13
14namespace Botan {
15
16namespace {
17
18// If the modulus is at most this many words, then use the stack instead
19// of a heap variable for some temporary values
20constexpr size_t MontgomeryUseStackLimit = 32;
21
22} // namespace
23
24Montgomery_Params::Data::Data(const BigInt& p, const Barrett_Reduction& mod_p) {
25 if(p.is_even() || p < 3) {
26 throw Invalid_Argument("Montgomery_Params invalid modulus");
27 }
28
29 m_p = p;
30 m_p_words = m_p.sig_words();
31 m_p_dash = monty_inverse(m_p.word_at(0));
32
33 const BigInt r = BigInt::power_of_2(m_p_words * WordInfo<word>::bits);
34
35 m_r1 = mod_p.reduce(r);
36 m_r2 = mod_p.square(m_r1);
37 m_r3 = mod_p.multiply(m_r1, m_r2);
38
39 // Barrett should be at least zero prefixing up to modulus size
40 BOTAN_ASSERT_NOMSG(m_r1.size() >= m_p_words);
41 BOTAN_ASSERT_NOMSG(m_r2.size() >= m_p_words);
42 BOTAN_ASSERT_NOMSG(m_r3.size() >= m_p_words);
43}
44
46 m_data(std::make_shared<Data>(p, mod_p)) {}
47
50
52 if(this->m_data == other.m_data) {
53 return true;
54 }
55
56 return (this->m_data->p() == other.m_data->p());
57}
58
60 const size_t p_size = this->p_words();
61
62 if(ws.size() < p_size) {
63 ws.resize(p_size);
64 }
65
66 BigInt z = x;
67 z.grow_to(2 * p_size);
68
69 bigint_monty_redc_inplace(z.mutable_data(), this->p()._data(), p_size, this->p_dash(), ws.data(), ws.size());
70
71 return z;
72}
73
75 const size_t p_size = this->p_words();
76 BigInt z = BigInt::with_capacity(2 * p_size);
77 this->mul(z, x, y, ws);
78 return z;
79}
80
81void Montgomery_Params::mul(BigInt& z, const BigInt& x, const BigInt& y, secure_vector<word>& ws) const {
82 const size_t p_size = this->p_words();
83
84 if(ws.size() < 2 * p_size) {
85 ws.resize(2 * p_size);
86 }
87
88 BOTAN_DEBUG_ASSERT(x.sig_words() <= p_size);
89 BOTAN_DEBUG_ASSERT(y.sig_words() <= p_size);
90
91 if(z.size() < 2 * p_size) {
92 z.grow_to(2 * p_size);
93 }
94
96 z.size(),
97 x._data(),
98 x.size(),
99 std::min(p_size, x.size()),
100 y._data(),
101 y.size(),
102 std::min(p_size, y.size()),
103 ws.data(),
104 ws.size());
105
106 bigint_monty_redc_inplace(z.mutable_data(), this->p()._data(), p_size, this->p_dash(), ws.data(), ws.size());
107}
108
109void Montgomery_Params::mul(BigInt& z, const BigInt& x, std::span<const word> y, secure_vector<word>& ws) const {
110 const size_t p_size = this->p_words();
111
112 if(ws.size() < 2 * p_size) {
113 ws.resize(2 * p_size);
114 }
115 if(z.size() < 2 * p_size) {
116 z.grow_to(2 * p_size);
117 }
118
119 BOTAN_DEBUG_ASSERT(x.sig_words() <= p_size);
120
122 z.size(),
123 x._data(),
124 x.size(),
125 std::min(p_size, x.size()),
126 y.data(),
127 y.size(),
128 std::min(p_size, y.size()),
129 ws.data(),
130 ws.size());
131
132 bigint_monty_redc_inplace(z.mutable_data(), this->p()._data(), p_size, this->p_dash(), ws.data(), ws.size());
133}
134
136 const size_t p_size = this->p_words();
137
138 if(ws.size() < 4 * p_size) {
139 ws.resize(4 * p_size);
140 }
141
142 word* z_data = ws.data();
143 word* ws_data = &ws[2 * p_size];
144
145 BOTAN_DEBUG_ASSERT(x.sig_words() <= p_size);
146
147 bigint_mul(z_data,
148 2 * p_size,
149 x._data(),
150 x.size(),
151 std::min(p_size, x.size()),
152 y._data(),
153 y.size(),
154 std::min(p_size, y.size()),
155 ws_data,
156 2 * p_size);
157
158 bigint_monty_redc_inplace(z_data, this->p()._data(), p_size, this->p_dash(), ws_data, 2 * p_size);
159
160 if(x.size() < 2 * p_size) {
161 x.grow_to(2 * p_size);
162 }
163 copy_mem(x.mutable_data(), z_data, 2 * p_size);
164}
165
167 BOTAN_DEBUG_ASSERT(x.sig_words() <= this->p_words());
168 return this->sqr(std::span{x._data(), x.size()}, ws);
169}
170
171BigInt Montgomery_Params::sqr(std::span<const word> x, secure_vector<word>& ws) const {
172 const size_t p_size = this->p_words();
173 BigInt z = BigInt::with_capacity(2 * p_size);
174 this->sqr(z, x, ws);
175 return z;
176}
177
179 this->sqr(z, std::span{x._data(), x.size()}, ws);
180}
181
182void Montgomery_Params::sqr(BigInt& z, std::span<const word> x, secure_vector<word>& ws) const {
183 const size_t p_size = this->p_words();
184
185 if(ws.size() < 2 * p_size) {
186 ws.resize(2 * p_size);
187 }
188
189 if(z.size() < 2 * p_size) {
190 z.grow_to(2 * p_size);
191 }
192
193 bigint_sqr(z.mutable_data(), z.size(), x.data(), x.size(), std::min(p_size, x.size()), ws.data(), ws.size());
194
195 bigint_monty_redc_inplace(z.mutable_data(), this->p()._data(), p_size, this->p_dash(), ws.data(), ws.size());
196}
197
199 m_params(params), m_v(std::move(words)) {
200 BOTAN_ASSERT_NOMSG(m_v.size() == m_params.p_words());
201}
202
204 return Montgomery_Int(params, params.R1(), false);
205}
206
209 auto redc_x = params.mul(params.redc(x, ws), params.R3(), ws);
210 return Montgomery_Int(params, redc_x, false);
211}
212
213Montgomery_Int::Montgomery_Int(const Montgomery_Params& params, const BigInt& v, bool redc_needed) :
214 m_params(params), m_v(m_params.p_words()) {
215 BOTAN_ASSERT_NOMSG(v < m_params.p());
216
217 const size_t p_size = m_params.p_words();
218
219 auto v_span = v._as_span();
220
221 if(v_span.size() > p_size) {
222 // Safe to truncate the span since we already checked v < p
223 v_span = v_span.first(p_size);
224 }
225
226 BOTAN_ASSERT_NOMSG(m_v.size() >= v_span.size());
227
228 copy_mem(std::span{m_v}.first(v_span.size()), v_span);
229
230 if(redc_needed) {
232 this->mul_by(m_params.R2()._as_span().first(p_size), ws);
233 }
234}
235
236Montgomery_Int::Montgomery_Int(const Montgomery_Params& params, std::span<const word> words) :
237 m_params(params), m_v(words.begin(), words.end()) {
238 BOTAN_ARG_CHECK(m_v.size() == m_params.p_words(), "Invalid input span");
239}
240
241std::vector<uint8_t> Montgomery_Int::serialize() const {
242 return value().serialize();
243}
244
246 secure_vector<word> ws(m_params.p_words());
247
248 secure_vector<word> z = m_v;
249 z.resize(2 * m_params.p_words()); // zero extend
250
252 z.data(), m_params.p()._data(), m_params.p_words(), m_params.p_dash(), ws.data(), ws.size());
253
254 return BigInt::_from_words(z);
255}
256
258 BOTAN_STATE_CHECK(other.m_params == m_params);
259
260 const size_t p_size = m_params.p_words();
261 BOTAN_ASSERT_NOMSG(m_v.size() == p_size && other.m_v.size() == p_size);
262
263 secure_vector<word> z(2 * p_size);
264
265 word* r = std::span{z}.first(p_size).data();
266 word* t = std::span{z}.last(p_size).data();
267
268 // t = this + other
269 const word carry = bigint_add3(t, m_v.data(), p_size, other.m_v.data(), p_size);
270
271 // Conditionally subtract r = t - p
272 bigint_monty_maybe_sub(p_size, r, carry, t, m_params.p()._data());
273
274 z.resize(p_size); // truncate leaving only r
275 return Montgomery_Int(m_params, std::move(z));
276}
277
279 BOTAN_STATE_CHECK(other.m_params == m_params);
280
281 const size_t p_size = m_params.p_words();
282 BOTAN_ASSERT_NOMSG(m_v.size() == p_size && other.m_v.size() == p_size);
283
284 secure_vector<word> t(p_size);
285 const word borrow = bigint_sub3(t.data(), m_v.data(), p_size, other.m_v.data(), p_size);
286
287 bigint_cnd_add(borrow, t.data(), m_params.p()._data(), p_size);
288
289 return Montgomery_Int(m_params, std::move(t));
290}
291
293 BOTAN_STATE_CHECK(other.m_params == m_params);
294
295 const size_t p_size = m_params.p_words();
296 BOTAN_ASSERT_NOMSG(m_v.size() == p_size && other.m_v.size() == p_size);
297
298 if(ws.size() < 2 * p_size) {
299 ws.resize(2 * p_size);
300 }
301
302 secure_vector<word> z(2 * p_size);
303
304 bigint_mul(z.data(), z.size(), m_v.data(), p_size, p_size, other.m_v.data(), p_size, p_size, ws.data(), ws.size());
305
306 bigint_monty_redc_inplace(z.data(), m_params.p()._data(), p_size, m_params.p_dash(), ws.data(), ws.size());
307 z.resize(p_size); // truncate off high zero words
308
309 return Montgomery_Int(m_params, std::move(z));
310}
311
313 BOTAN_STATE_CHECK(other.m_params == m_params);
314 return this->mul_by(std::span{other.m_v}, ws);
315}
316
318 const size_t p_size = m_params.p_words();
319 BOTAN_ASSERT_NOMSG(m_v.size() == p_size && other.size() == p_size);
320
321 if(ws.size() < 2 * p_size) {
322 ws.resize(2 * p_size);
323 }
324
325 auto do_mul_by = [&](std::span<word> z) {
326 bigint_mul(z.data(), z.size(), m_v.data(), p_size, p_size, other.data(), p_size, p_size, ws.data(), ws.size());
327
328 bigint_monty_redc_inplace(z.data(), m_params.p()._data(), p_size, m_params.p_dash(), ws.data(), ws.size());
329
330 copy_mem(m_v, z.first(p_size));
331 };
332
333 if(p_size <= MontgomeryUseStackLimit) {
334 std::array<word, 2 * MontgomeryUseStackLimit> z{};
335 do_mul_by(z);
336 } else {
337 secure_vector<word> z(2 * p_size);
338 do_mul_by(z);
339 }
340
341 return (*this);
342}
343
345 const size_t p_size = m_params.p_words();
346 BOTAN_ASSERT_NOMSG(m_v.size() == p_size);
347
348 if(ws.size() < 2 * p_size) {
349 ws.resize(2 * p_size);
350 }
351
352 auto do_sqr_n = [&](std::span<word> z) {
353 for(size_t i = 0; i != n; ++i) {
354 bigint_sqr(z.data(), 2 * p_size, m_v.data(), p_size, p_size, ws.data(), ws.size());
355
356 bigint_monty_redc_inplace(z.data(), m_params.p()._data(), p_size, m_params.p_dash(), ws.data(), ws.size());
357
358 copy_mem(m_v, std::span{z}.first(p_size));
359 }
360 };
361
362 if(p_size <= MontgomeryUseStackLimit) {
363 std::array<word, 2 * MontgomeryUseStackLimit> z{};
364 do_sqr_n(z);
365 } else {
366 secure_vector<word> z(2 * p_size);
367 do_sqr_n(z);
368 }
369
370 return (*this);
371}
372
374 auto z = (*this);
375 z.square_this_n_times(ws, 1);
376 return z;
377}
378
379} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:129
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
size_t sig_words() const
Definition bigint.h:615
word * mutable_data()
Definition bigint.h:640
size_t size() const
Definition bigint.h:609
void grow_to(size_t n) const
Definition bigint.h:666
static BigInt _from_words(secure_vector< word > &words)
Definition bigint.h:955
static BigInt power_of_2(size_t n)
Definition bigint.h:820
const word * _data() const
Definition bigint.h:936
T serialize(size_t len) const
Definition bigint.h:711
static BigInt with_capacity(size_t n)
Definition bigint.cpp:50
std::span< const word > _as_span() const
Definition bigint.h:926
static Montgomery_Int from_wide_int(const Montgomery_Params &params, const BigInt &x)
Definition monty.cpp:207
Montgomery_Int square(secure_vector< word > &ws) const
Definition monty.cpp:373
static Montgomery_Int one(const Montgomery_Params &params)
Definition monty.cpp:203
Montgomery_Int operator-(const Montgomery_Int &other) const
Definition monty.cpp:278
Montgomery_Int(const Montgomery_Params &params)
Definition monty.h:108
Montgomery_Int operator+(const Montgomery_Int &other) const
Definition monty.cpp:257
BigInt value() const
Definition monty.cpp:245
Montgomery_Int & square_this_n_times(secure_vector< word > &ws, size_t n)
Definition monty.cpp:344
Montgomery_Int mul(const Montgomery_Int &other, secure_vector< word > &ws) const
Definition monty.cpp:292
Montgomery_Int & mul_by(const Montgomery_Int &other, secure_vector< word > &ws)
Definition monty.cpp:312
std::vector< uint8_t > serialize() const
Definition monty.cpp:241
BigInt redc(const BigInt &x, secure_vector< word > &ws) const
Definition monty.cpp:59
BigInt sqr(const BigInt &x, secure_vector< word > &ws) const
Definition monty.cpp:166
void mul(BigInt &z, const BigInt &x, const BigInt &y, secure_vector< word > &ws) const
Definition monty.cpp:81
size_t p_words() const
Definition monty.h:51
bool operator==(const Montgomery_Params &other) const
Definition monty.cpp:51
void mul_by(BigInt &x, const BigInt &y, secure_vector< word > &ws) const
Definition monty.cpp:135
Montgomery_Params(const BigInt &p, const Barrett_Reduction &mod_p)
Definition monty.cpp:45
const BigInt & R3() const
Definition monty.h:47
const BigInt & R1() const
Definition monty.h:43
word p_dash() const
Definition monty.h:49
const BigInt & p() const
Definition monty.h:41
constexpr auto bigint_add3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:122
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:145
void bigint_sqr(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, word workspace[], size_t ws_size)
Definition mp_karat.cpp:327
constexpr auto bigint_sub3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:194
constexpr auto monty_inverse(W a) -> W
Definition mp_core.h:585
void bigint_mul(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, const word y[], size_t y_size, size_t y_sw, word workspace[], size_t ws_size)
Definition mp_karat.cpp:283
void bigint_monty_redc_inplace(word z[], const word p[], size_t p_size, word p_dash, word ws[], size_t ws_size)
Definition mp_core.h:829
constexpr W bigint_cnd_add(W cnd, W x[], const W y[], size_t size)
Definition mp_core.h:47
constexpr void bigint_monty_maybe_sub(size_t N, W z[], W x0, const W x[], const W p[])
Definition mp_core.h:227
void carry(int64_t &h0, int64_t &h1)
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:69
std::conditional_t< HasNative64BitRegisters, std::uint64_t, uint32_t > word
Definition types.h:119