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