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