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