Botan 3.6.1
Crypto and TLS for C&
ec_group.h
Go to the documentation of this file.
1/*
2* ECC Domain Parameters
3*
4* (C) 2007 Falko Strenzke, FlexSecure GmbH
5* 2008-2010,2024 Jack Lloyd
6*
7* Botan is released under the Simplified BSD License (see license.txt)
8*/
9
10#ifndef BOTAN_ECC_DOMAIN_PARAMETERS_H_
11#define BOTAN_ECC_DOMAIN_PARAMETERS_H_
12
13#include <botan/asn1_obj.h>
14#include <botan/ec_apoint.h>
15#include <botan/ec_point.h>
16#include <botan/ec_scalar.h>
17#include <memory>
18#include <set>
19#include <span>
20
21namespace Botan {
22
23/**
24* This class represents elliptic curce domain parameters
25*/
35
36enum class EC_Group_Source {
37 Builtin,
39};
40
41class EC_Mul2Table_Data;
42class EC_Group_Data;
43class EC_Group_Data_Map;
44
45/**
46* Class representing an elliptic curve
47*
48* The internal representation is stored in a shared_ptr, so copying an
49* EC_Group is inexpensive.
50*/
52 public:
53 /**
54 * Construct elliptic curve from the specified parameters
55 *
56 * This is used for example to create custom (application-specific) curves.
57 *
58 * @param p the elliptic curve p
59 * @param a the elliptic curve a param
60 * @param b the elliptic curve b param
61 * @param base_x the x coordinate of the base point
62 * @param base_y the y coordinate of the base point
63 * @param order the order of the base point
64 * @param cofactor the cofactor
65 * @param oid an optional OID used to identify this curve
66 *
67 * @warning This constructor is deprecated and will be removed in Botan 4
68 *
69 * @warning support for cofactors > 1 is deprecated and will be removed
70 *
71 * @warning support for prime fields > 521 bits is deprecated and
72 * will be removed.
73 *
74 * @warning Support for explicitly encoded curve parameters is deprecated.
75 * An OID must be assigned.
76 */
77 BOTAN_DEPRECATED("Use alternate constructor")
78 EC_Group(const BigInt& p,
79 const BigInt& a,
80 const BigInt& b,
81 const BigInt& base_x,
82 const BigInt& base_y,
83 const BigInt& order,
84 const BigInt& cofactor,
85 const OID& oid = OID());
86
87 /**
88 * Construct elliptic curve from the specified parameters
89 *
90 * This is used for example to create custom (application-specific) curves.
91 *
92 * Unlike the deprecated constructor, this constructor imposes
93 * additional restrictions on the parameters, namely:
94 *
95 * - The prime must be at least 128 bits and at most 512 bits, and
96 * a multiple of 32 bits.
97 * - As an extension of the above restriction, the prime can
98 * also be exactly the 521-bit Mersenne prime (2**521-1)
99 * - The prime must be congruent to 3 modulo 4
100 * - The group order must have the same bit length as the prime
101 * (It is allowed for the order to be larger than p, but they
102 * must have the same bit length)
103 * - An object identifier must be provided
104 * - There must be no cofactor
105 *
106 * @warning use only elliptic curve parameters that you trust
107 *
108 * @param oid an object identifier used to identify this curve
109 * @param p the elliptic curve prime (at most 521 bits)
110 * @param a the elliptic curve a param
111 * @param b the elliptic curve b param
112 * @param base_x the x coordinate of the group generator
113 * @param base_y the y coordinate of the group generator
114 * @param order the order of the group
115 */
116 EC_Group(const OID& oid,
117 const BigInt& p,
118 const BigInt& a,
119 const BigInt& b,
120 const BigInt& base_x,
121 const BigInt& base_y,
122 const BigInt& order);
123
124 /**
125 * Decode a BER encoded ECC domain parameter set
126 * @param ber the bytes of the BER encoding
127 */
128 explicit EC_Group(std::span<const uint8_t> ber);
129
130 BOTAN_DEPRECATED("Use EC_Group(std::span)")
131 EC_Group(const uint8_t ber[], size_t ber_len) : EC_Group(std::span{ber, ber_len}) {}
132
133 /**
134 * Create an EC domain by OID (or throw if unknown)
135 * @param oid the OID of the EC domain to create
136 */
137 BOTAN_DEPRECATED("Use EC_Group::from_OID") explicit EC_Group(const OID& oid) { *this = EC_Group::from_OID(oid); }
138
139 /**
140 * Create an EC domain from PEM encoding (as from PEM_encode()), or
141 * from an OID name (eg "secp256r1", or "1.2.840.10045.3.1.7")
142 * @param pem_or_oid PEM-encoded data, or an OID
143 *
144 * @warning Support for PEM in this function is deprecated. Use
145 * EC_Group::from_PEM or EC_Group::from_OID or EC_Group::from_name
146 */
147 BOTAN_DEPRECATED("Use EC_Group::from_{name,OID,PEM}") explicit EC_Group(std::string_view pem_or_oid);
148
149 /**
150 * Initialize an EC group from the PEM/ASN.1 encoding
151 */
152 static EC_Group from_PEM(std::string_view pem);
153
154 /**
155 * Initialize an EC group from a group named by an object identifier
156 */
157 static EC_Group from_OID(const OID& oid);
158
159 /**
160 * Initialize an EC group from a group common name (eg "secp256r1")
161 */
162 static EC_Group from_name(std::string_view name);
163
164 BOTAN_DEPRECATED("Use EC_Group::from_PEM") static EC_Group EC_Group_from_PEM(std::string_view pem) {
165 return EC_Group::from_PEM(pem);
166 }
167
168 /**
169 * Create an uninitialized EC_Group
170 */
172
174
176 EC_Group(EC_Group&&) = default;
177
180
181 bool initialized() const { return (m_data != nullptr); }
182
183 /**
184 * Verify EC_Group domain
185 * @returns true if group is valid. false otherwise
186 */
187 bool verify_group(RandomNumberGenerator& rng, bool strong = false) const;
188
189 bool operator==(const EC_Group& other) const;
190
191 EC_Group_Source source() const;
192
193 /**
194 * Return true if this EC_Group was derived from an explicit encoding
195 *
196 * Explicit encoding of groups is deprecated; when support for explicit curves
197 * is removed in a future major release, this function will also be removed.
198 */
199 bool used_explicit_encoding() const { return m_explicit_encoding; }
200
201 /**
202 * Return a set of known named EC groups
203 */
204 static const std::set<std::string>& known_named_groups();
205
206 /**
207 * Create the DER encoding of this domain
208 * @param form of encoding to use
209 * @returns the group information encoded as DER
210 */
211 BOTAN_DEPRECATED("Use the variant that does not take EC_Group_Encoding")
212 std::vector<uint8_t> DER_encode(EC_Group_Encoding form) const;
213
214 /**
215 * Create the DER encoding of this domain, using namedCurve format
216 * @returns the group information encoded as DER
217 */
218 std::vector<uint8_t> DER_encode() const;
219
220 /**
221 * Return the PEM encoding (always in explicit form)
222 * @return string containing PEM data
223 */
224 std::string PEM_encode() const;
225
226 /**
227 * Return the size of p in bits (same as get_p().bits())
228 */
229 size_t get_p_bits() const;
230
231 /**
232 * Return the size of p in bytes (same as get_p().bytes())
233 */
234 size_t get_p_bytes() const;
235
236 /**
237 * Return the size of group order in bits (same as get_order().bits())
238 */
239 size_t get_order_bits() const;
240
241 /**
242 * Return the size of the group order in bytes (same as get_order().bytes())
243 */
244 size_t get_order_bytes() const;
245
246 /**
247 * Check if y is a plausible point on the curve
248 *
249 * In particular, checks that it is a point on the curve, not infinity,
250 * and that it has order matching the group.
251 */
252 bool verify_public_element(const EC_Point& y) const;
253
254 /// Table for computing g*x + h*y
256 public:
257 /**
258 * Create a table for computing g*x + h*y
259 */
260 Mul2Table(const EC_AffinePoint& h);
261
262 /**
263 * Return the elliptic curve point g*x + h*y
264 *
265 * Where g is the group generator and h is the value passed to the constructor
266 *
267 * Returns nullopt if g*x + h*y was the point at infinity
268 *
269 * @warning this function is variable time with respect to x and y
270 */
271 std::optional<EC_AffinePoint> mul2_vartime(const EC_Scalar& x, const EC_Scalar& y) const;
272
273 /**
274 * Check if v equals the x coordinate of g*x + h*y reduced modulo the order
275 *
276 * Where g is the group generator and h is the value passed to the constructor
277 *
278 * Returns false if unequal, including if g*x + h*y was the point at infinity
279 *
280 * @warning this function is variable time with respect to x and y
281 */
282 bool mul2_vartime_x_mod_order_eq(const EC_Scalar& v, const EC_Scalar& x, const EC_Scalar& y) const;
283
284 /**
285 * Check if v equals the x coordinate of g*x*c + h*y*c reduced modulo the order
286 *
287 * Where g is the group generator and h is the value passed to the constructor
288 *
289 * Returns false if unequal, including if g*x*c + h*y*c was the point at infinity
290 *
291 * @warning this function is variable time with respect to x and y
292 */
293 bool mul2_vartime_x_mod_order_eq(const EC_Scalar& v,
294 const EC_Scalar& c,
295 const EC_Scalar& x,
296 const EC_Scalar& y) const;
297
299
300 private:
301 std::unique_ptr<EC_Mul2Table_Data> m_tbl;
302 };
303
304 /**
305 * Return the OID of these domain parameters
306 * @result the OID
307 */
308 const OID& get_curve_oid() const;
309
310 /**
311 * Return the prime modulus of the field
312 */
313 const BigInt& get_p() const;
314
315 /**
316 * Return the a parameter of the elliptic curve equation
317 */
318 const BigInt& get_a() const;
319
320 /**
321 * Return the b parameter of the elliptic curve equation
322 */
323 const BigInt& get_b() const;
324
325 /**
326 * Return the x coordinate of the base point
327 */
328 const BigInt& get_g_x() const;
329
330 /**
331 * Return the y coordinate of the base point
332 */
333 const BigInt& get_g_y() const;
334
335 /**
336 * Return the order of the base point
337 * @result order of the base point
338 */
339 const BigInt& get_order() const;
340
341 /**
342 * Return the cofactor
343 * @result the cofactor
344 */
345 const BigInt& get_cofactor() const;
346
347 /**
348 * Return true if the cofactor is > 1
349 */
350 bool has_cofactor() const;
351
352 /*
353 * For internal use only
354 */
355 static std::shared_ptr<EC_Group_Data> EC_group_info(const OID& oid);
356
357 /*
358 * For internal use only
359 */
360 static size_t clear_registered_curve_data();
361
362 /*
363 * For internal use only
364 */
365 static OID EC_group_identity_from_order(const BigInt& order);
366
367 /*
368 * For internal use only
369 */
370 const std::shared_ptr<EC_Group_Data>& _data() const { return m_data; }
371
372 /**
373 * OS2ECP (Octet String To Elliptic Curve Point)
374 *
375 * Deserialize an encoded point. Verifies that the point is on the curve.
376 */
377 EC_Point OS2ECP(const uint8_t bits[], size_t len) const {
378 return EC_AffinePoint(*this, std::span{bits, len}).to_legacy_point();
379 }
380
381 EC_Point OS2ECP(std::span<const uint8_t> encoded_point) const {
382 return EC_AffinePoint(*this, encoded_point).to_legacy_point();
383 }
384
385 /**
386 * Return group base point
387 * @result base point
388 */
389 BOTAN_DEPRECATED("Deprecated no replacement") const EC_Point& get_base_point() const;
390
391 // Everything below here will be removed in a future release:
392
393 /**
394 * Return the canonical group generator
395 * @result standard generator of the curve
396 */
397 BOTAN_DEPRECATED("Deprecated no replacement") const EC_Point& generator() const;
398
399 /**
400 * Multi exponentiate. Not constant time.
401 * @return base_point*x + h*y
402 */
403 BOTAN_DEPRECATED("Use EC_Group::Mul2Table")
404 EC_Point point_multiply(const BigInt& x_bn, const EC_Point& h_pt, const BigInt& y_bn) const {
405 auto x = EC_Scalar::from_bigint(*this, x_bn);
406 auto y = EC_Scalar::from_bigint(*this, y_bn);
407 auto h = EC_AffinePoint(*this, h_pt);
408
409 Mul2Table gh_mul(h);
410
411 if(auto r = gh_mul.mul2_vartime(x, y)) {
412 return r->to_legacy_point();
413 } else {
414 return EC_AffinePoint::identity(*this).to_legacy_point();
415 }
416 }
417
418 /**
419 * Blinded point multiplication, attempts resistance to side channels
420 * @param k_bn the scalar
421 * @param rng a random number generator
422 * @param ws a temp workspace
423 * @return base_point*k
424 */
425 BOTAN_DEPRECATED("Use EC_AffinePoint and EC_Scalar")
427 blinded_base_point_multiply(const BigInt& k_bn, RandomNumberGenerator& rng, std::vector<BigInt>& ws) const {
428 auto k = EC_Scalar::from_bigint(*this, k_bn);
429 auto pt = EC_AffinePoint::g_mul(k, rng, ws);
430 return pt.to_legacy_point();
431 }
432
433 /**
434 * Blinded point multiplication, attempts resistance to side channels
435 * Returns just the x coordinate of the point
436 *
437 * @param k_bn the scalar
438 * @param rng a random number generator
439 * @param ws a temp workspace
440 * @return x coordinate of base_point*k
441 */
442 BOTAN_DEPRECATED("Use EC_AffinePoint and EC_Scalar")
443 BigInt
444 blinded_base_point_multiply_x(const BigInt& k_bn, RandomNumberGenerator& rng, std::vector<BigInt>& ws) const {
445 auto k = EC_Scalar::from_bigint(*this, k_bn);
446 return BigInt(EC_AffinePoint::g_mul(k, rng, ws).x_bytes());
447 }
448
449 /**
450 * Blinded point multiplication, attempts resistance to side channels
451 * @param point input point
452 * @param k_bn the scalar
453 * @param rng a random number generator
454 * @param ws a temp workspace
455 * @return point*k
456 */
457 BOTAN_DEPRECATED("Use EC_AffinePoint and EC_Scalar")
458 EC_Point blinded_var_point_multiply(const EC_Point& point,
459 const BigInt& k_bn,
461 std::vector<BigInt>& ws) const {
462 auto k = EC_Scalar::from_bigint(*this, k_bn);
463 auto pt = EC_AffinePoint(*this, point);
464 return pt.mul(k, rng, ws).to_legacy_point();
465 }
466
467 /**
468 * Return a random scalar ie an integer in [1,order)
469 */
470 BOTAN_DEPRECATED("Use EC_Scalar::random") BigInt random_scalar(RandomNumberGenerator& rng) const {
471 return EC_Scalar::random(*this, rng).to_bigint();
472 }
473
474 /**
475 * Hash onto the curve.
476 * For some curve types no mapping is currently available, in this
477 * case this function will throw an exception.
478 *
479 * @param hash_fn the hash function to use (typically "SHA-256" or "SHA-512")
480 * @param input the input to hash
481 * @param input_len length of input in bytes
482 * @param domain_sep a domain seperator
483 * @param domain_sep_len length of domain_sep in bytes
484 * @param random_oracle if the mapped point must be uniform (use
485 "true" here unless you know what you are doing)
486 */
487 BOTAN_DEPRECATED("Use EC_AffinePoint")
488 EC_Point hash_to_curve(std::string_view hash_fn,
489 const uint8_t input[],
490 size_t input_len,
491 const uint8_t domain_sep[],
492 size_t domain_sep_len,
493 bool random_oracle = true) const {
494 auto inp = std::span{input, input_len};
495 auto dst = std::span{domain_sep, domain_sep_len};
496
497 if(random_oracle) {
498 return EC_AffinePoint::hash_to_curve_ro(*this, hash_fn, inp, dst).to_legacy_point();
499 } else {
500 return EC_AffinePoint::hash_to_curve_nu(*this, hash_fn, inp, dst).to_legacy_point();
501 }
502 }
503
504 /**
505 * Hash onto the curve.
506 * For some curve types no mapping is currently available, in this
507 * case this function will throw an exception.
508 *
509 * @param hash_fn the hash function to use (typically "SHA-256" or "SHA-512")
510 * @param input the input to hash
511 * @param input_len length of input in bytes
512 * @param domain_sep a domain seperator
513 * @param random_oracle if the mapped point must be uniform (use
514 "true" here unless you know what you are doing)
515 */
516 BOTAN_DEPRECATED("Use EC_AffinePoint")
517 EC_Point hash_to_curve(std::string_view hash_fn,
518 const uint8_t input[],
519 size_t input_len,
520 std::string_view domain_sep,
521 bool random_oracle = true) const {
522 auto inp = std::span{input, input_len};
523 auto dst = std::span{reinterpret_cast<const uint8_t*>(domain_sep.data()), domain_sep.size()};
524
525 if(random_oracle) {
526 return EC_AffinePoint::hash_to_curve_ro(*this, hash_fn, inp, dst).to_legacy_point();
527 } else {
528 return EC_AffinePoint::hash_to_curve_nu(*this, hash_fn, inp, dst).to_legacy_point();
529 }
530 }
531
532 /**
533 * Return if a == -3 mod p
534 */
535 BOTAN_DEPRECATED("Deprecated no replacement") bool a_is_minus_3() const { return get_a() + 3 == get_p(); }
536
537 /**
538 * Return if a == 0 mod p
539 */
540 BOTAN_DEPRECATED("Deprecated no replacement") bool a_is_zero() const { return get_a().is_zero(); }
541
542 /*
543 * Reduce x modulo the order
544 */
545 BOTAN_DEPRECATED("Deprecated no replacement") BigInt mod_order(const BigInt& x) const;
546
547 /*
548 * Return inverse of x modulo the order
549 */
550 BOTAN_DEPRECATED("Use EC_Scalar") BigInt inverse_mod_order(const BigInt& x) const {
551 return EC_Scalar::from_bigint(*this, x).invert().to_bigint();
552 }
553
554 /*
555 * Reduce (x*x) modulo the order
556 */
557 BOTAN_DEPRECATED("Use EC_Scalar") BigInt square_mod_order(const BigInt& x) const {
558 auto xs = EC_Scalar::from_bigint(*this, x);
559 xs.square_self();
560 return xs.to_bigint();
561 }
562
563 /*
564 * Reduce (x*y) modulo the order
565 */
566 BOTAN_DEPRECATED("Use EC_Scalar") BigInt multiply_mod_order(const BigInt& x, const BigInt& y) const {
567 auto xs = EC_Scalar::from_bigint(*this, x);
568 auto ys = EC_Scalar::from_bigint(*this, y);
569 return (xs * ys).to_bigint();
570 }
571
572 /*
573 * Reduce (x*y*z) modulo the order
574 */
575 BOTAN_DEPRECATED("Use EC_Scalar")
576 BigInt multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const {
577 auto xs = EC_Scalar::from_bigint(*this, x);
578 auto ys = EC_Scalar::from_bigint(*this, y);
579 auto zs = EC_Scalar::from_bigint(*this, z);
580 return (xs * ys * zs).to_bigint();
581 }
582
583 /*
584 * Return x^3 modulo the order
585 */
586 BOTAN_DEPRECATED("Deprecated no replacement") BigInt cube_mod_order(const BigInt& x) const {
587 auto xs = EC_Scalar::from_bigint(*this, x);
588 return (xs * xs * xs).to_bigint();
589 }
590
591 /**
592 * Return a point on this curve with the affine values x, y
593 */
594 BOTAN_DEPRECATED("Deprecated - use EC_AffinePoint") EC_Point point(const BigInt& x, const BigInt& y) const {
595 if(auto pt = EC_AffinePoint::from_bigint_xy(*this, x, y)) {
596 return pt->to_legacy_point();
597 } else {
598 throw Decoding_Error("Invalid x/y coordinates for elliptic curve point");
599 }
600 }
601
602 /**
603 * Return the zero (or infinite) point on this curve
604 */
605 BOTAN_DEPRECATED("Deprecated no replacement") EC_Point zero_point() const {
606 return EC_AffinePoint::identity(*this).to_legacy_point();
607 }
608
609 BOTAN_DEPRECATED("Just serialize the point and check") size_t point_size(EC_Point_Format format) const {
610 // Hybrid and standard format are (x,y), compressed is y, +1 format byte
611 if(format == EC_Point_Format::Compressed) {
612 return (1 + get_p_bytes());
613 } else {
614 return (1 + 2 * get_p_bytes());
615 }
616 }
617
618 private:
619 static EC_Group_Data_Map& ec_group_data();
620
621 EC_Group(std::shared_ptr<EC_Group_Data>&& data);
622
623 static std::pair<std::shared_ptr<EC_Group_Data>, bool> BER_decode_EC_group(std::span<const uint8_t> ber,
624 EC_Group_Source source);
625
626 static std::shared_ptr<EC_Group_Data> load_EC_group_info(const char* p,
627 const char* a,
628 const char* b,
629 const char* g_x,
630 const char* g_y,
631 const char* order,
632 const OID& oid);
633
634 const EC_Group_Data& data() const;
635
636 // Member data
637 std::shared_ptr<EC_Group_Data> m_data;
638 bool m_explicit_encoding = false;
639};
640
641inline bool operator!=(const EC_Group& lhs, const EC_Group& rhs) {
642 return !(lhs == rhs);
643}
644
645} // namespace Botan
646
647#endif
EC_Point to_legacy_point() const
Table for computing g*x + h*y.
Definition ec_group.h:255
std::optional< EC_AffinePoint > mul2_vartime(const EC_Scalar &x, const EC_Scalar &y) const
Definition ec_group.cpp:643
bool initialized() const
Definition ec_group.h:181
EC_Group & operator=(EC_Group &&)=default
EC_Group(const EC_Group &)
bool used_explicit_encoding() const
Definition ec_group.h:199
const std::shared_ptr< EC_Group_Data > & _data() const
Definition ec_group.h:370
EC_Point OS2ECP(std::span< const uint8_t > encoded_point) const
Definition ec_group.h:381
EC_Group(EC_Group &&)=default
EC_Group & operator=(const EC_Group &)
EC_Point OS2ECP(const uint8_t bits[], size_t len) const
Definition ec_group.h:377
std::string name
int(* final)(unsigned char *, CTX *)
#define BOTAN_PUBLIC_API(maj, min)
Definition compiler.h:31
#define BOTAN_DEPRECATED(msg)
Definition compiler.h:125
EC_Group_Source
Definition ec_group.h:36
bool operator!=(const AlgorithmIdentifier &a1, const AlgorithmIdentifier &a2)
Definition alg_id.cpp:69
EC_Point_Format
Definition ec_point.h:19
bool operator==(const AlgorithmIdentifier &a1, const AlgorithmIdentifier &a2)
Definition alg_id.cpp:54
const SIMD_8x32 & b
EC_Group_Encoding
Definition ec_group.h:26