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
18 use cfg_if::cfg_if;
19 use foreign_types::{ForeignType, ForeignTypeRef};
20 use libc::c_int;
21 use std::fmt;
22 use std::ptr;
23 
24 use crate::bn::{BigNum, BigNumContextRef, BigNumRef};
25 use crate::error::ErrorStack;
26 use crate::nid::Nid;
27 use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public};
28 use crate::util::ForeignTypeRefExt;
29 use crate::{cvt, cvt_n, cvt_p, init};
30 use openssl_macros::corresponds;
31 
32 cfg_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)]
49 pub struct PointConversionForm(ffi::point_conversion_form_t);
50 
51 impl 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)]
69 pub struct Asn1Flag(c_int);
70 
71 impl 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 
98 foreign_type_and_impl_send_sync! {
99     type CType = ffi::EC_GROUP;
dropnull100     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 
125 impl 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)]
from_curve_namenull141     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)]
from_componentsnull150     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 
168 impl 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)]
components_gfpnull172     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(any(boringssl, osslconf = "OPENSSL_NO_EC2M")))]
components_gf2mnull199     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)]
cofactornull220     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)]
degreenull237     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)]
order_bitsnull244     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)]
generatornull250     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)]
set_generatornull259     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)]
ordernull278     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)]
set_asn1_flagnull299     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)]
asn1_flagnull307     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)]
curve_namenull313     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 
323 foreign_type_and_impl_send_sync! {
324     type CType = ffi::EC_POINT;
dropnull325     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 
333 impl EcPointRef {
334     /// Computes `a + b`, storing the result in `self`.
335     #[corresponds(EC_POINT_add)]
addnull336     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)]
mulnull357     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)]
mul_generatornull380     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)]
mul_fullnull402     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
invertnull426     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)]
to_bytesnull439     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))]
to_hex_strnull477     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)]
to_ownednull496     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)]
eqnull502     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))]
affine_coordinatesnull523     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)]
affine_coordinates_gfpnull545     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)]
set_affine_coordinates_gfpnull567     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(any(boringssl, osslconf = "OPENSSL_NO_EC2M")))]
affine_coordinates_gf2mnull590     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)]
is_infinitynull611     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)]
is_on_curvenull620     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 
636 impl EcPoint {
637     /// Creates a new point on the specified curve.
638     #[corresponds(EC_POINT_new)]
newnull639     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)]
from_bytesnull645     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))]
from_hex_strnull666     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 
685 generic_foreign_type_and_impl_send_sync! {
686     type CType = ffi::EC_KEY;
dropnull687     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 
695 impl<T> EcKeyRef<T>
696 where
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)]
private_keynull722     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 
730 impl<T> EcKeyRef<T>
731 where
732     T: HasPublic,
733 {
734     /// Returns the public key.
735     #[corresponds(EC_KEY_get0_public_key)]
public_keynull736     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 
760 impl<T> EcKeyRef<T>
761 where
762     T: HasParams,
763 {
764     /// Returns the key's group.
765     #[corresponds(EC_KEY_get0_group)]
groupnull766     pub fn group(&self) -> &EcGroupRef {
767         unsafe {
768             let ptr = 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)]
check_keynull775     pub fn check_key(&self) -> Result<(), ErrorStack> {
776         unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) }
777     }
778 }
779 
780 impl<T> ToOwned for EcKeyRef<T> {
781     type Owned = EcKey<T>;
782 
to_ownednull783     fn to_owned(&self) -> EcKey<T> {
784         unsafe {
785             let r = ffi::EC_KEY_up_ref(self.as_ptr());
786             assert!(r == 1);
787             EcKey::from_ptr(self.as_ptr())
788         }
789     }
790 }
791 
792 impl 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)]
from_curve_namenull798     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)]
from_groupnull807     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 
818 impl 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)]
from_public_keynull847     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)]
from_public_key_affine_coordinatesnull869     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 
910 impl 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)]
generatenull940     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)]
from_private_componentsnull953     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 
1014 impl<T> Clone for EcKey<T> {
clonenull1015     fn clone(&self) -> EcKey<T> {
1016         (**self).to_owned()
1017     }
1018 }
1019 
1020 impl<T> fmt::Debug for EcKey<T> {
fmtnull1021     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1022         write!(f, "EcKey")
1023     }
1024 }
1025 
1026 #[cfg(test)]
1027 mod 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(any(boringssl, 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