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 prefered.
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_GFp`]
484     ///
485     /// [`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>486     pub fn affine_coordinates_gfp(
487         &self,
488         group: &EcGroupRef,
489         x: &mut BigNumRef,
490         y: &mut BigNumRef,
491         ctx: &mut BigNumContextRef,
492     ) -> Result<(), ErrorStack> {
493         unsafe {
494             cvt(ffi::EC_POINT_get_affine_coordinates_GFp(
495                 group.as_ptr(),
496                 self.as_ptr(),
497                 x.as_ptr(),
498                 y.as_ptr(),
499                 ctx.as_ptr(),
500             ))
501             .map(|_| ())
502         }
503     }
504 
505     /// Place affine coordinates of a curve over a binary field in the provided
506     /// `x` and `y` `BigNum`s
507     ///
508     /// OpenSSL documentation at [`EC_POINT_get_affine_coordinates_GF2m`]
509     ///
510     /// [`EC_POINT_get_affine_coordinates_GF2m`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_get_affine_coordinates_GF2m.html
511     #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
affine_coordinates_gf2m( &self, group: &EcGroupRef, x: &mut BigNumRef, y: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>512     pub fn affine_coordinates_gf2m(
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_GF2m(
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     /// Checks if point is infinity
532     ///
533     /// OpenSSL documentation at [`EC_POINT_is_at_infinity`]
534     ///
535     /// [`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) -> bool536     pub fn is_infinity(&self, group: &EcGroupRef) -> bool {
537         unsafe {
538             let res = ffi::EC_POINT_is_at_infinity(group.as_ptr(), self.as_ptr());
539             res == 1
540         }
541     }
542 
543     /// Checks if point is on a given curve
544     ///
545     /// OpenSSL documentation at [`EC_POINT_is_on_curve`]
546     ///
547     /// [`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>548     pub fn is_on_curve(
549         &self,
550         group: &EcGroupRef,
551         ctx: &mut BigNumContextRef,
552     ) -> Result<bool, ErrorStack> {
553         unsafe {
554             let res = cvt_n(ffi::EC_POINT_is_on_curve(
555                 group.as_ptr(),
556                 self.as_ptr(),
557                 ctx.as_ptr(),
558             ))?;
559             Ok(res == 1)
560         }
561     }
562 }
563 
564 impl EcPoint {
565     /// Creates a new point on the specified curve.
566     ///
567     /// OpenSSL documentation at [`EC_POINT_new`]
568     ///
569     /// [`EC_POINT_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_new.html
new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack>570     pub fn new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
571         unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) }
572     }
573 
574     /// Creates point from a binary representation
575     ///
576     /// OpenSSL documentation at [`EC_POINT_oct2point`]
577     ///
578     /// [`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>579     pub fn from_bytes(
580         group: &EcGroupRef,
581         buf: &[u8],
582         ctx: &mut BigNumContextRef,
583     ) -> Result<EcPoint, ErrorStack> {
584         let point = EcPoint::new(group)?;
585         unsafe {
586             cvt(ffi::EC_POINT_oct2point(
587                 group.as_ptr(),
588                 point.as_ptr(),
589                 buf.as_ptr(),
590                 buf.len(),
591                 ctx.as_ptr(),
592             ))?;
593         }
594         Ok(point)
595     }
596 }
597 
598 generic_foreign_type_and_impl_send_sync! {
599     type CType = ffi::EC_KEY;
600     fn drop = ffi::EC_KEY_free;
601 
602     /// Public and optional Private key on the given curve
603     ///
604     /// OpenSSL documentation at [`EC_KEY_new`]
605     ///
606     /// [`EC_KEY_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new.html
607     pub struct EcKey<T>;
608 
609     /// Reference to [`EcKey`]
610     ///
611     /// [`EcKey`]: struct.EcKey.html
612     pub struct EcKeyRef<T>;
613 }
614 
615 impl<T> EcKeyRef<T>
616 where
617     T: HasPrivate,
618 {
619     private_key_to_pem! {
620         /// Serializes the private key to a PEM-encoded ECPrivateKey structure.
621         ///
622         /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`.
623         ///
624         /// This corresponds to [`PEM_write_bio_ECPrivateKey`].
625         ///
626         /// [`PEM_write_bio_ECPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_ECPrivateKey.html
627         private_key_to_pem,
628         /// Serializes the private key to a PEM-encoded encrypted ECPrivateKey structure.
629         ///
630         /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`.
631         ///
632         /// This corresponds to [`PEM_write_bio_ECPrivateKey`].
633         ///
634         /// [`PEM_write_bio_ECPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_ECPrivateKey.html
635         private_key_to_pem_passphrase,
636         ffi::PEM_write_bio_ECPrivateKey
637     }
638 
639     to_der! {
640         /// Serializes the private key into a DER-encoded ECPrivateKey structure.
641         ///
642         /// This corresponds to [`i2d_ECPrivateKey`].
643         ///
644         /// [`i2d_ECPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_ECPrivate_key.html
645         private_key_to_der,
646         ffi::i2d_ECPrivateKey
647     }
648 
649     /// Return [`EcPoint`] associated with the private key
650     ///
651     /// OpenSSL documentation at [`EC_KEY_get0_private_key`]
652     ///
653     /// [`EC_KEY_get0_private_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_private_key.html
private_key(&self) -> &BigNumRef654     pub fn private_key(&self) -> &BigNumRef {
655         unsafe {
656             let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr());
657             BigNumRef::from_const_ptr(ptr)
658         }
659     }
660 }
661 
662 impl<T> EcKeyRef<T>
663 where
664     T: HasPublic,
665 {
666     /// Returns the public key.
667     ///
668     /// OpenSSL documentation at [`EC_KEY_get0_public_key`]
669     ///
670     /// [`EC_KEY_get0_public_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_public_key.html
public_key(&self) -> &EcPointRef671     pub fn public_key(&self) -> &EcPointRef {
672         unsafe {
673             let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr());
674             EcPointRef::from_const_ptr(ptr)
675         }
676     }
677 
678     to_pem! {
679         /// Serialies the public key into a PEM-encoded SubjectPublicKeyInfo structure.
680         ///
681         /// The output will have a header of `-----BEGIN PUBLIC KEY-----`.
682         ///
683         /// This corresponds to [`PEM_write_bio_EC_PUBKEY`].
684         ///
685         /// [`PEM_write_bio_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_EC_PUBKEY.html
686         public_key_to_pem,
687         ffi::PEM_write_bio_EC_PUBKEY
688     }
689 
690     to_der! {
691         /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure.
692         ///
693         /// This corresponds to [`i2d_EC_PUBKEY`].
694         ///
695         /// [`i2d_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_EC_PUBKEY.html
696         public_key_to_der,
697         ffi::i2d_EC_PUBKEY
698     }
699 }
700 
701 impl<T> EcKeyRef<T>
702 where
703     T: HasParams,
704 {
705     /// Return [`EcGroup`] of the `EcKey`
706     ///
707     /// OpenSSL documentation at [`EC_KEY_get0_group`]
708     ///
709     /// [`EC_KEY_get0_group`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_group.html
group(&self) -> &EcGroupRef710     pub fn group(&self) -> &EcGroupRef {
711         unsafe {
712             let ptr = ffi::EC_KEY_get0_group(self.as_ptr());
713             EcGroupRef::from_const_ptr(ptr)
714         }
715     }
716 
717     /// Checks the key for validity.
718     ///
719     /// OpenSSL documenation at [`EC_KEY_check_key`]
720     ///
721     /// [`EC_KEY_check_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_check_key.html
check_key(&self) -> Result<(), ErrorStack>722     pub fn check_key(&self) -> Result<(), ErrorStack> {
723         unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) }
724     }
725 }
726 
727 impl<T> ToOwned for EcKeyRef<T> {
728     type Owned = EcKey<T>;
729 
to_owned(&self) -> EcKey<T>730     fn to_owned(&self) -> EcKey<T> {
731         unsafe {
732             let r = ffi::EC_KEY_up_ref(self.as_ptr());
733             assert!(r == 1);
734             EcKey::from_ptr(self.as_ptr())
735         }
736     }
737 }
738 
739 impl EcKey<Params> {
740     /// Constructs an `EcKey` corresponding to a known curve.
741     ///
742     /// It will not have an associated public or private key. This kind of key is primarily useful
743     /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`.
744     ///
745     /// OpenSSL documenation at [`EC_KEY_new_by_curve_name`]
746     ///
747     /// [`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>748     pub fn from_curve_name(nid: Nid) -> Result<EcKey<Params>, ErrorStack> {
749         unsafe {
750             init();
751             cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p))
752         }
753     }
754 
755     /// Constructs an `EcKey` corresponding to a curve.
756     ///
757     /// This corresponds to [`EC_KEY_set_group`].
758     ///
759     /// [`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>760     pub fn from_group(group: &EcGroupRef) -> Result<EcKey<Params>, ErrorStack> {
761         unsafe {
762             cvt_p(ffi::EC_KEY_new())
763                 .map(|p| EcKey::from_ptr(p))
764                 .and_then(|key| {
765                     cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
766                 })
767         }
768     }
769 }
770 
771 impl EcKey<Public> {
772     /// Constructs an `EcKey` from the specified group with the associated `EcPoint`, public_key.
773     ///
774     /// This will only have the associated public_key.
775     ///
776     /// # Example
777     ///
778     /// ```no_run
779     /// use openssl::bn::BigNumContext;
780     /// use openssl::ec::*;
781     /// use openssl::nid::Nid;
782     /// use openssl::pkey::PKey;
783     ///
784     /// // get bytes from somewhere, i.e. this will not produce a valid key
785     /// let public_key: Vec<u8> = vec![];
786     ///
787     /// // create an EcKey from the binary form of a EcPoint
788     /// let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
789     /// let mut ctx = BigNumContext::new().unwrap();
790     /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx).unwrap();
791     /// let key = EcKey::from_public_key(&group, &point);
792     /// ```
from_public_key( group: &EcGroupRef, public_key: &EcPointRef, ) -> Result<EcKey<Public>, ErrorStack>793     pub fn from_public_key(
794         group: &EcGroupRef,
795         public_key: &EcPointRef,
796     ) -> Result<EcKey<Public>, ErrorStack> {
797         unsafe {
798             cvt_p(ffi::EC_KEY_new())
799                 .map(|p| EcKey::from_ptr(p))
800                 .and_then(|key| {
801                     cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
802                 })
803                 .and_then(|key| {
804                     cvt(ffi::EC_KEY_set_public_key(
805                         key.as_ptr(),
806                         public_key.as_ptr(),
807                     ))
808                     .map(|_| key)
809                 })
810         }
811     }
812 
813     /// Constructs a public key from its 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         ///
841         /// This corresponds to [`PEM_read_bio_EC_PUBKEY`].
842         ///
843         /// [`PEM_read_bio_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_EC_PUBKEY.html
844         public_key_from_pem,
845         EcKey<Public>,
846         ffi::PEM_read_bio_EC_PUBKEY
847     }
848 
849     from_der! {
850         /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a EC key.
851         ///
852         /// This corresponds to [`d2i_EC_PUBKEY`].
853         ///
854         /// [`d2i_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_EC_PUBKEY.html
855         public_key_from_der,
856         EcKey<Public>,
857         ffi::d2i_EC_PUBKEY
858     }
859 }
860 
861 impl EcKey<Private> {
862     /// Generates a new public/private key pair on the specified curve.
generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack>863     pub fn generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack> {
864         unsafe {
865             cvt_p(ffi::EC_KEY_new())
866                 .map(|p| EcKey::from_ptr(p))
867                 .and_then(|key| {
868                     cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
869                 })
870                 .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key))
871         }
872     }
873 
874     /// 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>875     pub fn from_private_components(
876         group: &EcGroupRef,
877         private_number: &BigNumRef,
878         public_key: &EcPointRef,
879     ) -> Result<EcKey<Private>, ErrorStack> {
880         unsafe {
881             cvt_p(ffi::EC_KEY_new())
882                 .map(|p| EcKey::from_ptr(p))
883                 .and_then(|key| {
884                     cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
885                 })
886                 .and_then(|key| {
887                     cvt(ffi::EC_KEY_set_private_key(
888                         key.as_ptr(),
889                         private_number.as_ptr(),
890                     ))
891                     .map(|_| key)
892                 })
893                 .and_then(|key| {
894                     cvt(ffi::EC_KEY_set_public_key(
895                         key.as_ptr(),
896                         public_key.as_ptr(),
897                     ))
898                     .map(|_| key)
899                 })
900         }
901     }
902 
903     private_key_from_pem! {
904         /// Deserializes a private key from a PEM-encoded ECPrivateKey structure.
905         ///
906         /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
907         ///
908         /// This corresponds to `PEM_read_bio_ECPrivateKey`.
909         private_key_from_pem,
910 
911         /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure.
912         ///
913         /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
914         ///
915         /// This corresponds to `PEM_read_bio_ECPrivateKey`.
916         private_key_from_pem_passphrase,
917 
918         /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure.
919         ///
920         /// The callback should fill the password into the provided buffer and return its length.
921         ///
922         /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
923         ///
924         /// This corresponds to `PEM_read_bio_ECPrivateKey`.
925         private_key_from_pem_callback,
926         EcKey<Private>,
927         ffi::PEM_read_bio_ECPrivateKey
928     }
929 
930     from_der! {
931         /// Decodes a DER-encoded elliptic curve private key structure.
932         ///
933         /// This corresponds to [`d2i_ECPrivateKey`].
934         ///
935         /// [`d2i_ECPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_ECPrivate_key.html
936         private_key_from_der,
937         EcKey<Private>,
938         ffi::d2i_ECPrivateKey
939     }
940 }
941 
942 impl<T> Clone for EcKey<T> {
clone(&self) -> EcKey<T>943     fn clone(&self) -> EcKey<T> {
944         (**self).to_owned()
945     }
946 }
947 
948 impl<T> fmt::Debug for EcKey<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result949     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
950         write!(f, "EcKey")
951     }
952 }
953 
954 #[cfg(test)]
955 mod test {
956     use hex::FromHex;
957 
958     use super::*;
959     use crate::bn::{BigNum, BigNumContext};
960     use crate::nid::Nid;
961 
962     #[test]
key_new_by_curve_name()963     fn key_new_by_curve_name() {
964         EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
965     }
966 
967     #[test]
generate()968     fn generate() {
969         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
970         EcKey::generate(&group).unwrap();
971     }
972 
973     #[test]
cofactor()974     fn cofactor() {
975         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
976         let mut ctx = BigNumContext::new().unwrap();
977         let mut cofactor = BigNum::new().unwrap();
978         group.cofactor(&mut cofactor, &mut ctx).unwrap();
979         let one = BigNum::from_u32(1).unwrap();
980         assert_eq!(cofactor, one);
981     }
982 
983     #[test]
984     #[allow(clippy::redundant_clone)]
dup()985     fn dup() {
986         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
987         let key = EcKey::generate(&group).unwrap();
988         drop(key.clone());
989     }
990 
991     #[test]
point_new()992     fn point_new() {
993         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
994         EcPoint::new(&group).unwrap();
995     }
996 
997     #[test]
point_bytes()998     fn point_bytes() {
999         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1000         let key = EcKey::generate(&group).unwrap();
1001         let point = key.public_key();
1002         let mut ctx = BigNumContext::new().unwrap();
1003         let bytes = point
1004             .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1005             .unwrap();
1006         let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1007         assert!(point.eq(&group, &point2, &mut ctx).unwrap());
1008     }
1009 
1010     #[test]
point_owned()1011     fn point_owned() {
1012         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1013         let key = EcKey::generate(&group).unwrap();
1014         let point = key.public_key();
1015         let owned = point.to_owned(&group).unwrap();
1016         let mut ctx = BigNumContext::new().unwrap();
1017         assert!(owned.eq(&group, point, &mut ctx).unwrap());
1018     }
1019 
1020     #[test]
mul_generator()1021     fn mul_generator() {
1022         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1023         let key = EcKey::generate(&group).unwrap();
1024         let mut ctx = BigNumContext::new().unwrap();
1025         let mut public_key = EcPoint::new(&group).unwrap();
1026         public_key
1027             .mul_generator(&group, key.private_key(), &ctx)
1028             .unwrap();
1029         assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap());
1030     }
1031 
1032     #[test]
generator()1033     fn generator() {
1034         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1035         let gen = group.generator();
1036         let one = BigNum::from_u32(1).unwrap();
1037         let mut ctx = BigNumContext::new().unwrap();
1038         let mut ecp = EcPoint::new(&group).unwrap();
1039         ecp.mul_generator(&group, &one, &ctx).unwrap();
1040         assert!(ecp.eq(&group, gen, &mut ctx).unwrap());
1041     }
1042 
1043     #[test]
key_from_public_key()1044     fn key_from_public_key() {
1045         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1046         let key = EcKey::generate(&group).unwrap();
1047         let mut ctx = BigNumContext::new().unwrap();
1048         let bytes = key
1049             .public_key()
1050             .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1051             .unwrap();
1052 
1053         drop(key);
1054         let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1055         let ec_key = EcKey::from_public_key(&group, &public_key).unwrap();
1056         assert!(ec_key.check_key().is_ok());
1057     }
1058 
1059     #[test]
key_from_private_components()1060     fn key_from_private_components() {
1061         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1062         let key = EcKey::generate(&group).unwrap();
1063 
1064         let dup_key =
1065             EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap();
1066         dup_key.check_key().unwrap();
1067 
1068         assert!(key.private_key() == dup_key.private_key());
1069     }
1070 
1071     #[test]
key_from_affine_coordinates()1072     fn key_from_affine_coordinates() {
1073         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1074         let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1075             .unwrap();
1076         let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1077             .unwrap();
1078 
1079         let xbn = BigNum::from_slice(&x).unwrap();
1080         let ybn = BigNum::from_slice(&y).unwrap();
1081 
1082         let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1083         assert!(ec_key.check_key().is_ok());
1084     }
1085 
1086     #[test]
get_affine_coordinates()1087     fn get_affine_coordinates() {
1088         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1089         let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1090             .unwrap();
1091         let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1092             .unwrap();
1093 
1094         let xbn = BigNum::from_slice(&x).unwrap();
1095         let ybn = BigNum::from_slice(&y).unwrap();
1096 
1097         let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1098 
1099         let mut xbn2 = BigNum::new().unwrap();
1100         let mut ybn2 = BigNum::new().unwrap();
1101         let mut ctx = BigNumContext::new().unwrap();
1102         let ec_key_pk = ec_key.public_key();
1103         ec_key_pk
1104             .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx)
1105             .unwrap();
1106         assert_eq!(xbn2, xbn);
1107         assert_eq!(ybn2, ybn);
1108     }
1109 
1110     #[test]
is_infinity()1111     fn is_infinity() {
1112         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1113         let mut ctx = BigNumContext::new().unwrap();
1114         let g = group.generator();
1115         assert_eq!(g.is_infinity(&group), false);
1116 
1117         let mut order = BigNum::new().unwrap();
1118         group.order(&mut order, &mut ctx).unwrap();
1119         let mut inf = EcPoint::new(&group).unwrap();
1120         inf.mul_generator(&group, &order, &ctx).unwrap();
1121         assert_eq!(inf.is_infinity(&group), true);
1122     }
1123 
1124     #[test]
is_on_curve()1125     fn is_on_curve() {
1126         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1127         let mut ctx = BigNumContext::new().unwrap();
1128         let g = group.generator();
1129         assert_eq!(g.is_on_curve(&group, &mut ctx).unwrap(), true);
1130 
1131         let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap();
1132         assert_eq!(g.is_on_curve(&group2, &mut ctx).unwrap(), false);
1133     }
1134 }
1135