1//! Elliptic Curve
2//!
3//! Cryptography relies on the difficulty of solving mathematical problems, such as the factor
4//! of large integers composed of two large prime numbers and the discrete logarithm of a
5//! random elliptic curve. This module provides low-level features of the latter.
6//! Elliptic Curve protocols can provide the same security with smaller keys.
7//!
8//! There are 2 forms of elliptic curves, `Fp` and `F2^m`. These curves use irreducible
9//! trinomial or pentanomial. Being a generic interface to a wide range of algorithms,
10//! the curves are generally referenced by [`EcGroup`]. There are many built-in groups
11//! found in [`Nid`].
12//!
13//! OpenSSL Wiki explains the fields and curves in detail at [Elliptic Curve Cryptography].
14//!
15//! [`EcGroup`]: struct.EcGroup.html
16//! [`Nid`]: ../nid/struct.Nid.html
17//! [Elliptic Curve Cryptography]: https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography
18use cfg_if::cfg_if;
19use foreign_types::{ForeignType, ForeignTypeRef};
20use libc::c_int;
21use std::fmt;
22use std::ptr;
23
24use crate::bn::{BigNum, BigNumContextRef, BigNumRef};
25use crate::error::ErrorStack;
26use crate::nid::Nid;
27use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public};
28use crate::util::ForeignTypeRefExt;
29use crate::{cvt, cvt_n, cvt_p, init};
30use openssl_macros::corresponds;
31
32cfg_if! {
33 if #[cfg(not(boringssl))] {
34 use std::ffi::CString;
35 use crate::string::OpensslString;
36 }
37}
38
39/// Compressed or Uncompressed conversion
40///
41/// Conversion from the binary value of the point on the curve is performed in one of
42/// compressed, uncompressed, or hybrid conversions. The default is compressed, except
43/// for binary curves.
44///
45/// Further documentation is available in the [X9.62] standard.
46///
47/// [X9.62]: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.202.2977&rep=rep1&type=pdf
48#[derive(Copy, Clone)]
49pub struct PointConversionForm(ffi::point_conversion_form_t);
50
51impl PointConversionForm {
52 /// Compressed conversion from point value.
53 pub const COMPRESSED: PointConversionForm =
54 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED);
55
56 /// Uncompressed conversion from point value.
57 pub const UNCOMPRESSED: PointConversionForm =
58 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED);
59
60 /// Performs both compressed and uncompressed conversions.
61 pub const HYBRID: PointConversionForm =
62 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID);
63}
64
65/// Named Curve or Explicit
66///
67/// This type acts as a boolean as to whether the `EcGroup` is named or explicit.
68#[derive(Copy, Clone, Debug, PartialEq)]
69pub struct Asn1Flag(c_int);
70
71impl Asn1Flag {
72 /// Curve defined using polynomial parameters
73 ///
74 /// Most applications use a named EC_GROUP curve, however, support
75 /// is included to explicitly define the curve used to calculate keys
76 /// This information would need to be known by both endpoint to make communication
77 /// effective.
78 ///
79 /// OPENSSL_EC_EXPLICIT_CURVE, but that was only added in 1.1.
80 /// Man page documents that 0 can be used in older versions.
81 ///
82 /// OpenSSL documentation at [`EC_GROUP`]
83 ///
84 /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/crypto/EC_GROUP_get_seed_len.html
85 pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0);
86
87 /// Standard Curves
88 ///
89 /// Curves that make up the typical encryption use cases. The collection of curves
90 /// are well known but extensible.
91 ///
92 /// OpenSSL documentation at [`EC_GROUP`]
93 ///
94 /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/man3/EC_GROUP_order_bits.html
95 pub const NAMED_CURVE: Asn1Flag = Asn1Flag(ffi::OPENSSL_EC_NAMED_CURVE);
96}
97
98foreign_type_and_impl_send_sync! {
99 type CType = ffi::EC_GROUP;
100 fn drop = ffi::EC_GROUP_free;
101
102 /// Describes the curve
103 ///
104 /// A curve can be of the named curve type. These curves can be discovered
105 /// using openssl binary `openssl ecparam -list_curves`. Other operations
106 /// are available in the [wiki]. These named curves are available in the
107 /// [`Nid`] module.
108 ///
109 /// Curves can also be generated using prime field parameters or a binary field.
110 ///
111 /// Prime fields use the formula `y^2 mod p = x^3 + ax + b mod p`. Binary
112 /// fields use the formula `y^2 + xy = x^3 + ax^2 + b`. Named curves have
113 /// assured security. To prevent accidental vulnerabilities, they should
114 /// be preferred.
115 ///
116 /// [wiki]: https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations
117 /// [`Nid`]: ../nid/index.html
118 pub struct EcGroup;
119 /// Reference to [`EcGroup`]
120 ///
121 /// [`EcGroup`]: struct.EcGroup.html
122 pub struct EcGroupRef;
123}
124
125impl EcGroup {
126 /// Returns the group of a standard named curve.
127 ///
128 /// # Examples
129 ///
130 /// ```
131 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
132 /// use openssl::nid::Nid;
133 /// use openssl::ec::{EcGroup, EcKey};
134 ///
135 /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve
136 /// let group = EcGroup::from_curve_name(nid)?;
137 /// let key = EcKey::generate(&group)?;
138 /// # Ok(()) }
139 /// ```
140 #[corresponds(EC_GROUP_new_by_curve_name)]
141 pub fn from_curve_name(nid: Nid) -> Result<EcGroup, ErrorStack> {
142 unsafe {
143 init();
144 cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup)
145 }
146 }
147
148 /// Returns the group for given parameters
149 #[corresponds(EC_GROUP_new_curve_GFp)]
150 pub fn from_components(
151 p: BigNum,
152 a: BigNum,
153 b: BigNum,
154 ctx: &mut BigNumContextRef,
155 ) -> Result<EcGroup, ErrorStack> {
156 unsafe {
157 cvt_p(ffi::EC_GROUP_new_curve_GFp(
158 p.as_ptr(),
159 a.as_ptr(),
160 b.as_ptr(),
161 ctx.as_ptr(),
162 ))
163 .map(EcGroup)
164 }
165 }
166}
167
168impl EcGroupRef {
169 /// Places the components of a curve over a prime field in the provided `BigNum`s.
170 /// The components make up the formula `y^2 mod p = x^3 + ax + b mod p`.
171 #[corresponds(EC_GROUP_get_curve_GFp)]
172 pub fn components_gfp(
173 &self,
174 p: &mut BigNumRef,
175 a: &mut BigNumRef,
176 b: &mut BigNumRef,
177 ctx: &mut BigNumContextRef,
178 ) -> Result<(), ErrorStack> {
179 unsafe {
180 cvt(ffi::EC_GROUP_get_curve_GFp(
181 self.as_ptr(),
182 p.as_ptr(),
183 a.as_ptr(),
184 b.as_ptr(),
185 ctx.as_ptr(),
186 ))
187 .map(|_| ())
188 }
189 }
190
191 /// Places the components of a curve over a binary field in the provided `BigNum`s.
192 /// The components make up the formula `y^2 + xy = x^3 + ax^2 + b`.
193 ///
194 /// In this form `p` relates to the irreducible polynomial. Each bit represents
195 /// a term in the polynomial. It will be set to 3 `1`s or 5 `1`s depending on
196 /// using a trinomial or pentanomial.
197 #[corresponds(EC_GROUP_get_curve_GF2m)]
198 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
199 pub fn components_gf2m(
200 &self,
201 p: &mut BigNumRef,
202 a: &mut BigNumRef,
203 b: &mut BigNumRef,
204 ctx: &mut BigNumContextRef,
205 ) -> Result<(), ErrorStack> {
206 unsafe {
207 cvt(ffi::EC_GROUP_get_curve_GF2m(
208 self.as_ptr(),
209 p.as_ptr(),
210 a.as_ptr(),
211 b.as_ptr(),
212 ctx.as_ptr(),
213 ))
214 .map(|_| ())
215 }
216 }
217
218 /// Places the cofactor of the group in the provided `BigNum`.
219 #[corresponds(EC_GROUP_get_cofactor)]
220 pub fn cofactor(
221 &self,
222 cofactor: &mut BigNumRef,
223 ctx: &mut BigNumContextRef,
224 ) -> Result<(), ErrorStack> {
225 unsafe {
226 cvt(ffi::EC_GROUP_get_cofactor(
227 self.as_ptr(),
228 cofactor.as_ptr(),
229 ctx.as_ptr(),
230 ))
231 .map(|_| ())
232 }
233 }
234
235 /// Returns the degree of the curve.
236 #[corresponds(EC_GROUP_get_degree)]
237 pub fn degree(&self) -> u32 {
238 unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 }
239 }
240
241 /// Returns the number of bits in the group order.
242 #[corresponds(EC_GROUP_order_bits)]
243 #[cfg(ossl110)]
244 pub fn order_bits(&self) -> u32 {
245 unsafe { ffi::EC_GROUP_order_bits(self.as_ptr()) as u32 }
246 }
247
248 /// Returns the generator for the given curve as an [`EcPoint`].
249 #[corresponds(EC_GROUP_get0_generator)]
250 pub fn generator(&self) -> &EcPointRef {
251 unsafe {
252 let ptr = ffi::EC_GROUP_get0_generator(self.as_ptr());
253 EcPointRef::from_const_ptr(ptr)
254 }
255 }
256
257 /// Sets the generator point for the given curve
258 #[corresponds(EC_GROUP_set_generator)]
259 pub fn set_generator(
260 &mut self,
261 generator: EcPoint,
262 order: BigNum,
263 cofactor: BigNum,
264 ) -> Result<(), ErrorStack> {
265 unsafe {
266 cvt(ffi::EC_GROUP_set_generator(
267 self.as_ptr(),
268 generator.as_ptr(),
269 order.as_ptr(),
270 cofactor.as_ptr(),
271 ))
272 .map(|_| ())
273 }
274 }
275
276 /// Places the order of the curve in the provided `BigNum`.
277 #[corresponds(EC_GROUP_get_order)]
278 pub fn order(
279 &self,
280 order: &mut BigNumRef,
281 ctx: &mut BigNumContextRef,
282 ) -> Result<(), ErrorStack> {
283 unsafe {
284 cvt(ffi::EC_GROUP_get_order(
285 self.as_ptr(),
286 order.as_ptr(),
287 ctx.as_ptr(),
288 ))
289 .map(|_| ())
290 }
291 }
292
293 /// Sets the flag determining if the group corresponds to a named curve or must be explicitly
294 /// parameterized.
295 ///
296 /// This defaults to `EXPLICIT_CURVE` in OpenSSL 1.0.1 and 1.0.2, but `NAMED_CURVE` in OpenSSL
297 /// 1.1.0.
298 #[corresponds(EC_GROUP_set_asn1_flag)]
299 pub fn set_asn1_flag(&mut self, flag: Asn1Flag) {
300 unsafe {
301 ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0);
302 }
303 }
304
305 /// Gets the flag determining if the group corresponds to a named curve.
306 #[corresponds(EC_GROUP_get_asn1_flag)]
307 pub fn asn1_flag(&self) -> Asn1Flag {
308 unsafe { Asn1Flag(ffi::EC_GROUP_get_asn1_flag(self.as_ptr())) }
309 }
310
311 /// Returns the name of the curve, if a name is associated.
312 #[corresponds(EC_GROUP_get_curve_name)]
313 pub fn curve_name(&self) -> Option<Nid> {
314 let nid = unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) };
315 if nid > 0 {
316 Some(Nid::from_raw(nid))
317 } else {
318 None
319 }
320 }
321}
322
323foreign_type_and_impl_send_sync! {
324 type CType = ffi::EC_POINT;
325 fn drop = ffi::EC_POINT_free;
326
327 /// Represents a point on the curve
328 pub struct EcPoint;
329 /// A reference a borrowed [`EcPoint`].
330 pub struct EcPointRef;
331}
332
333impl EcPointRef {
334 /// Computes `a + b`, storing the result in `self`.
335 #[corresponds(EC_POINT_add)]
336 pub fn add(
337 &mut self,
338 group: &EcGroupRef,
339 a: &EcPointRef,
340 b: &EcPointRef,
341 ctx: &mut BigNumContextRef,
342 ) -> Result<(), ErrorStack> {
343 unsafe {
344 cvt(ffi::EC_POINT_add(
345 group.as_ptr(),
346 self.as_ptr(),
347 a.as_ptr(),
348 b.as_ptr(),
349 ctx.as_ptr(),
350 ))
351 .map(|_| ())
352 }
353 }
354
355 /// Computes `q * m`, storing the result in `self`.
356 #[corresponds(EC_POINT_mul)]
357 pub fn mul(
358 &mut self,
359 group: &EcGroupRef,
360 q: &EcPointRef,
361 m: &BigNumRef,
362 // FIXME should be &mut
363 ctx: &BigNumContextRef,
364 ) -> Result<(), ErrorStack> {
365 unsafe {
366 cvt(ffi::EC_POINT_mul(
367 group.as_ptr(),
368 self.as_ptr(),
369 ptr::null(),
370 q.as_ptr(),
371 m.as_ptr(),
372 ctx.as_ptr(),
373 ))
374 .map(|_| ())
375 }
376 }
377
378 /// Computes `generator * n`, storing the result in `self`.
379 #[corresponds(EC_POINT_mul)]
380 pub fn mul_generator(
381 &mut self,
382 group: &EcGroupRef,
383 n: &BigNumRef,
384 // FIXME should be &mut
385 ctx: &BigNumContextRef,
386 ) -> Result<(), ErrorStack> {
387 unsafe {
388 cvt(ffi::EC_POINT_mul(
389 group.as_ptr(),
390 self.as_ptr(),
391 n.as_ptr(),
392 ptr::null(),
393 ptr::null(),
394 ctx.as_ptr(),
395 ))
396 .map(|_| ())
397 }
398 }
399
400 /// Computes `generator * n + q * m`, storing the result in `self`.
401 #[corresponds(EC_POINT_mul)]
402 pub fn mul_full(
403 &mut self,
404 group: &EcGroupRef,
405 n: &BigNumRef,
406 q: &EcPointRef,
407 m: &BigNumRef,
408 ctx: &mut BigNumContextRef,
409 ) -> Result<(), ErrorStack> {
410 unsafe {
411 cvt(ffi::EC_POINT_mul(
412 group.as_ptr(),
413 self.as_ptr(),
414 n.as_ptr(),
415 q.as_ptr(),
416 m.as_ptr(),
417 ctx.as_ptr(),
418 ))
419 .map(|_| ())
420 }
421 }
422
423 /// Inverts `self`.
424 #[corresponds(EC_POINT_invert)]
425 // FIXME should be mutable
426 pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> {
427 unsafe {
428 cvt(ffi::EC_POINT_invert(
429 group.as_ptr(),
430 self.as_ptr(),
431 ctx.as_ptr(),
432 ))
433 .map(|_| ())
434 }
435 }
436
437 /// Serializes the point to a binary representation.
438 #[corresponds(EC_POINT_point2oct)]
439 pub fn to_bytes(
440 &self,
441 group: &EcGroupRef,
442 form: PointConversionForm,
443 ctx: &mut BigNumContextRef,
444 ) -> Result<Vec<u8>, ErrorStack> {
445 unsafe {
446 let len = ffi::EC_POINT_point2oct(
447 group.as_ptr(),
448 self.as_ptr(),
449 form.0,
450 ptr::null_mut(),
451 0,
452 ctx.as_ptr(),
453 );
454 if len == 0 {
455 return Err(ErrorStack::get());
456 }
457 let mut buf = vec![0; len];
458 let len = ffi::EC_POINT_point2oct(
459 group.as_ptr(),
460 self.as_ptr(),
461 form.0,
462 buf.as_mut_ptr(),
463 len,
464 ctx.as_ptr(),
465 );
466 if len == 0 {
467 Err(ErrorStack::get())
468 } else {
469 Ok(buf)
470 }
471 }
472 }
473
474 /// Serializes the point to a hexadecimal string representation.
475 #[corresponds(EC_POINT_point2hex)]
476 #[cfg(not(boringssl))]
477 pub fn to_hex_str(
478 &self,
479 group: &EcGroupRef,
480 form: PointConversionForm,
481 ctx: &mut BigNumContextRef,
482 ) -> Result<OpensslString, ErrorStack> {
483 unsafe {
484 let buf = cvt_p(ffi::EC_POINT_point2hex(
485 group.as_ptr(),
486 self.as_ptr(),
487 form.0,
488 ctx.as_ptr(),
489 ))?;
490 Ok(OpensslString::from_ptr(buf))
491 }
492 }
493
494 /// Creates a new point on the specified curve with the same value.
495 #[corresponds(EC_POINT_dup)]
496 pub fn to_owned(&self, group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
497 unsafe { cvt_p(ffi::EC_POINT_dup(self.as_ptr(), group.as_ptr())).map(EcPoint) }
498 }
499
500 /// Determines if this point is equal to another.
501 #[corresponds(EC_POINT_cmp)]
502 pub fn eq(
503 &self,
504 group: &EcGroupRef,
505 other: &EcPointRef,
506 ctx: &mut BigNumContextRef,
507 ) -> Result<bool, ErrorStack> {
508 unsafe {
509 let res = cvt_n(ffi::EC_POINT_cmp(
510 group.as_ptr(),
511 self.as_ptr(),
512 other.as_ptr(),
513 ctx.as_ptr(),
514 ))?;
515 Ok(res == 0)
516 }
517 }
518
519 /// Places affine coordinates of a curve over a prime field in the provided
520 /// `x` and `y` `BigNum`s.
521 #[corresponds(EC_POINT_get_affine_coordinates)]
522 #[cfg(any(ossl111, boringssl, libressl350))]
523 pub fn affine_coordinates(
524 &self,
525 group: &EcGroupRef,
526 x: &mut BigNumRef,
527 y: &mut BigNumRef,
528 ctx: &mut BigNumContextRef,
529 ) -> Result<(), ErrorStack> {
530 unsafe {
531 cvt(ffi::EC_POINT_get_affine_coordinates(
532 group.as_ptr(),
533 self.as_ptr(),
534 x.as_ptr(),
535 y.as_ptr(),
536 ctx.as_ptr(),
537 ))
538 .map(|_| ())
539 }
540 }
541
542 /// Places affine coordinates of a curve over a prime field in the provided
543 /// `x` and `y` `BigNum`s
544 #[corresponds(EC_POINT_get_affine_coordinates_GFp)]
545 pub fn affine_coordinates_gfp(
546 &self,
547 group: &EcGroupRef,
548 x: &mut BigNumRef,
549 y: &mut BigNumRef,
550 ctx: &mut BigNumContextRef,
551 ) -> Result<(), ErrorStack> {
552 unsafe {
553 cvt(ffi::EC_POINT_get_affine_coordinates_GFp(
554 group.as_ptr(),
555 self.as_ptr(),
556 x.as_ptr(),
557 y.as_ptr(),
558 ctx.as_ptr(),
559 ))
560 .map(|_| ())
561 }
562 }
563
564 /// Sets affine coordinates of a curve over a prime field using the provided
565 /// `x` and `y` `BigNum`s
566 #[corresponds(EC_POINT_set_affine_coordinates_GFp)]
567 pub fn set_affine_coordinates_gfp(
568 &mut self,
569 group: &EcGroupRef,
570 x: &BigNumRef,
571 y: &BigNumRef,
572 ctx: &mut BigNumContextRef,
573 ) -> Result<(), ErrorStack> {
574 unsafe {
575 cvt(ffi::EC_POINT_set_affine_coordinates_GFp(
576 group.as_ptr(),
577 self.as_ptr(),
578 x.as_ptr(),
579 y.as_ptr(),
580 ctx.as_ptr(),
581 ))
582 .map(|_| ())
583 }
584 }
585
586 /// Places affine coordinates of a curve over a binary field in the provided
587 /// `x` and `y` `BigNum`s
588 #[corresponds(EC_POINT_get_affine_coordinates_GF2m)]
589 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
590 pub fn affine_coordinates_gf2m(
591 &self,
592 group: &EcGroupRef,
593 x: &mut BigNumRef,
594 y: &mut BigNumRef,
595 ctx: &mut BigNumContextRef,
596 ) -> Result<(), ErrorStack> {
597 unsafe {
598 cvt(ffi::EC_POINT_get_affine_coordinates_GF2m(
599 group.as_ptr(),
600 self.as_ptr(),
601 x.as_ptr(),
602 y.as_ptr(),
603 ctx.as_ptr(),
604 ))
605 .map(|_| ())
606 }
607 }
608
609 /// Checks if point is infinity
610 #[corresponds(EC_POINT_is_at_infinity)]
611 pub fn is_infinity(&self, group: &EcGroupRef) -> bool {
612 unsafe {
613 let res = ffi::EC_POINT_is_at_infinity(group.as_ptr(), self.as_ptr());
614 res == 1
615 }
616 }
617
618 /// Checks if point is on a given curve
619 #[corresponds(EC_POINT_is_on_curve)]
620 pub fn is_on_curve(
621 &self,
622 group: &EcGroupRef,
623 ctx: &mut BigNumContextRef,
624 ) -> Result<bool, ErrorStack> {
625 unsafe {
626 let res = cvt_n(ffi::EC_POINT_is_on_curve(
627 group.as_ptr(),
628 self.as_ptr(),
629 ctx.as_ptr(),
630 ))?;
631 Ok(res == 1)
632 }
633 }
634}
635
636impl EcPoint {
637 /// Creates a new point on the specified curve.
638 #[corresponds(EC_POINT_new)]
639 pub fn new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
640 unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) }
641 }
642
643 /// Creates point from a binary representation
644 #[corresponds(EC_POINT_oct2point)]
645 pub fn from_bytes(
646 group: &EcGroupRef,
647 buf: &[u8],
648 ctx: &mut BigNumContextRef,
649 ) -> Result<EcPoint, ErrorStack> {
650 let point = EcPoint::new(group)?;
651 unsafe {
652 cvt(ffi::EC_POINT_oct2point(
653 group.as_ptr(),
654 point.as_ptr(),
655 buf.as_ptr(),
656 buf.len(),
657 ctx.as_ptr(),
658 ))?;
659 }
660 Ok(point)
661 }
662
663 /// Creates point from a hexadecimal string representation
664 #[corresponds(EC_POINT_hex2point)]
665 #[cfg(not(boringssl))]
666 pub fn from_hex_str(
667 group: &EcGroupRef,
668 s: &str,
669 ctx: &mut BigNumContextRef,
670 ) -> Result<EcPoint, ErrorStack> {
671 let point = EcPoint::new(group)?;
672 unsafe {
673 let c_str = CString::new(s.as_bytes()).unwrap();
674 cvt_p(ffi::EC_POINT_hex2point(
675 group.as_ptr(),
676 c_str.as_ptr() as *const _,
677 point.as_ptr(),
678 ctx.as_ptr(),
679 ))?;
680 }
681 Ok(point)
682 }
683}
684
685generic_foreign_type_and_impl_send_sync! {
686 type CType = ffi::EC_KEY;
687 fn drop = ffi::EC_KEY_free;
688
689 /// Public and optional private key on the given curve.
690 pub struct EcKey<T>;
691 /// A reference to an [`EcKey`].
692 pub struct EcKeyRef<T>;
693}
694
695impl<T> EcKeyRef<T>
696where
697 T: HasPrivate,
698{
699 private_key_to_pem! {
700 /// Serializes the private key to a PEM-encoded ECPrivateKey structure.
701 ///
702 /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`.
703 #[corresponds(PEM_write_bio_ECPrivateKey)]
704 private_key_to_pem,
705 /// Serializes the private key to a PEM-encoded encrypted ECPrivateKey structure.
706 ///
707 /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`.
708 #[corresponds(PEM_write_bio_ECPrivateKey)]
709 private_key_to_pem_passphrase,
710 ffi::PEM_write_bio_ECPrivateKey
711 }
712
713 to_der! {
714 /// Serializes the private key into a DER-encoded ECPrivateKey structure.
715 #[corresponds(i2d_ECPrivateKey)]
716 private_key_to_der,
717 ffi::i2d_ECPrivateKey
718 }
719
720 /// Returns the private key value.
721 #[corresponds(EC_KEY_get0_private_key)]
722 pub fn private_key(&self) -> &BigNumRef {
723 unsafe {
724 let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr());
725 BigNumRef::from_const_ptr(ptr)
726 }
727 }
728}
729
730impl<T> EcKeyRef<T>
731where
732 T: HasPublic,
733{
734 /// Returns the public key.
735 #[corresponds(EC_KEY_get0_public_key)]
736 pub fn public_key(&self) -> &EcPointRef {
737 unsafe {
738 let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr());
739 EcPointRef::from_const_ptr(ptr)
740 }
741 }
742
743 to_pem! {
744 /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure.
745 ///
746 /// The output will have a header of `-----BEGIN PUBLIC KEY-----`.
747 #[corresponds(PEM_write_bio_EC_PUBKEY)]
748 public_key_to_pem,
749 ffi::PEM_write_bio_EC_PUBKEY
750 }
751
752 to_der! {
753 /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure.
754 #[corresponds(i2d_EC_PUBKEY)]
755 public_key_to_der,
756 ffi::i2d_EC_PUBKEY
757 }
758}
759
760impl<T> EcKeyRef<T>
761where
762 T: HasParams,
763{
764 /// Returns the key's group.
765 #[corresponds(EC_KEY_get0_group)]
766 pub fn group(&self) -> &EcGroupRef {
767 unsafe {
768 let ptr: *const EC_GROUP = ffi::EC_KEY_get0_group(self.as_ptr());
769 EcGroupRef::from_const_ptr(ptr)
770 }
771 }
772
773 /// Checks the key for validity.
774 #[corresponds(EC_KEY_check_key)]
775 pub fn check_key(&self) -> Result<(), ErrorStack> {
776 unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) }
777 }
778}
779
780impl<T> ToOwned for EcKeyRef<T> {
781 type Owned = EcKey<T>;
782
783 fn to_owned(&self) -> EcKey<T> {
784 unsafe {
785 let r: i32 = ffi::EC_KEY_up_ref(self.as_ptr());
786 assert!(r == 1);
787 EcKey::from_ptr(self.as_ptr())
788 }
789 }
790}
791
792impl EcKey<Params> {
793 /// Constructs an `EcKey` corresponding to a known curve.
794 ///
795 /// It will not have an associated public or private key. This kind of key is primarily useful
796 /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`.
797 #[corresponds(EC_KEY_new_by_curve_name)]
798 pub fn from_curve_name(nid: Nid) -> Result<EcKey<Params>, ErrorStack> {
799 unsafe {
800 init();
801 cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p))
802 }
803 }
804
805 /// Constructs an `EcKey` corresponding to a curve.
806 #[corresponds(EC_KEY_set_group)]
807 pub fn from_group(group: &EcGroupRef) -> Result<EcKey<Params>, ErrorStack> {
808 unsafe {
809 cvt_p(ffi::EC_KEY_new())
810 .map(|p| EcKey::from_ptr(p))
811 .and_then(|key| {
812 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
813 })
814 }
815 }
816}
817
818impl EcKey<Public> {
819 /// Constructs an `EcKey` from the specified group with the associated [`EcPoint`]: `public_key`.
820 ///
821 /// This will only have the associated `public_key`.
822 ///
823 /// # Example
824 ///
825 /// ```
826 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
827 /// use openssl::bn::BigNumContext;
828 /// use openssl::ec::*;
829 /// use openssl::nid::Nid;
830 /// use openssl::pkey::PKey;
831 ///
832 /// let group = EcGroup::from_curve_name(Nid::SECP384R1)?;
833 /// let mut ctx = BigNumContext::new()?;
834 ///
835 /// // get bytes from somewhere
836 /// let public_key = // ...
837 /// # EcKey::generate(&group)?.public_key().to_bytes(&group,
838 /// # PointConversionForm::COMPRESSED, &mut ctx)?;
839 ///
840 /// // create an EcKey from the binary form of a EcPoint
841 /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx)?;
842 /// let key = EcKey::from_public_key(&group, &point)?;
843 /// key.check_key()?;
844 /// # Ok(()) }
845 /// ```
846 #[corresponds(EC_KEY_set_public_key)]
847 pub fn from_public_key(
848 group: &EcGroupRef,
849 public_key: &EcPointRef,
850 ) -> Result<EcKey<Public>, ErrorStack> {
851 unsafe {
852 cvt_p(ffi::EC_KEY_new())
853 .map(|p| EcKey::from_ptr(p))
854 .and_then(|key| {
855 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
856 })
857 .and_then(|key| {
858 cvt(ffi::EC_KEY_set_public_key(
859 key.as_ptr(),
860 public_key.as_ptr(),
861 ))
862 .map(|_| key)
863 })
864 }
865 }
866
867 /// Constructs a public key from its affine coordinates.
868 #[corresponds(EC_KEY_set_public_key_affine_coordinates)]
869 pub fn from_public_key_affine_coordinates(
870 group: &EcGroupRef,
871 x: &BigNumRef,
872 y: &BigNumRef,
873 ) -> Result<EcKey<Public>, ErrorStack> {
874 unsafe {
875 cvt_p(ffi::EC_KEY_new())
876 .map(|p| EcKey::from_ptr(p))
877 .and_then(|key| {
878 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
879 })
880 .and_then(|key| {
881 cvt(ffi::EC_KEY_set_public_key_affine_coordinates(
882 key.as_ptr(),
883 x.as_ptr(),
884 y.as_ptr(),
885 ))
886 .map(|_| key)
887 })
888 }
889 }
890
891 from_pem! {
892 /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a EC key.
893 ///
894 /// The input should have a header of `-----BEGIN PUBLIC KEY-----`.
895 #[corresponds(PEM_read_bio_EC_PUBKEY)]
896 public_key_from_pem,
897 EcKey<Public>,
898 ffi::PEM_read_bio_EC_PUBKEY
899 }
900
901 from_der! {
902 /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a EC key.
903 #[corresponds(d2i_EC_PUBKEY)]
904 public_key_from_der,
905 EcKey<Public>,
906 ffi::d2i_EC_PUBKEY
907 }
908}
909
910impl EcKey<Private> {
911 /// Generates a new public/private key pair on the specified curve.
912 ///
913 /// # Examples
914 ///
915 /// ```
916 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
917 /// use openssl::bn::BigNumContext;
918 /// use openssl::nid::Nid;
919 /// use openssl::ec::{EcGroup, EcKey, PointConversionForm};
920 ///
921 /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve
922 /// let group = EcGroup::from_curve_name(nid)?;
923 /// let key = EcKey::generate(&group)?;
924 ///
925 /// let mut ctx = BigNumContext::new()?;
926 ///
927 /// let public_key = &key.public_key().to_bytes(
928 /// &group,
929 /// PointConversionForm::COMPRESSED,
930 /// &mut ctx,
931 /// )?;
932 /// assert_eq!(public_key.len(), 33);
933 /// assert_ne!(public_key[0], 0x04);
934 ///
935 /// let private_key = key.private_key().to_vec();
936 /// assert!(private_key.len() >= 31);
937 /// # Ok(()) }
938 /// ```
939 #[corresponds(EC_KEY_generate_key)]
940 pub fn generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack> {
941 unsafe {
942 cvt_p(ffi::EC_KEY_new())
943 .map(|p| EcKey::from_ptr(p))
944 .and_then(|key| {
945 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
946 })
947 .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key))
948 }
949 }
950
951 /// Constructs an public/private key pair given a curve, a private key and a public key point.
952 #[corresponds(EC_KEY_set_private_key)]
953 pub fn from_private_components(
954 group: &EcGroupRef,
955 private_number: &BigNumRef,
956 public_key: &EcPointRef,
957 ) -> Result<EcKey<Private>, ErrorStack> {
958 unsafe {
959 cvt_p(ffi::EC_KEY_new())
960 .map(|p| EcKey::from_ptr(p))
961 .and_then(|key| {
962 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
963 })
964 .and_then(|key| {
965 cvt(ffi::EC_KEY_set_private_key(
966 key.as_ptr(),
967 private_number.as_ptr(),
968 ))
969 .map(|_| key)
970 })
971 .and_then(|key| {
972 cvt(ffi::EC_KEY_set_public_key(
973 key.as_ptr(),
974 public_key.as_ptr(),
975 ))
976 .map(|_| key)
977 })
978 }
979 }
980
981 private_key_from_pem! {
982 /// Deserializes a private key from a PEM-encoded ECPrivateKey structure.
983 ///
984 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
985 #[corresponds(PEM_read_bio_ECPrivateKey)]
986 private_key_from_pem,
987
988 /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure.
989 ///
990 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
991 #[corresponds(PEM_read_bio_ECPrivateKey)]
992 private_key_from_pem_passphrase,
993
994 /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure.
995 ///
996 /// The callback should fill the password into the provided buffer and return its length.
997 ///
998 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
999 #[corresponds(PEM_read_bio_ECPrivateKey)]
1000 private_key_from_pem_callback,
1001 EcKey<Private>,
1002 ffi::PEM_read_bio_ECPrivateKey
1003 }
1004
1005 from_der! {
1006 /// Decodes a DER-encoded elliptic curve private key structure.
1007 #[corresponds(d2i_ECPrivateKey)]
1008 private_key_from_der,
1009 EcKey<Private>,
1010 ffi::d2i_ECPrivateKey
1011 }
1012}
1013
1014impl<T> Clone for EcKey<T> {
1015 fn clone(&self) -> EcKey<T> {
1016 (**self).to_owned()
1017 }
1018}
1019
1020impl<T> fmt::Debug for EcKey<T> {
1021 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1022 write!(f, "EcKey")
1023 }
1024}
1025
1026#[cfg(test)]
1027mod test {
1028 use hex::FromHex;
1029
1030 use super::*;
1031 use crate::bn::{BigNum, BigNumContext};
1032 use crate::nid::Nid;
1033
1034 #[test]
1035 fn key_new_by_curve_name() {
1036 EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1037 }
1038
1039 #[test]
1040 fn generate() {
1041 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1042 EcKey::generate(&group).unwrap();
1043 }
1044
1045 #[test]
1046 fn ec_group_from_components() {
1047 // parameters are from secp256r1
1048 let p = BigNum::from_hex_str(
1049 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1050 )
1051 .unwrap();
1052 let a = BigNum::from_hex_str(
1053 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1054 )
1055 .unwrap();
1056 let b = BigNum::from_hex_str(
1057 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1058 )
1059 .unwrap();
1060 let mut ctx = BigNumContext::new().unwrap();
1061
1062 let _curve = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1063 }
1064
1065 #[test]
1066 fn ec_point_set_affine() {
1067 // parameters are from secp256r1
1068 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1069 let mut ctx = BigNumContext::new().unwrap();
1070 let mut gen_point = EcPoint::new(&group).unwrap();
1071 let gen_x = BigNum::from_hex_str(
1072 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1073 )
1074 .unwrap();
1075 let gen_y = BigNum::from_hex_str(
1076 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1077 )
1078 .unwrap();
1079 gen_point
1080 .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx)
1081 .unwrap();
1082 assert!(gen_point.is_on_curve(&group, &mut ctx).unwrap());
1083 }
1084
1085 #[test]
1086 fn ec_group_set_generator() {
1087 // parameters are from secp256r1
1088 let mut ctx = BigNumContext::new().unwrap();
1089 let p = BigNum::from_hex_str(
1090 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1091 )
1092 .unwrap();
1093 let a = BigNum::from_hex_str(
1094 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1095 )
1096 .unwrap();
1097 let b = BigNum::from_hex_str(
1098 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1099 )
1100 .unwrap();
1101
1102 let mut group = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1103
1104 let mut gen_point = EcPoint::new(&group).unwrap();
1105 let gen_x = BigNum::from_hex_str(
1106 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1107 )
1108 .unwrap();
1109 let gen_y = BigNum::from_hex_str(
1110 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1111 )
1112 .unwrap();
1113 gen_point
1114 .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx)
1115 .unwrap();
1116
1117 let order = BigNum::from_hex_str(
1118 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
1119 )
1120 .unwrap();
1121 let cofactor = BigNum::from_hex_str("01").unwrap();
1122 group.set_generator(gen_point, order, cofactor).unwrap();
1123 let mut constructed_order = BigNum::new().unwrap();
1124 group.order(&mut constructed_order, &mut ctx).unwrap();
1125
1126 let named_group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1127 let mut named_order = BigNum::new().unwrap();
1128 named_group.order(&mut named_order, &mut ctx).unwrap();
1129
1130 assert_eq!(
1131 constructed_order.ucmp(&named_order),
1132 std::cmp::Ordering::Equal
1133 );
1134 }
1135
1136 #[test]
1137 fn cofactor() {
1138 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1139 let mut ctx = BigNumContext::new().unwrap();
1140 let mut cofactor = BigNum::new().unwrap();
1141 group.cofactor(&mut cofactor, &mut ctx).unwrap();
1142 let one = BigNum::from_u32(1).unwrap();
1143 assert_eq!(cofactor, one);
1144 }
1145
1146 #[test]
1147 #[allow(clippy::redundant_clone)]
1148 fn dup() {
1149 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1150 let key = EcKey::generate(&group).unwrap();
1151 drop(key.clone());
1152 }
1153
1154 #[test]
1155 fn point_new() {
1156 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1157 EcPoint::new(&group).unwrap();
1158 }
1159
1160 #[test]
1161 fn point_bytes() {
1162 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1163 let key = EcKey::generate(&group).unwrap();
1164 let point = key.public_key();
1165 let mut ctx = BigNumContext::new().unwrap();
1166 let bytes = point
1167 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1168 .unwrap();
1169 let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1170 assert!(point.eq(&group, &point2, &mut ctx).unwrap());
1171 }
1172
1173 #[test]
1174 #[cfg(not(boringssl))]
1175 fn point_hex_str() {
1176 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1177 let key = EcKey::generate(&group).unwrap();
1178 let point = key.public_key();
1179 let mut ctx = BigNumContext::new().unwrap();
1180 let hex = point
1181 .to_hex_str(&group, PointConversionForm::COMPRESSED, &mut ctx)
1182 .unwrap();
1183 let point2 = EcPoint::from_hex_str(&group, &hex, &mut ctx).unwrap();
1184 assert!(point.eq(&group, &point2, &mut ctx).unwrap());
1185 }
1186
1187 #[test]
1188 fn point_owned() {
1189 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1190 let key = EcKey::generate(&group).unwrap();
1191 let point = key.public_key();
1192 let owned = point.to_owned(&group).unwrap();
1193 let mut ctx = BigNumContext::new().unwrap();
1194 assert!(owned.eq(&group, point, &mut ctx).unwrap());
1195 }
1196
1197 #[test]
1198 fn mul_generator() {
1199 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1200 let key = EcKey::generate(&group).unwrap();
1201 let mut ctx = BigNumContext::new().unwrap();
1202 let mut public_key = EcPoint::new(&group).unwrap();
1203 public_key
1204 .mul_generator(&group, key.private_key(), &ctx)
1205 .unwrap();
1206 assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap());
1207 }
1208
1209 #[test]
1210 fn generator() {
1211 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1212 let gen = group.generator();
1213 let one = BigNum::from_u32(1).unwrap();
1214 let mut ctx = BigNumContext::new().unwrap();
1215 let mut ecp = EcPoint::new(&group).unwrap();
1216 ecp.mul_generator(&group, &one, &ctx).unwrap();
1217 assert!(ecp.eq(&group, gen, &mut ctx).unwrap());
1218 }
1219
1220 #[test]
1221 fn key_from_public_key() {
1222 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1223 let key = EcKey::generate(&group).unwrap();
1224 let mut ctx = BigNumContext::new().unwrap();
1225 let bytes = key
1226 .public_key()
1227 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1228 .unwrap();
1229
1230 drop(key);
1231 let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1232 let ec_key = EcKey::from_public_key(&group, &public_key).unwrap();
1233 assert!(ec_key.check_key().is_ok());
1234 }
1235
1236 #[test]
1237 fn key_from_private_components() {
1238 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1239 let key = EcKey::generate(&group).unwrap();
1240
1241 let dup_key =
1242 EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap();
1243 dup_key.check_key().unwrap();
1244
1245 assert!(key.private_key() == dup_key.private_key());
1246 }
1247
1248 #[test]
1249 fn key_from_affine_coordinates() {
1250 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1251 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1252 .unwrap();
1253 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1254 .unwrap();
1255
1256 let xbn = BigNum::from_slice(&x).unwrap();
1257 let ybn = BigNum::from_slice(&y).unwrap();
1258
1259 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1260 assert!(ec_key.check_key().is_ok());
1261 }
1262
1263 #[cfg(any(ossl111, boringssl, libressl350))]
1264 #[test]
1265 fn get_affine_coordinates() {
1266 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1267 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1268 .unwrap();
1269 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1270 .unwrap();
1271
1272 let xbn = BigNum::from_slice(&x).unwrap();
1273 let ybn = BigNum::from_slice(&y).unwrap();
1274
1275 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1276
1277 let mut xbn2 = BigNum::new().unwrap();
1278 let mut ybn2 = BigNum::new().unwrap();
1279 let mut ctx = BigNumContext::new().unwrap();
1280 let ec_key_pk = ec_key.public_key();
1281 ec_key_pk
1282 .affine_coordinates(&group, &mut xbn2, &mut ybn2, &mut ctx)
1283 .unwrap();
1284 assert_eq!(xbn2, xbn);
1285 assert_eq!(ybn2, ybn);
1286 }
1287
1288 #[test]
1289 fn get_affine_coordinates_gfp() {
1290 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1291 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1292 .unwrap();
1293 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1294 .unwrap();
1295
1296 let xbn = BigNum::from_slice(&x).unwrap();
1297 let ybn = BigNum::from_slice(&y).unwrap();
1298
1299 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1300
1301 let mut xbn2 = BigNum::new().unwrap();
1302 let mut ybn2 = BigNum::new().unwrap();
1303 let mut ctx = BigNumContext::new().unwrap();
1304 let ec_key_pk = ec_key.public_key();
1305 ec_key_pk
1306 .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx)
1307 .unwrap();
1308 assert_eq!(xbn2, xbn);
1309 assert_eq!(ybn2, ybn);
1310 }
1311
1312 #[test]
1313 fn is_infinity() {
1314 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1315 let mut ctx = BigNumContext::new().unwrap();
1316 let g = group.generator();
1317 assert!(!g.is_infinity(&group));
1318
1319 let mut order = BigNum::new().unwrap();
1320 group.order(&mut order, &mut ctx).unwrap();
1321 let mut inf = EcPoint::new(&group).unwrap();
1322 inf.mul_generator(&group, &order, &ctx).unwrap();
1323 assert!(inf.is_infinity(&group));
1324 }
1325
1326 #[test]
1327 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
1328 fn is_on_curve() {
1329 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1330 let mut ctx = BigNumContext::new().unwrap();
1331 let g = group.generator();
1332 assert!(g.is_on_curve(&group, &mut ctx).unwrap());
1333
1334 let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap();
1335 assert!(!g.is_on_curve(&group2, &mut ctx).unwrap());
1336 }
1337
1338 #[test]
1339 #[cfg(any(boringssl, ossl111, libressl350))]
1340 fn asn1_flag() {
1341 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1342 let flag = group.asn1_flag();
1343 assert_eq!(flag, Asn1Flag::NAMED_CURVE);
1344 }
1345}
1346