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