Botan 3.6.1
Crypto and TLS for C&
curve_gfp.cpp
Go to the documentation of this file.
1/*
2* Elliptic curves over GF(p) Montgomery Representation
3* (C) 2014,2015,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/curve_gfp.h>
10
11#include <botan/numthry.h>
12#include <botan/reducer.h>
13#include <botan/internal/curve_nistp.h>
14#include <botan/internal/monty.h>
15#include <botan/internal/mp_core.h>
16
17namespace Botan {
18
19namespace {
20
21class CurveGFp_Montgomery final : public CurveGFp_Repr {
22 public:
23 CurveGFp_Montgomery(const BigInt& p, const BigInt& a, const BigInt& b) :
24 m_p(p),
25 m_a(a),
26 m_b(b),
27 m_p_bits(m_p.bits()),
28 m_p_words(m_p.sig_words()),
29 m_p_dash(monty_inverse(m_p.word_at(0))) {
30 Modular_Reducer mod_p(m_p);
31
32 m_r.set_bit(m_p_words * BOTAN_MP_WORD_BITS);
33 m_r = mod_p.reduce(m_r);
34
35 m_r2 = mod_p.square(m_r);
36 m_r3 = mod_p.multiply(m_r, m_r2);
37 m_a_r = mod_p.multiply(m_r, m_a);
38 m_b_r = mod_p.multiply(m_r, m_b);
39
40 m_a_is_zero = m_a.is_zero();
41 m_a_is_minus_3 = (m_a + 3 == m_p);
42 }
43
44 bool a_is_zero() const override { return m_a_is_zero; }
45
46 bool a_is_minus_3() const override { return m_a_is_minus_3; }
47
48 const BigInt& get_a() const override { return m_a; }
49
50 const BigInt& get_b() const override { return m_b; }
51
52 const BigInt& get_p() const override { return m_p; }
53
54 const BigInt& get_a_rep() const override { return m_a_r; }
55
56 const BigInt& get_b_rep() const override { return m_b_r; }
57
58 const BigInt& get_1_rep() const override { return m_r; }
59
60 bool is_one(const BigInt& x) const override { return x == m_r; }
61
62 size_t get_p_bits() const override { return m_p_bits; }
63
64 size_t get_ws_size() const override { return 2 * m_p_words; }
65
66 BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const override;
67
68 void to_curve_rep(BigInt& x, secure_vector<word>& ws) const override;
69
70 void from_curve_rep(BigInt& x, secure_vector<word>& ws) const override;
71
72 void curve_mul_words(
73 BigInt& z, const word x_words[], size_t x_size, const BigInt& y, secure_vector<word>& ws) const override;
74
75 void curve_sqr_words(BigInt& z, const word x_words[], size_t x_size, secure_vector<word>& ws) const override;
76
77 private:
78 BigInt m_p;
79 BigInt m_a, m_b;
80 BigInt m_a_r, m_b_r;
81 size_t m_p_bits; // cache of m_p.bits()
82 size_t m_p_words; // cache of m_p.sig_words()
83
84 // Montgomery parameters
85 BigInt m_r, m_r2, m_r3;
86 word m_p_dash;
87
88 bool m_a_is_zero;
89 bool m_a_is_minus_3;
90};
91
92BigInt CurveGFp_Montgomery::invert_element(const BigInt& x, secure_vector<word>& ws) const {
93 // Should we use Montgomery inverse instead?
94 const BigInt inv = inverse_mod(x, m_p);
95 BigInt res;
96 curve_mul(res, inv, m_r3, ws);
97 return res;
98}
99
100void CurveGFp_Montgomery::to_curve_rep(BigInt& x, secure_vector<word>& ws) const {
101 const BigInt tx = x;
102 curve_mul(x, tx, m_r2, ws);
103}
104
105void CurveGFp_Montgomery::from_curve_rep(BigInt& z, secure_vector<word>& ws) const {
106 if(ws.size() < get_ws_size()) {
107 ws.resize(get_ws_size());
108 }
109
110 const size_t output_size = 2 * m_p_words;
111 if(z.size() < output_size) {
112 z.grow_to(output_size);
113 }
114
115 bigint_monty_redc(z.mutable_data(), m_p._data(), m_p_words, m_p_dash, ws.data(), ws.size());
116}
117
118void CurveGFp_Montgomery::curve_mul_words(
119 BigInt& z, const word x_w[], size_t x_size, const BigInt& y, secure_vector<word>& ws) const {
120 BOTAN_DEBUG_ASSERT(y.sig_words() <= m_p_words);
121
122 if(ws.size() < get_ws_size()) {
123 ws.resize(get_ws_size());
124 }
125
126 const size_t output_size = 2 * m_p_words;
127 if(z.size() < output_size) {
128 z.grow_to(output_size);
129 }
130
131 bigint_mul(z.mutable_data(),
132 z.size(),
133 x_w,
134 x_size,
135 std::min(m_p_words, x_size),
136 y._data(),
137 y.size(),
138 std::min(m_p_words, y.size()),
139 ws.data(),
140 ws.size());
141
142 bigint_monty_redc(z.mutable_data(), m_p._data(), m_p_words, m_p_dash, ws.data(), ws.size());
143}
144
145void CurveGFp_Montgomery::curve_sqr_words(BigInt& z, const word x[], size_t x_size, secure_vector<word>& ws) const {
146 if(ws.size() < get_ws_size()) {
147 ws.resize(get_ws_size());
148 }
149
150 const size_t output_size = 2 * m_p_words;
151 if(z.size() < output_size) {
152 z.grow_to(output_size);
153 }
154
155 bigint_sqr(z.mutable_data(), z.size(), x, x_size, std::min(m_p_words, x_size), ws.data(), ws.size());
156
157 bigint_monty_redc(z.mutable_data(), m_p._data(), m_p_words, m_p_dash, ws.data(), ws.size());
158}
159
160class CurveGFp_NIST : public CurveGFp_Repr {
161 public:
162 CurveGFp_NIST(size_t p_bits, const BigInt& a, const BigInt& b) :
163 m_1(1),
164 m_a(a),
165 m_b(b),
166 m_p_bits(p_bits),
167 m_p_words((p_bits + BOTAN_MP_WORD_BITS - 1) / BOTAN_MP_WORD_BITS) {
168 // All Solinas prime curves are assumed a == -3
169 }
170
171 bool a_is_zero() const override { return false; }
172
173 bool a_is_minus_3() const override { return true; }
174
175 const BigInt& get_a() const override { return m_a; }
176
177 const BigInt& get_b() const override { return m_b; }
178
179 const BigInt& get_1_rep() const override { return m_1; }
180
181 size_t get_p_bits() const override { return m_p_bits; }
182
183 size_t get_ws_size() const override { return 2 * m_p_words; }
184
185 const BigInt& get_a_rep() const override { return m_a; }
186
187 const BigInt& get_b_rep() const override { return m_b; }
188
189 bool is_one(const BigInt& x) const override { return x == 1; }
190
191 void to_curve_rep(BigInt& x, secure_vector<word>& ws) const override { redc_mod_p(x, ws); }
192
193 void from_curve_rep(BigInt& x, secure_vector<word>& ws) const override { redc_mod_p(x, ws); }
194
195 virtual void redc_mod_p(BigInt& z, secure_vector<word>& ws) const = 0;
196
197 BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const override;
198
199 void curve_mul_words(
200 BigInt& z, const word x_words[], size_t x_size, const BigInt& y, secure_vector<word>& ws) const override;
201
202 void curve_mul_tmp(BigInt& x, const BigInt& y, BigInt& tmp, secure_vector<word>& ws) const {
203 curve_mul(tmp, x, y, ws);
204 x.swap(tmp);
205 }
206
207 void curve_sqr_tmp(BigInt& x, BigInt& tmp, secure_vector<word>& ws) const {
208 curve_sqr(tmp, x, ws);
209 x.swap(tmp);
210 }
211
212 void curve_sqr_words(BigInt& z, const word x_words[], size_t x_size, secure_vector<word>& ws) const override;
213
214 private:
215 // Curve parameters
216 BigInt m_1;
217 BigInt m_a, m_b;
218 size_t m_p_bits; // cache of m_p.bits()
219 size_t m_p_words; // cache of m_p.sig_words()
220};
221
222BigInt CurveGFp_NIST::invert_element(const BigInt& x, secure_vector<word>& ws) const {
223 BOTAN_UNUSED(ws);
224 return inverse_mod(x, get_p());
225}
226
227void CurveGFp_NIST::curve_mul_words(
228 BigInt& z, const word x_w[], size_t x_size, const BigInt& y, secure_vector<word>& ws) const {
229 BOTAN_DEBUG_ASSERT(y.sig_words() <= m_p_words);
230
231 if(ws.size() < get_ws_size()) {
232 ws.resize(get_ws_size());
233 }
234
235 const size_t output_size = 2 * m_p_words;
236 if(z.size() < output_size) {
237 z.grow_to(output_size);
238 }
239
240 bigint_mul(z.mutable_data(),
241 z.size(),
242 x_w,
243 x_size,
244 std::min(m_p_words, x_size),
245 y._data(),
246 y.size(),
247 std::min(m_p_words, y.size()),
248 ws.data(),
249 ws.size());
250
251 this->redc_mod_p(z, ws);
252}
253
254void CurveGFp_NIST::curve_sqr_words(BigInt& z, const word x[], size_t x_size, secure_vector<word>& ws) const {
255 if(ws.size() < get_ws_size()) {
256 ws.resize(get_ws_size());
257 }
258
259 const size_t output_size = 2 * m_p_words;
260 if(z.size() < output_size) {
261 z.grow_to(output_size);
262 }
263
264 bigint_sqr(z.mutable_data(), output_size, x, x_size, std::min(m_p_words, x_size), ws.data(), ws.size());
265
266 this->redc_mod_p(z, ws);
267}
268
269/**
270* The NIST P-192 curve
271*/
272class CurveGFp_P192 final : public CurveGFp_NIST {
273 public:
274 CurveGFp_P192(const BigInt& a, const BigInt& b) : CurveGFp_NIST(192, a, b) {}
275
276 const BigInt& get_p() const override { return prime_p192(); }
277
278 private:
279 void redc_mod_p(BigInt& x, secure_vector<word>& ws) const override { redc_p192(x, ws); }
280};
281
282/**
283* The NIST P-224 curve
284*/
285class CurveGFp_P224 final : public CurveGFp_NIST {
286 public:
287 CurveGFp_P224(const BigInt& a, const BigInt& b) : CurveGFp_NIST(224, a, b) {}
288
289 const BigInt& get_p() const override { return prime_p224(); }
290
291 private:
292 void redc_mod_p(BigInt& x, secure_vector<word>& ws) const override { redc_p224(x, ws); }
293};
294
295/**
296* The NIST P-256 curve
297*/
298class CurveGFp_P256 final : public CurveGFp_NIST {
299 public:
300 CurveGFp_P256(const BigInt& a, const BigInt& b) : CurveGFp_NIST(256, a, b) {}
301
302 const BigInt& get_p() const override { return prime_p256(); }
303
304 private:
305 void redc_mod_p(BigInt& x, secure_vector<word>& ws) const override { redc_p256(x, ws); }
306
307 BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const override;
308};
309
310BigInt CurveGFp_P256::invert_element(const BigInt& x, secure_vector<word>& ws) const {
311 BigInt r, p2, p4, p8, p16, p32, tmp;
312
313 curve_sqr(r, x, ws);
314
315 curve_mul(p2, r, x, ws);
316 curve_sqr(r, p2, ws);
317 curve_sqr_tmp(r, tmp, ws);
318
319 curve_mul(p4, r, p2, ws);
320
321 curve_sqr(r, p4, ws);
322 for(size_t i = 0; i != 3; ++i) {
323 curve_sqr_tmp(r, tmp, ws);
324 }
325 curve_mul(p8, r, p4, ws);
326
327 curve_sqr(r, p8, ws);
328 for(size_t i = 0; i != 7; ++i) {
329 curve_sqr_tmp(r, tmp, ws);
330 }
331 curve_mul(p16, r, p8, ws);
332
333 curve_sqr(r, p16, ws);
334 for(size_t i = 0; i != 15; ++i) {
335 curve_sqr_tmp(r, tmp, ws);
336 }
337 curve_mul(p32, r, p16, ws);
338
339 curve_sqr(r, p32, ws);
340 for(size_t i = 0; i != 31; ++i) {
341 curve_sqr_tmp(r, tmp, ws);
342 }
343 curve_mul_tmp(r, x, tmp, ws);
344
345 for(size_t i = 0; i != 32 * 4; ++i) {
346 curve_sqr_tmp(r, tmp, ws);
347 }
348 curve_mul_tmp(r, p32, tmp, ws);
349
350 for(size_t i = 0; i != 32; ++i) {
351 curve_sqr_tmp(r, tmp, ws);
352 }
353 curve_mul_tmp(r, p32, tmp, ws);
354
355 for(size_t i = 0; i != 16; ++i) {
356 curve_sqr_tmp(r, tmp, ws);
357 }
358 curve_mul_tmp(r, p16, tmp, ws);
359 for(size_t i = 0; i != 8; ++i) {
360 curve_sqr_tmp(r, tmp, ws);
361 }
362 curve_mul_tmp(r, p8, tmp, ws);
363
364 for(size_t i = 0; i != 4; ++i) {
365 curve_sqr_tmp(r, tmp, ws);
366 }
367 curve_mul_tmp(r, p4, tmp, ws);
368
369 for(size_t i = 0; i != 2; ++i) {
370 curve_sqr_tmp(r, tmp, ws);
371 }
372 curve_mul_tmp(r, p2, tmp, ws);
373
374 for(size_t i = 0; i != 2; ++i) {
375 curve_sqr_tmp(r, tmp, ws);
376 }
377 curve_mul_tmp(r, x, tmp, ws);
378
379 return r;
380}
381
382/**
383* The NIST P-384 curve
384*/
385class CurveGFp_P384 final : public CurveGFp_NIST {
386 public:
387 CurveGFp_P384(const BigInt& a, const BigInt& b) : CurveGFp_NIST(384, a, b) {}
388
389 const BigInt& get_p() const override { return prime_p384(); }
390
391 private:
392 void redc_mod_p(BigInt& x, secure_vector<word>& ws) const override { redc_p384(x, ws); }
393
394 BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const override;
395};
396
397BigInt CurveGFp_P384::invert_element(const BigInt& x, secure_vector<word>& ws) const {
398 // From https://briansmith.org/ecc-inversion-addition-chains-01
399
400 BigInt r, x2, x3, x15, x30, tmp, rl;
401
402 r = x;
403 curve_sqr_tmp(r, tmp, ws);
404 curve_mul_tmp(r, x, tmp, ws);
405 x2 = r;
406
407 curve_sqr_tmp(r, tmp, ws);
408 curve_mul_tmp(r, x, tmp, ws);
409
410 x3 = r;
411
412 for(size_t i = 0; i != 3; ++i) {
413 curve_sqr_tmp(r, tmp, ws);
414 }
415 curve_mul_tmp(r, x3, tmp, ws);
416
417 rl = r;
418 for(size_t i = 0; i != 6; ++i) {
419 curve_sqr_tmp(r, tmp, ws);
420 }
421 curve_mul_tmp(r, rl, tmp, ws);
422
423 for(size_t i = 0; i != 3; ++i) {
424 curve_sqr_tmp(r, tmp, ws);
425 }
426 curve_mul_tmp(r, x3, tmp, ws);
427
428 x15 = r;
429 for(size_t i = 0; i != 15; ++i) {
430 curve_sqr_tmp(r, tmp, ws);
431 }
432 curve_mul_tmp(r, x15, tmp, ws);
433
434 x30 = r;
435 for(size_t i = 0; i != 30; ++i) {
436 curve_sqr_tmp(r, tmp, ws);
437 }
438 curve_mul_tmp(r, x30, tmp, ws);
439
440 rl = r;
441 for(size_t i = 0; i != 60; ++i) {
442 curve_sqr_tmp(r, tmp, ws);
443 }
444 curve_mul_tmp(r, rl, tmp, ws);
445
446 rl = r;
447 for(size_t i = 0; i != 120; ++i) {
448 curve_sqr_tmp(r, tmp, ws);
449 }
450 curve_mul_tmp(r, rl, tmp, ws);
451
452 for(size_t i = 0; i != 15; ++i) {
453 curve_sqr_tmp(r, tmp, ws);
454 }
455 curve_mul_tmp(r, x15, tmp, ws);
456
457 for(size_t i = 0; i != 31; ++i) {
458 curve_sqr_tmp(r, tmp, ws);
459 }
460 curve_mul_tmp(r, x30, tmp, ws);
461
462 for(size_t i = 0; i != 2; ++i) {
463 curve_sqr_tmp(r, tmp, ws);
464 }
465 curve_mul_tmp(r, x2, tmp, ws);
466
467 for(size_t i = 0; i != 94; ++i) {
468 curve_sqr_tmp(r, tmp, ws);
469 }
470 curve_mul_tmp(r, x30, tmp, ws);
471
472 for(size_t i = 0; i != 2; ++i) {
473 curve_sqr_tmp(r, tmp, ws);
474 }
475
476 curve_mul_tmp(r, x, tmp, ws);
477
478 return r;
479}
480
481/**
482* The NIST P-521 curve
483*/
484class CurveGFp_P521 final : public CurveGFp_NIST {
485 public:
486 CurveGFp_P521(const BigInt& a, const BigInt& b) : CurveGFp_NIST(521, a, b) {}
487
488 const BigInt& get_p() const override { return prime_p521(); }
489
490 private:
491 void redc_mod_p(BigInt& x, secure_vector<word>& ws) const override { redc_p521(x, ws); }
492
493 BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const override;
494};
495
496BigInt CurveGFp_P521::invert_element(const BigInt& x, secure_vector<word>& ws) const {
497 // Addition chain from https://eprint.iacr.org/2014/852.pdf section
498
499 BigInt r;
500 BigInt rl;
501 BigInt a7;
502 BigInt tmp;
503
504 curve_sqr(r, x, ws);
505 curve_mul_tmp(r, x, tmp, ws);
506
507 curve_sqr_tmp(r, tmp, ws);
508 curve_mul_tmp(r, x, tmp, ws);
509
510 rl = r;
511
512 for(size_t i = 0; i != 3; ++i) {
513 curve_sqr_tmp(r, tmp, ws);
514 }
515 curve_mul_tmp(r, rl, tmp, ws);
516
517 curve_sqr_tmp(r, tmp, ws);
518 curve_mul_tmp(r, x, tmp, ws);
519 a7 = r; // need this value later
520
521 curve_sqr_tmp(r, tmp, ws);
522 curve_mul_tmp(r, x, tmp, ws);
523
524 rl = r;
525 for(size_t i = 0; i != 8; ++i) {
526 curve_sqr_tmp(r, tmp, ws);
527 }
528 curve_mul_tmp(r, rl, tmp, ws);
529
530 rl = r;
531 for(size_t i = 0; i != 16; ++i) {
532 curve_sqr_tmp(r, tmp, ws);
533 }
534 curve_mul_tmp(r, rl, tmp, ws);
535
536 rl = r;
537 for(size_t i = 0; i != 32; ++i) {
538 curve_sqr_tmp(r, tmp, ws);
539 }
540 curve_mul_tmp(r, rl, tmp, ws);
541
542 rl = r;
543 for(size_t i = 0; i != 64; ++i) {
544 curve_sqr_tmp(r, tmp, ws);
545 }
546 curve_mul_tmp(r, rl, tmp, ws);
547
548 rl = r;
549 for(size_t i = 0; i != 128; ++i) {
550 curve_sqr_tmp(r, tmp, ws);
551 }
552 curve_mul_tmp(r, rl, tmp, ws);
553
554 rl = r;
555 for(size_t i = 0; i != 256; ++i) {
556 curve_sqr_tmp(r, tmp, ws);
557 }
558 curve_mul_tmp(r, rl, tmp, ws);
559
560 for(size_t i = 0; i != 7; ++i) {
561 curve_sqr_tmp(r, tmp, ws);
562 }
563 curve_mul_tmp(r, a7, tmp, ws);
564
565 for(size_t i = 0; i != 2; ++i) {
566 curve_sqr_tmp(r, tmp, ws);
567 }
568 curve_mul_tmp(r, x, tmp, ws);
569
570 return r;
571}
572
573} // namespace
574
575std::shared_ptr<CurveGFp_Repr> CurveGFp::choose_repr(const BigInt& p, const BigInt& a, const BigInt& b) {
576 if(p == prime_p192() && p == a + 3) {
577 return std::make_shared<CurveGFp_P192>(a, b);
578 }
579 if(p == prime_p224() && p == a + 3) {
580 return std::make_shared<CurveGFp_P224>(a, b);
581 }
582 if(p == prime_p256() && p == a + 3) {
583 return std::make_shared<CurveGFp_P256>(a, b);
584 }
585 if(p == prime_p384() && p == a + 3) {
586 return std::make_shared<CurveGFp_P384>(a, b);
587 }
588 if(p == prime_p521() && p == a + 3) {
589 return std::make_shared<CurveGFp_P521>(a, b);
590 }
591
592 return std::make_shared<CurveGFp_Montgomery>(p, a, b);
593}
594
595} // namespace Botan
#define BOTAN_UNUSED
Definition assert.h:118
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:98
const word * _data() const
Definition bigint.h:936
int(* final)(unsigned char *, CTX *)
#define BOTAN_MP_WORD_BITS
Definition build.h:71
BOTAN_TEST_API void redc_p521(BigInt &x, secure_vector< word > &ws)
void bigint_monty_redc(word z[], const word p[], size_t p_size, word p_dash, word ws[], size_t ws_size)
Definition mp_core.h:1047
BOTAN_TEST_API void redc_p192(BigInt &x, secure_vector< word > &ws)
BOTAN_TEST_API void redc_p256(BigInt &x, secure_vector< word > &ws)
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:326
constexpr auto monty_inverse(W a) -> W
Definition mp_core.h:832
BOTAN_TEST_API void redc_p224(BigInt &x, secure_vector< word > &ws)
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:282
BOTAN_TEST_API const BigInt & prime_p384()
BOTAN_TEST_API const BigInt & prime_p224()
BOTAN_TEST_API void redc_p384(BigInt &x, secure_vector< word > &ws)
const SIMD_8x32 & b
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
BOTAN_TEST_API const BigInt & prime_p256()
BOTAN_TEST_API const BigInt & prime_p192()
BOTAN_TEST_API const BigInt & prime_p521()
BigInt inverse_mod(const BigInt &n, const BigInt &mod)
Definition mod_inv.cpp:179