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