Botan 3.5.0
Crypto and TLS for C&
ec_point.cpp
Go to the documentation of this file.
1/*
2* Point arithmetic on elliptic curves over GF(p)
3*
4* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke
5* 2008-2011,2012,2014,2015,2018 Jack Lloyd
6*
7* Botan is released under the Simplified BSD License (see license.txt)
8*/
9
10#include <botan/ec_point.h>
11
12#include <botan/numthry.h>
13#include <botan/rng.h>
14#include <botan/internal/ct_utils.h>
15#include <botan/internal/stl_util.h>
16
17namespace Botan {
18
19EC_Point::EC_Point(const CurveGFp& curve) : m_curve(curve), m_coord_x(0), m_coord_y(curve.get_1_rep()), m_coord_z(0) {
20 // Assumes Montgomery rep of zero is zero
21}
22
23EC_Point::EC_Point(const CurveGFp& curve, const BigInt& x, const BigInt& y) :
24 m_curve(curve), m_coord_x(x), m_coord_y(y), m_coord_z(m_curve.get_1_rep()) {
25 if(x < 0 || x >= curve.get_p()) {
26 throw Invalid_Argument("Invalid EC_Point affine x");
27 }
28 if(y < 0 || y >= curve.get_p()) {
29 throw Invalid_Argument("Invalid EC_Point affine y");
30 }
31
32 secure_vector<word> monty_ws(m_curve.get_ws_size());
33 m_curve.to_rep(m_coord_x, monty_ws);
34 m_curve.to_rep(m_coord_y, monty_ws);
35}
36
38 secure_vector<word> ws(m_curve.get_ws_size());
39 randomize_repr(rng, ws);
40}
41
43 const BigInt mask = BigInt::random_integer(rng, 2, m_curve.get_p());
44
45 /*
46 * No reason to convert this to Montgomery representation first,
47 * just pretend the random mask was chosen as Redc(mask) and the
48 * random mask we generated above is in the Montgomery
49 * representation.
50 * //m_curve.to_rep(mask, ws);
51 */
52 const BigInt mask2 = m_curve.sqr_to_tmp(mask, ws);
53 const BigInt mask3 = m_curve.mul_to_tmp(mask2, mask, ws);
54
55 m_coord_x = m_curve.mul_to_tmp(m_coord_x, mask2, ws);
56 m_coord_y = m_curve.mul_to_tmp(m_coord_y, mask3, ws);
57 m_coord_z = m_curve.mul_to_tmp(m_coord_z, mask, ws);
58}
59
60namespace {
61
62inline void resize_ws(std::vector<BigInt>& ws_bn, size_t cap_size) {
63 BOTAN_ASSERT(ws_bn.size() >= EC_Point::WORKSPACE_SIZE, "Expected size for EC_Point workspace");
64
65 for(auto& ws : ws_bn) {
66 if(ws.size() < cap_size) {
67 ws.get_word_vector().resize(cap_size);
68 }
69 }
70}
71
72} // namespace
73
75 const word x_words[], size_t x_size, const word y_words[], size_t y_size, std::vector<BigInt>& ws_bn) {
76 if((CT::all_zeros(x_words, x_size) & CT::all_zeros(y_words, y_size)).as_bool()) {
77 return;
78 }
79
80 if(is_zero()) {
81 m_coord_x.set_words(x_words, x_size);
82 m_coord_y.set_words(y_words, y_size);
83 m_coord_z = m_curve.get_1_rep();
84 return;
85 }
86
87 resize_ws(ws_bn, m_curve.get_ws_size());
88
89 secure_vector<word>& ws = ws_bn[0].get_word_vector();
90 secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
91
92 BigInt& T0 = ws_bn[2];
93 BigInt& T1 = ws_bn[3];
94 BigInt& T2 = ws_bn[4];
95 BigInt& T3 = ws_bn[5];
96 BigInt& T4 = ws_bn[6];
97
98 /*
99 https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
100 simplified with Z2 = 1
101 */
102
103 const BigInt& p = m_curve.get_p();
104
105 m_curve.sqr(T3, m_coord_z, ws); // z1^2
106 m_curve.mul(T4, x_words, x_size, T3, ws); // x2*z1^2
107
108 m_curve.mul(T2, m_coord_z, T3, ws); // z1^3
109 m_curve.mul(T0, y_words, y_size, T2, ws); // y2*z1^3
110
111 T4.mod_sub(m_coord_x, p, sub_ws); // x2*z1^2 - x1*z2^2
112
113 T0.mod_sub(m_coord_y, p, sub_ws);
114
115 if(T4.is_zero()) {
116 if(T0.is_zero()) {
117 mult2(ws_bn);
118 return;
119 }
120
121 // setting to zero:
122 m_coord_x.clear();
123 m_coord_y = m_curve.get_1_rep();
124 m_coord_z.clear();
125 return;
126 }
127
128 m_curve.sqr(T2, T4, ws);
129
130 m_curve.mul(T3, m_coord_x, T2, ws);
131
132 m_curve.mul(T1, T2, T4, ws);
133
134 m_curve.sqr(m_coord_x, T0, ws);
135 m_coord_x.mod_sub(T1, p, sub_ws);
136
137 m_coord_x.mod_sub(T3, p, sub_ws);
138 m_coord_x.mod_sub(T3, p, sub_ws);
139
140 T3.mod_sub(m_coord_x, p, sub_ws);
141
142 m_curve.mul(T2, T0, T3, ws);
143 m_curve.mul(T0, m_coord_y, T1, ws);
144 T2.mod_sub(T0, p, sub_ws);
145 m_coord_y.swap(T2);
146
147 m_curve.mul(T0, m_coord_z, T4, ws);
148 m_coord_z.swap(T0);
149}
150
151void EC_Point::add(const word x_words[],
152 size_t x_size,
153 const word y_words[],
154 size_t y_size,
155 const word z_words[],
156 size_t z_size,
157 std::vector<BigInt>& ws_bn) {
158 if((CT::all_zeros(x_words, x_size) & CT::all_zeros(z_words, z_size)).as_bool()) {
159 return;
160 }
161
162 if(is_zero()) {
163 m_coord_x.set_words(x_words, x_size);
164 m_coord_y.set_words(y_words, y_size);
165 m_coord_z.set_words(z_words, z_size);
166 return;
167 }
168
169 resize_ws(ws_bn, m_curve.get_ws_size());
170
171 secure_vector<word>& ws = ws_bn[0].get_word_vector();
172 secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
173
174 BigInt& T0 = ws_bn[2];
175 BigInt& T1 = ws_bn[3];
176 BigInt& T2 = ws_bn[4];
177 BigInt& T3 = ws_bn[5];
178 BigInt& T4 = ws_bn[6];
179 BigInt& T5 = ws_bn[7];
180
181 /*
182 https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
183 */
184
185 const BigInt& p = m_curve.get_p();
186
187 m_curve.sqr(T0, z_words, z_size, ws); // z2^2
188 m_curve.mul(T1, m_coord_x, T0, ws); // x1*z2^2
189 m_curve.mul(T3, z_words, z_size, T0, ws); // z2^3
190 m_curve.mul(T2, m_coord_y, T3, ws); // y1*z2^3
191
192 m_curve.sqr(T3, m_coord_z, ws); // z1^2
193 m_curve.mul(T4, x_words, x_size, T3, ws); // x2*z1^2
194
195 m_curve.mul(T5, m_coord_z, T3, ws); // z1^3
196 m_curve.mul(T0, y_words, y_size, T5, ws); // y2*z1^3
197
198 T4.mod_sub(T1, p, sub_ws); // x2*z1^2 - x1*z2^2
199
200 T0.mod_sub(T2, p, sub_ws);
201
202 if(T4.is_zero()) {
203 if(T0.is_zero()) {
204 mult2(ws_bn);
205 return;
206 }
207
208 // setting to zero:
209 m_coord_x.clear();
210 m_coord_y = m_curve.get_1_rep();
211 m_coord_z.clear();
212 return;
213 }
214
215 m_curve.sqr(T5, T4, ws);
216
217 m_curve.mul(T3, T1, T5, ws);
218
219 m_curve.mul(T1, T5, T4, ws);
220
221 m_curve.sqr(m_coord_x, T0, ws);
222 m_coord_x.mod_sub(T1, p, sub_ws);
223 m_coord_x.mod_sub(T3, p, sub_ws);
224 m_coord_x.mod_sub(T3, p, sub_ws);
225
226 T3.mod_sub(m_coord_x, p, sub_ws);
227
228 m_curve.mul(m_coord_y, T0, T3, ws);
229 m_curve.mul(T3, T2, T1, ws);
230
231 m_coord_y.mod_sub(T3, p, sub_ws);
232
233 m_curve.mul(T3, z_words, z_size, m_coord_z, ws);
234 m_curve.mul(m_coord_z, T3, T4, ws);
235}
236
237void EC_Point::mult2i(size_t iterations, std::vector<BigInt>& ws_bn) {
238 if(iterations == 0) {
239 return;
240 }
241
242 if(m_coord_y.is_zero()) {
243 *this = EC_Point(m_curve); // setting myself to zero
244 return;
245 }
246
247 /*
248 TODO we can save 2 squarings per iteration by computing
249 a*Z^4 using values cached from previous iteration
250 */
251 for(size_t i = 0; i != iterations; ++i) {
252 mult2(ws_bn);
253 }
254}
255
256// *this *= 2
257void EC_Point::mult2(std::vector<BigInt>& ws_bn) {
258 if(is_zero()) {
259 return;
260 }
261
262 if(m_coord_y.is_zero()) {
263 *this = EC_Point(m_curve); // setting myself to zero
264 return;
265 }
266
267 resize_ws(ws_bn, m_curve.get_ws_size());
268
269 secure_vector<word>& ws = ws_bn[0].get_word_vector();
270 secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
271
272 BigInt& T0 = ws_bn[2];
273 BigInt& T1 = ws_bn[3];
274 BigInt& T2 = ws_bn[4];
275 BigInt& T3 = ws_bn[5];
276 BigInt& T4 = ws_bn[6];
277
278 /*
279 https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-1986-cc
280 */
281 const BigInt& p = m_curve.get_p();
282
283 m_curve.sqr(T0, m_coord_y, ws);
284
285 m_curve.mul(T1, m_coord_x, T0, ws);
286 T1.mod_mul(4, p, sub_ws);
287
288 if(m_curve.a_is_zero()) {
289 // if a == 0 then 3*x^2 + a*z^4 is just 3*x^2
290 m_curve.sqr(T4, m_coord_x, ws); // x^2
291 T4.mod_mul(3, p, sub_ws); // 3*x^2
292 } else if(m_curve.a_is_minus_3()) {
293 /*
294 if a == -3 then
295 3*x^2 + a*z^4 == 3*x^2 - 3*z^4 == 3*(x^2-z^4) == 3*(x-z^2)*(x+z^2)
296 */
297 m_curve.sqr(T3, m_coord_z, ws); // z^2
298
299 // (x-z^2)
300 T2 = m_coord_x;
301 T2.mod_sub(T3, p, sub_ws);
302
303 // (x+z^2)
304 T3.mod_add(m_coord_x, p, sub_ws);
305
306 m_curve.mul(T4, T2, T3, ws); // (x-z^2)*(x+z^2)
307
308 T4.mod_mul(3, p, sub_ws); // 3*(x-z^2)*(x+z^2)
309 } else {
310 m_curve.sqr(T3, m_coord_z, ws); // z^2
311 m_curve.sqr(T4, T3, ws); // z^4
312 m_curve.mul(T3, m_curve.get_a_rep(), T4, ws); // a*z^4
313
314 m_curve.sqr(T4, m_coord_x, ws); // x^2
315 T4.mod_mul(3, p, sub_ws);
316 T4.mod_add(T3, p, sub_ws); // 3*x^2 + a*z^4
317 }
318
319 m_curve.sqr(T2, T4, ws);
320 T2.mod_sub(T1, p, sub_ws);
321 T2.mod_sub(T1, p, sub_ws);
322
323 m_curve.sqr(T3, T0, ws);
324 T3.mod_mul(8, p, sub_ws);
325
326 T1.mod_sub(T2, p, sub_ws);
327
328 m_curve.mul(T0, T4, T1, ws);
329 T0.mod_sub(T3, p, sub_ws);
330
331 m_coord_x.swap(T2);
332
333 m_curve.mul(T2, m_coord_y, m_coord_z, ws);
334 T2.mod_mul(2, p, sub_ws);
335
336 m_coord_y.swap(T0);
337 m_coord_z.swap(T2);
338}
339
340// arithmetic operators
342 std::vector<BigInt> ws(EC_Point::WORKSPACE_SIZE);
343 add(rhs, ws);
344 return *this;
345}
346
348 EC_Point minus_rhs = EC_Point(rhs).negate();
349
350 if(is_zero()) {
351 *this = minus_rhs;
352 } else {
353 *this += minus_rhs;
354 }
355
356 return *this;
357}
358
360 *this = scalar * *this;
361 return *this;
362}
363
364EC_Point EC_Point::mul(const BigInt& scalar) const {
365 const size_t scalar_bits = scalar.bits();
366
367 std::vector<BigInt> ws(EC_Point::WORKSPACE_SIZE);
368
369 EC_Point R[2] = {this->zero(), *this};
370
371 for(size_t i = scalar_bits; i > 0; i--) {
372 const size_t b = scalar.get_bit(i - 1);
373 R[b ^ 1].add(R[b], ws);
374 R[b].mult2(ws);
375 }
376
377 if(scalar.is_negative()) {
378 R[0].negate();
379 }
380
382
383 return R[0];
384}
385
386//static
387void EC_Point::force_all_affine(std::span<EC_Point> points, secure_vector<word>& ws) {
388 if(points.size() <= 1) {
389 for(auto& point : points) {
390 point.force_affine();
391 }
392 return;
393 }
394
395 for(auto& point : points) {
396 if(point.is_zero()) {
397 throw Invalid_State("Cannot convert zero ECC point to affine");
398 }
399 }
400
401 /*
402 For >= 2 points use Montgomery's trick
403
404 See Algorithm 2.26 in "Guide to Elliptic Curve Cryptography"
405 (Hankerson, Menezes, Vanstone)
406
407 TODO is it really necessary to save all k points in c?
408 */
409
410 const CurveGFp& curve = points[0].m_curve;
411 const BigInt& rep_1 = curve.get_1_rep();
412
413 if(ws.size() < curve.get_ws_size()) {
414 ws.resize(curve.get_ws_size());
415 }
416
417 std::vector<BigInt> c(points.size());
418 c[0] = points[0].m_coord_z;
419
420 for(size_t i = 1; i != points.size(); ++i) {
421 curve.mul(c[i], c[i - 1], points[i].m_coord_z, ws);
422 }
423
424 BigInt s_inv = curve.invert_element(c[c.size() - 1], ws);
425
426 BigInt z_inv, z2_inv, z3_inv;
427
428 for(size_t i = points.size() - 1; i != 0; i--) {
429 EC_Point& point = points[i];
430
431 curve.mul(z_inv, s_inv, c[i - 1], ws);
432
433 s_inv = curve.mul_to_tmp(s_inv, point.m_coord_z, ws);
434
435 curve.sqr(z2_inv, z_inv, ws);
436 curve.mul(z3_inv, z2_inv, z_inv, ws);
437 point.m_coord_x = curve.mul_to_tmp(point.m_coord_x, z2_inv, ws);
438 point.m_coord_y = curve.mul_to_tmp(point.m_coord_y, z3_inv, ws);
439 point.m_coord_z = rep_1;
440 }
441
442 curve.sqr(z2_inv, s_inv, ws);
443 curve.mul(z3_inv, z2_inv, s_inv, ws);
444 points[0].m_coord_x = curve.mul_to_tmp(points[0].m_coord_x, z2_inv, ws);
445 points[0].m_coord_y = curve.mul_to_tmp(points[0].m_coord_y, z3_inv, ws);
446 points[0].m_coord_z = rep_1;
447}
448
450 if(is_zero()) {
451 throw Invalid_State("Cannot convert zero ECC point to affine");
452 }
453
455
456 const BigInt z_inv = m_curve.invert_element(m_coord_z, ws);
457 const BigInt z2_inv = m_curve.sqr_to_tmp(z_inv, ws);
458 const BigInt z3_inv = m_curve.mul_to_tmp(z_inv, z2_inv, ws);
459 m_coord_x = m_curve.mul_to_tmp(m_coord_x, z2_inv, ws);
460 m_coord_y = m_curve.mul_to_tmp(m_coord_y, z3_inv, ws);
461 m_coord_z = m_curve.get_1_rep();
462}
463
465 return m_curve.is_one(m_coord_z);
466}
467
469 const size_t p_bytes = m_curve.get_p_bytes();
470 secure_vector<uint8_t> b(p_bytes);
471 BigInt::encode_1363(b.data(), b.size(), this->get_affine_x());
472 return b;
473}
474
476 const size_t p_bytes = m_curve.get_p_bytes();
477 secure_vector<uint8_t> b(p_bytes);
478 BigInt::encode_1363(b.data(), b.size(), this->get_affine_y());
479 return b;
480}
481
483 const size_t p_bytes = m_curve.get_p_bytes();
484 secure_vector<uint8_t> b(2 * p_bytes);
485 BigInt::encode_1363(&b[0], p_bytes, this->get_affine_x());
486 BigInt::encode_1363(&b[p_bytes], p_bytes, this->get_affine_y());
487 return b;
488}
489
491 if(is_zero()) {
492 throw Invalid_State("Cannot convert zero point to affine");
493 }
494
495 secure_vector<word> monty_ws;
496
497 if(is_affine()) {
498 return m_curve.from_rep_to_tmp(m_coord_x, monty_ws);
499 }
500
501 BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws);
502 z2 = m_curve.invert_element(z2, monty_ws);
503
504 BigInt r;
505 m_curve.mul(r, m_coord_x, z2, monty_ws);
506 m_curve.from_rep(r, monty_ws);
507 return r;
508}
509
511 if(is_zero()) {
512 throw Invalid_State("Cannot convert zero point to affine");
513 }
514
515 secure_vector<word> monty_ws;
516
517 if(is_affine()) {
518 return m_curve.from_rep_to_tmp(m_coord_y, monty_ws);
519 }
520
521 const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws);
522 const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws);
523 const BigInt z3_inv = m_curve.invert_element(z3, monty_ws);
524
525 BigInt r;
526 m_curve.mul(r, m_coord_y, z3_inv, monty_ws);
527 m_curve.from_rep(r, monty_ws);
528 return r;
529}
530
532 /*
533 Is the point still on the curve?? (If everything is correct, the
534 point is always on its curve; then the function will return true.
535 If somehow the state is corrupted, which suggests a fault attack
536 (or internal computational error), then return false.
537 */
538 if(is_zero()) {
539 return true;
540 }
541
542 secure_vector<word> monty_ws;
543
544 const BigInt y2 = m_curve.from_rep_to_tmp(m_curve.sqr_to_tmp(m_coord_y, monty_ws), monty_ws);
545 const BigInt x3 = m_curve.mul_to_tmp(m_coord_x, m_curve.sqr_to_tmp(m_coord_x, monty_ws), monty_ws);
546 const BigInt ax = m_curve.mul_to_tmp(m_coord_x, m_curve.get_a_rep(), monty_ws);
547 const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws);
548
549 if(m_coord_z == z2) // Is z equal to 1 (in Montgomery form)?
550 {
551 if(y2 != m_curve.from_rep_to_tmp(x3 + ax + m_curve.get_b_rep(), monty_ws)) {
552 return false;
553 }
554 }
555
556 const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws);
557 const BigInt ax_z4 = m_curve.mul_to_tmp(ax, m_curve.sqr_to_tmp(z2, monty_ws), monty_ws);
558 const BigInt b_z6 = m_curve.mul_to_tmp(m_curve.get_b_rep(), m_curve.sqr_to_tmp(z3, monty_ws), monty_ws);
559
560 if(y2 != m_curve.from_rep_to_tmp(x3 + ax_z4 + b_z6, monty_ws)) {
561 return false;
562 }
563
564 return true;
565}
566
567// swaps the states of *this and other
568void EC_Point::swap(EC_Point& other) noexcept {
569 m_curve.swap(other.m_curve);
570 m_coord_x.swap(other.m_coord_x);
571 m_coord_y.swap(other.m_coord_y);
572 m_coord_z.swap(other.m_coord_z);
573}
574
575bool EC_Point::operator==(const EC_Point& other) const {
576 if(m_curve != other.m_curve) {
577 return false;
578 }
579
580 // If this is zero, only equal if other is also zero
581 if(is_zero()) {
582 return other.is_zero();
583 }
584
585 return (get_affine_x() == other.get_affine_x() && get_affine_y() == other.get_affine_y());
586}
587
588// encoding and decoding
589std::vector<uint8_t> EC_Point::encode(EC_Point_Format format) const {
590 if(is_zero()) {
591 return std::vector<uint8_t>(1); // single 0 byte
592 }
593
594 const size_t p_bytes = m_curve.get_p().bytes();
595
596 const BigInt x = get_affine_x();
597 const BigInt y = get_affine_y();
598
599 const size_t parts = (format == EC_Point_Format::Compressed) ? 1 : 2;
600
601 std::vector<uint8_t> result(1 + parts * p_bytes);
602 BufferStuffer stuffer(result);
603
604 if(format == EC_Point_Format::Uncompressed) {
605 stuffer.append(0x04);
606 x.serialize_to(stuffer.next(p_bytes));
607 y.serialize_to(stuffer.next(p_bytes));
608 } else if(format == EC_Point_Format::Compressed) {
609 stuffer.append(0x02 | static_cast<uint8_t>(y.get_bit(0)));
610 x.serialize_to(stuffer.next(p_bytes));
611 } else if(format == EC_Point_Format::Hybrid) {
612 stuffer.append(0x06 | static_cast<uint8_t>(y.get_bit(0)));
613 x.serialize_to(stuffer.next(p_bytes));
614 y.serialize_to(stuffer.next(p_bytes));
615 } else {
616 throw Invalid_Argument("EC2OSP illegal point encoding");
617 }
618
619 return result;
620}
621
622namespace {
623
624BigInt decompress_point(
625 bool yMod2, const BigInt& x, const BigInt& curve_p, const BigInt& curve_a, const BigInt& curve_b) {
626 BigInt xpow3 = x * x * x;
627
628 BigInt g = curve_a * x;
629 g += xpow3;
630 g += curve_b;
631 g = g % curve_p;
632
633 BigInt z = sqrt_modulo_prime(g, curve_p);
634
635 if(z < 0) {
636 throw Decoding_Error("Error during EC point decompression");
637 }
638
639 if(z.get_bit(0) != yMod2) {
640 z = curve_p - z;
641 }
642
643 return z;
644}
645
646} // namespace
647
648EC_Point OS2ECP(const uint8_t data[], size_t data_len, const CurveGFp& curve) {
649 // Should we really be doing this?
650 if(data_len <= 1) {
651 return EC_Point(curve); // return zero
652 }
653
654 std::pair<BigInt, BigInt> xy = OS2ECP(data, data_len, curve.get_p(), curve.get_a(), curve.get_b());
655
656 EC_Point point(curve, xy.first, xy.second);
657
658 if(!point.on_the_curve()) {
659 throw Decoding_Error("OS2ECP: Decoded point was not on the curve");
660 }
661
662 return point;
663}
664
665std::pair<BigInt, BigInt> OS2ECP(
666 const uint8_t data[], size_t data_len, const BigInt& curve_p, const BigInt& curve_a, const BigInt& curve_b) {
667 if(data_len <= 1) {
668 throw Decoding_Error("OS2ECP invalid point");
669 }
670
671 const uint8_t pc = data[0];
672
673 BigInt x, y;
674
675 if(pc == 2 || pc == 3) {
676 //compressed form
677 x = BigInt::decode(&data[1], data_len - 1);
678
679 const bool y_mod_2 = ((pc & 0x01) == 1);
680 y = decompress_point(y_mod_2, x, curve_p, curve_a, curve_b);
681 } else if(pc == 4) {
682 const size_t l = (data_len - 1) / 2;
683
684 // uncompressed form
685 x = BigInt::decode(&data[1], l);
686 y = BigInt::decode(&data[l + 1], l);
687 } else if(pc == 6 || pc == 7) {
688 const size_t l = (data_len - 1) / 2;
689
690 // hybrid form
691 x = BigInt::decode(&data[1], l);
692 y = BigInt::decode(&data[l + 1], l);
693
694 const bool y_mod_2 = ((pc & 0x01) == 1);
695
696 if(decompress_point(y_mod_2, x, curve_p, curve_a, curve_b) != y) {
697 throw Decoding_Error("OS2ECP: Decoding error in hybrid format");
698 }
699 } else {
700 throw Invalid_Argument("OS2ECP: Unknown format type " + std::to_string(pc));
701 }
702
703 return std::make_pair(x, y);
704}
705
706EC_Point OS2ECP(std::span<const uint8_t> data, const CurveGFp& curve) {
707 return OS2ECP(data.data(), data.size(), curve);
708}
709
710} // namespace Botan
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:98
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:50
BigInt & mod_mul(uint8_t y, const BigInt &mod, secure_vector< word > &ws)
Definition big_ops2.cpp:119
void swap(BigInt &other)
Definition bigint.h:191
static BigInt decode(const uint8_t buf[], size_t length)
Definition bigint.h:862
static BigInt random_integer(RandomNumberGenerator &rng, const BigInt &min, const BigInt &max)
Definition big_rand.cpp:43
void resize(size_t s)
Definition bigint.h:668
void set_words(const word w[], size_t len)
Definition bigint.h:551
BigInt & mod_add(const BigInt &y, const BigInt &mod, secure_vector< word > &ws)
Definition big_ops2.cpp:45
void serialize_to(std::span< uint8_t > out) const
Definition bigint.cpp:383
BigInt & mod_sub(const BigInt &y, const BigInt &mod, secure_vector< word > &ws)
Definition big_ops2.cpp:90
size_t bits() const
Definition bigint.cpp:295
static secure_vector< uint8_t > encode_1363(const BigInt &n, size_t bytes)
Definition bigint.h:900
void clear()
Definition bigint.h:399
bool is_zero() const
Definition bigint.h:457
bool is_negative() const
Definition bigint.h:559
size_t bytes() const
Definition bigint.cpp:282
bool get_bit(size_t n) const
Definition bigint.h:496
Helper class to ease in-place marshalling of concatenated fixed-length values.
Definition stl_util.h:142
constexpr void append(std::span< const uint8_t > buffer)
Definition stl_util.h:177
constexpr std::span< uint8_t > next(size_t bytes)
Definition stl_util.h:150
const BigInt & get_a() const
Definition curve_gfp.h:98
const BigInt & get_p() const
Definition curve_gfp.h:109
const BigInt & get_b() const
Definition curve_gfp.h:103
EC_Point & negate()
Definition ec_point.h:133
void randomize_repr(RandomNumberGenerator &rng)
Definition ec_point.cpp:37
BigInt get_affine_x() const
Definition ec_point.cpp:490
secure_vector< uint8_t > x_bytes() const
Definition ec_point.cpp:468
secure_vector< uint8_t > xy_bytes() const
Definition ec_point.cpp:482
void add(const EC_Point &other, std::vector< BigInt > &workspace)
Definition ec_point.h:263
void add_affine(const EC_Point &other, std::vector< BigInt > &workspace)
Definition ec_point.h:301
void mult2(std::vector< BigInt > &workspace)
Definition ec_point.cpp:257
void mult2i(size_t i, std::vector< BigInt > &workspace)
Definition ec_point.cpp:237
EC_Point & operator-=(const EC_Point &rhs)
Definition ec_point.cpp:347
bool is_zero() const
Definition ec_point.h:156
bool on_the_curve() const
Definition ec_point.cpp:531
EC_Point & operator+=(const EC_Point &rhs)
Definition ec_point.cpp:341
EC_Point zero() const
Definition ec_point.h:195
bool is_affine() const
Definition ec_point.cpp:464
bool operator==(const EC_Point &other) const
Definition ec_point.cpp:575
EC_Point mul(const BigInt &scalar) const
Definition ec_point.cpp:364
void force_affine()
Definition ec_point.cpp:449
static void force_all_affine(std::span< EC_Point > points, secure_vector< word > &ws)
Definition ec_point.cpp:387
BigInt get_affine_y() const
Definition ec_point.cpp:510
EC_Point & operator*=(const BigInt &scalar)
Definition ec_point.cpp:359
secure_vector< uint8_t > y_bytes() const
Definition ec_point.cpp:475
friend void swap(EC_Point &x, EC_Point &y)
Definition ec_point.h:250
EC_Point()=default
std::vector< uint8_t > encode(EC_Point_Format format) const
Definition ec_point.cpp:589
constexpr CT::Mask< T > all_zeros(const T elem[], size_t len)
Definition ct_utils.h:473
EC_Point_Format
Definition ec_point.h:19
EC_Point OS2ECP(const uint8_t data[], size_t data_len, const CurveGFp &curve)
Definition ec_point.cpp:648
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
BigInt sqrt_modulo_prime(const BigInt &a, const BigInt &p)
Definition numthry.cpp:26