• 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/man1.1.0/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     /// Decodes a DER-encoded elliptic curve private key structure for the specified curve.
959     #[corresponds(EC_KEY_parse_private_key)]
960     #[cfg(boringssl)]
private_key_from_der_for_group( der: &[u8], group: &EcGroupRef, ) -> Result<EcKey<Private>, ErrorStack>961     pub fn private_key_from_der_for_group(
962         der: &[u8],
963         group: &EcGroupRef,
964     ) -> Result<EcKey<Private>, ErrorStack> {
965         unsafe {
966             let mut cbs = ffi::CBS {
967                 data: der.as_ptr(),
968                 len: der.len(),
969             };
970             cvt_p(ffi::EC_KEY_parse_private_key(
971                 &mut cbs as *mut ffi::CBS,
972                 group.as_ptr(),
973             ))
974             .map(|p| EcKey::from_ptr(p))
975         }
976     }
977 }
978 
979 impl<T> Clone for EcKey<T> {
clone(&self) -> EcKey<T>980     fn clone(&self) -> EcKey<T> {
981         (**self).to_owned()
982     }
983 }
984 
985 impl<T> fmt::Debug for EcKey<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result986     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
987         write!(f, "EcKey")
988     }
989 }
990 
991 #[cfg(test)]
992 mod test {
993     use hex::FromHex;
994 
995     use super::*;
996     use crate::bn::{BigNum, BigNumContext};
997     use crate::nid::Nid;
998 
999     #[test]
key_new_by_curve_name()1000     fn key_new_by_curve_name() {
1001         EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1002     }
1003 
1004     #[test]
generate()1005     fn generate() {
1006         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1007         EcKey::generate(&group).unwrap();
1008     }
1009 
1010     #[test]
ec_group_from_components()1011     fn ec_group_from_components() {
1012         // parameters are from secp256r1
1013         let p = BigNum::from_hex_str(
1014             "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1015         )
1016         .unwrap();
1017         let a = BigNum::from_hex_str(
1018             "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1019         )
1020         .unwrap();
1021         let b = BigNum::from_hex_str(
1022             "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1023         )
1024         .unwrap();
1025         let mut ctx = BigNumContext::new().unwrap();
1026 
1027         let _curve = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1028     }
1029 
1030     #[test]
ec_point_set_affine()1031     fn ec_point_set_affine() {
1032         // parameters are from secp256r1
1033         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1034         let mut ctx = BigNumContext::new().unwrap();
1035         let mut gen_point = EcPoint::new(&group).unwrap();
1036         let gen_x = BigNum::from_hex_str(
1037             "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1038         )
1039         .unwrap();
1040         let gen_y = BigNum::from_hex_str(
1041             "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1042         )
1043         .unwrap();
1044         gen_point
1045             .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx)
1046             .unwrap();
1047         assert!(gen_point.is_on_curve(&group, &mut ctx).unwrap());
1048     }
1049 
1050     #[test]
ec_group_set_generator()1051     fn ec_group_set_generator() {
1052         // parameters are from secp256r1
1053         let mut ctx = BigNumContext::new().unwrap();
1054         let p = BigNum::from_hex_str(
1055             "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1056         )
1057         .unwrap();
1058         let a = BigNum::from_hex_str(
1059             "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1060         )
1061         .unwrap();
1062         let b = BigNum::from_hex_str(
1063             "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1064         )
1065         .unwrap();
1066 
1067         let mut group = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1068 
1069         let mut gen_point = EcPoint::new(&group).unwrap();
1070         let gen_x = BigNum::from_hex_str(
1071             "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1072         )
1073         .unwrap();
1074         let gen_y = BigNum::from_hex_str(
1075             "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1076         )
1077         .unwrap();
1078         gen_point
1079             .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx)
1080             .unwrap();
1081 
1082         let order = BigNum::from_hex_str(
1083             "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
1084         )
1085         .unwrap();
1086         let cofactor = BigNum::from_hex_str("01").unwrap();
1087         group.set_generator(gen_point, order, cofactor).unwrap();
1088         let mut constructed_order = BigNum::new().unwrap();
1089         group.order(&mut constructed_order, &mut ctx).unwrap();
1090 
1091         let named_group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1092         let mut named_order = BigNum::new().unwrap();
1093         named_group.order(&mut named_order, &mut ctx).unwrap();
1094 
1095         assert_eq!(
1096             constructed_order.ucmp(&named_order),
1097             std::cmp::Ordering::Equal
1098         );
1099     }
1100 
1101     #[test]
cofactor()1102     fn cofactor() {
1103         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1104         let mut ctx = BigNumContext::new().unwrap();
1105         let mut cofactor = BigNum::new().unwrap();
1106         group.cofactor(&mut cofactor, &mut ctx).unwrap();
1107         let one = BigNum::from_u32(1).unwrap();
1108         assert_eq!(cofactor, one);
1109     }
1110 
1111     #[test]
1112     #[allow(clippy::redundant_clone)]
dup()1113     fn dup() {
1114         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1115         let key = EcKey::generate(&group).unwrap();
1116         drop(key.clone());
1117     }
1118 
1119     #[test]
point_new()1120     fn point_new() {
1121         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1122         EcPoint::new(&group).unwrap();
1123     }
1124 
1125     #[test]
point_bytes()1126     fn point_bytes() {
1127         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1128         let key = EcKey::generate(&group).unwrap();
1129         let point = key.public_key();
1130         let mut ctx = BigNumContext::new().unwrap();
1131         let bytes = point
1132             .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1133             .unwrap();
1134         let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1135         assert!(point.eq(&group, &point2, &mut ctx).unwrap());
1136     }
1137 
1138     #[test]
point_owned()1139     fn point_owned() {
1140         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1141         let key = EcKey::generate(&group).unwrap();
1142         let point = key.public_key();
1143         let owned = point.to_owned(&group).unwrap();
1144         let mut ctx = BigNumContext::new().unwrap();
1145         assert!(owned.eq(&group, point, &mut ctx).unwrap());
1146     }
1147 
1148     #[test]
mul_generator()1149     fn mul_generator() {
1150         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1151         let key = EcKey::generate(&group).unwrap();
1152         let mut ctx = BigNumContext::new().unwrap();
1153         let mut public_key = EcPoint::new(&group).unwrap();
1154         public_key
1155             .mul_generator(&group, key.private_key(), &ctx)
1156             .unwrap();
1157         assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap());
1158     }
1159 
1160     #[test]
generator()1161     fn generator() {
1162         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1163         let gen = group.generator();
1164         let one = BigNum::from_u32(1).unwrap();
1165         let mut ctx = BigNumContext::new().unwrap();
1166         let mut ecp = EcPoint::new(&group).unwrap();
1167         ecp.mul_generator(&group, &one, &ctx).unwrap();
1168         assert!(ecp.eq(&group, gen, &mut ctx).unwrap());
1169     }
1170 
1171     #[test]
key_from_public_key()1172     fn key_from_public_key() {
1173         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1174         let key = EcKey::generate(&group).unwrap();
1175         let mut ctx = BigNumContext::new().unwrap();
1176         let bytes = key
1177             .public_key()
1178             .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1179             .unwrap();
1180 
1181         drop(key);
1182         let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1183         let ec_key = EcKey::from_public_key(&group, &public_key).unwrap();
1184         assert!(ec_key.check_key().is_ok());
1185     }
1186 
1187     #[test]
key_from_private_components()1188     fn key_from_private_components() {
1189         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1190         let key = EcKey::generate(&group).unwrap();
1191 
1192         let dup_key =
1193             EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap();
1194         dup_key.check_key().unwrap();
1195 
1196         assert!(key.private_key() == dup_key.private_key());
1197     }
1198 
1199     #[test]
key_from_affine_coordinates()1200     fn key_from_affine_coordinates() {
1201         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1202         let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1203             .unwrap();
1204         let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1205             .unwrap();
1206 
1207         let xbn = BigNum::from_slice(&x).unwrap();
1208         let ybn = BigNum::from_slice(&y).unwrap();
1209 
1210         let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1211         assert!(ec_key.check_key().is_ok());
1212     }
1213 
1214     #[cfg(ossl111)]
1215     #[test]
get_affine_coordinates()1216     fn get_affine_coordinates() {
1217         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1218         let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1219             .unwrap();
1220         let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1221             .unwrap();
1222 
1223         let xbn = BigNum::from_slice(&x).unwrap();
1224         let ybn = BigNum::from_slice(&y).unwrap();
1225 
1226         let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1227 
1228         let mut xbn2 = BigNum::new().unwrap();
1229         let mut ybn2 = BigNum::new().unwrap();
1230         let mut ctx = BigNumContext::new().unwrap();
1231         let ec_key_pk = ec_key.public_key();
1232         ec_key_pk
1233             .affine_coordinates(&group, &mut xbn2, &mut ybn2, &mut ctx)
1234             .unwrap();
1235         assert_eq!(xbn2, xbn);
1236         assert_eq!(ybn2, ybn);
1237     }
1238 
1239     #[test]
get_affine_coordinates_gfp()1240     fn get_affine_coordinates_gfp() {
1241         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1242         let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1243             .unwrap();
1244         let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1245             .unwrap();
1246 
1247         let xbn = BigNum::from_slice(&x).unwrap();
1248         let ybn = BigNum::from_slice(&y).unwrap();
1249 
1250         let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1251 
1252         let mut xbn2 = BigNum::new().unwrap();
1253         let mut ybn2 = BigNum::new().unwrap();
1254         let mut ctx = BigNumContext::new().unwrap();
1255         let ec_key_pk = ec_key.public_key();
1256         ec_key_pk
1257             .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx)
1258             .unwrap();
1259         assert_eq!(xbn2, xbn);
1260         assert_eq!(ybn2, ybn);
1261     }
1262 
1263     #[test]
is_infinity()1264     fn is_infinity() {
1265         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1266         let mut ctx = BigNumContext::new().unwrap();
1267         let g = group.generator();
1268         assert!(!g.is_infinity(&group));
1269 
1270         let mut order = BigNum::new().unwrap();
1271         group.order(&mut order, &mut ctx).unwrap();
1272         let mut inf = EcPoint::new(&group).unwrap();
1273         inf.mul_generator(&group, &order, &ctx).unwrap();
1274         assert!(inf.is_infinity(&group));
1275     }
1276 
1277     #[test]
1278     #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_EC2M")))]
is_on_curve()1279     fn is_on_curve() {
1280         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1281         let mut ctx = BigNumContext::new().unwrap();
1282         let g = group.generator();
1283         assert!(g.is_on_curve(&group, &mut ctx).unwrap());
1284 
1285         let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap();
1286         assert!(!g.is_on_curve(&group2, &mut ctx).unwrap());
1287     }
1288 }
1289