variant_ssl/
ec.rs

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