1use 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#[derive(Copy, Clone)]
49pub struct PointConversionForm(ffi::point_conversion_form_t);
50
51impl PointConversionForm {
52 pub const COMPRESSED: PointConversionForm =
54 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED);
55
56 pub const UNCOMPRESSED: PointConversionForm =
58 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED);
59
60 pub const HYBRID: PointConversionForm =
62 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID);
63}
64
65#[derive(Copy, Clone, Debug, PartialEq)]
69pub struct Asn1Flag(c_int);
70
71impl Asn1Flag {
72 pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0);
86
87 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 pub struct EcGroup;
119 pub struct EcGroupRef;
123}
124
125impl EcGroup {
126 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[corresponds(EC_GROUP_get0_generator)]
261 #[deprecated(
262 since = "0.10.79",
263 note = "Panics if the group has no generator. Use generator_opt instead."
264 )]
265 pub fn generator(&self) -> &EcPointRef {
266 self.generator_opt().expect("EC_GROUP has no generator set")
267 }
268
269 #[corresponds(EC_GROUP_get0_generator)]
272 pub fn generator_opt(&self) -> Option<&EcPointRef> {
273 unsafe {
274 let ptr = ffi::EC_GROUP_get0_generator(self.as_ptr());
275 EcPointRef::from_const_ptr_opt(ptr)
276 }
277 }
278
279 #[corresponds(EC_GROUP_set_generator)]
281 pub fn set_generator(
282 &mut self,
283 generator: EcPoint,
284 order: BigNum,
285 cofactor: BigNum,
286 ) -> Result<(), ErrorStack> {
287 unsafe {
288 cvt(ffi::EC_GROUP_set_generator(
289 self.as_ptr(),
290 generator.as_ptr(),
291 order.as_ptr(),
292 cofactor.as_ptr(),
293 ))
294 .map(|_| ())
295 }
296 }
297
298 #[corresponds(EC_GROUP_get_order)]
300 pub fn order(
301 &self,
302 order: &mut BigNumRef,
303 ctx: &mut BigNumContextRef,
304 ) -> Result<(), ErrorStack> {
305 unsafe {
306 cvt(ffi::EC_GROUP_get_order(
307 self.as_ptr(),
308 order.as_ptr(),
309 ctx.as_ptr(),
310 ))
311 .map(|_| ())
312 }
313 }
314
315 #[corresponds(EC_GROUP_set_asn1_flag)]
321 pub fn set_asn1_flag(&mut self, flag: Asn1Flag) {
322 unsafe {
323 ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0);
324 }
325 }
326
327 #[corresponds(EC_GROUP_get_asn1_flag)]
329 pub fn asn1_flag(&self) -> Asn1Flag {
330 unsafe { Asn1Flag(ffi::EC_GROUP_get_asn1_flag(self.as_ptr())) }
331 }
332
333 #[corresponds(EC_GROUP_get_curve_name)]
335 pub fn curve_name(&self) -> Option<Nid> {
336 let nid = unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) };
337 if nid > 0 {
338 Some(Nid::from_raw(nid))
339 } else {
340 None
341 }
342 }
343}
344
345impl fmt::Debug for EcGroupRef {
346 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
347 if let Some(curve_name) = self.curve_name() {
348 if let Ok(name) = curve_name.short_name() {
349 f.debug_struct("EcGroup")
350 .field("curve_name", &name)
351 .finish()
352 } else {
353 f.debug_struct("EcGroup")
354 .field("curve", &curve_name)
355 .finish()
356 }
357 } else {
358 if let Ok(mut p) = BigNum::new() {
360 if let Ok(mut a) = BigNum::new() {
361 if let Ok(mut b) = BigNum::new() {
362 if let Ok(mut ctx) = BigNumContext::new() {
363 if self
364 .components_gfp(&mut p, &mut a, &mut b, &mut ctx)
365 .is_ok()
366 {
367 return f
369 .debug_struct("EcGroup")
370 .field("p", &format!("{:X}", p))
371 .field("a", &format!("{:X}", a))
372 .field("b", &format!("{:X}", b))
373 .finish();
374 }
375 }
376 }
377 }
378 }
379
380 f.debug_struct("EcGroup").finish()
381 }
382 }
383}
384
385foreign_type_and_impl_send_sync! {
386 type CType = ffi::EC_POINT;
387 fn drop = ffi::EC_POINT_free;
388
389 pub struct EcPoint;
391 pub struct EcPointRef;
393}
394
395impl EcPointRef {
396 #[corresponds(EC_POINT_add)]
398 pub fn add(
399 &mut self,
400 group: &EcGroupRef,
401 a: &EcPointRef,
402 b: &EcPointRef,
403 ctx: &mut BigNumContextRef,
404 ) -> Result<(), ErrorStack> {
405 unsafe {
406 cvt(ffi::EC_POINT_add(
407 group.as_ptr(),
408 self.as_ptr(),
409 a.as_ptr(),
410 b.as_ptr(),
411 ctx.as_ptr(),
412 ))
413 .map(|_| ())
414 }
415 }
416
417 #[corresponds(EC_POINT_mul)]
424 #[deprecated(
425 since = "0.10.79",
426 note = "Unsound: ctx is mutated internally. Use mul2 instead."
427 )]
428 pub fn mul(
429 &mut self,
430 group: &EcGroupRef,
431 q: &EcPointRef,
432 m: &BigNumRef,
433 ctx: &BigNumContextRef,
434 ) -> Result<(), ErrorStack> {
435 unsafe {
436 cvt(ffi::EC_POINT_mul(
437 group.as_ptr(),
438 self.as_ptr(),
439 ptr::null(),
440 q.as_ptr(),
441 m.as_ptr(),
442 ctx.as_ptr(),
443 ))
444 .map(|_| ())
445 }
446 }
447
448 #[corresponds(EC_POINT_mul)]
450 pub fn mul2(
451 &mut self,
452 group: &EcGroupRef,
453 q: &EcPointRef,
454 m: &BigNumRef,
455 ctx: &mut BigNumContextRef,
456 ) -> Result<(), ErrorStack> {
457 unsafe {
458 cvt(ffi::EC_POINT_mul(
459 group.as_ptr(),
460 self.as_ptr(),
461 ptr::null(),
462 q.as_ptr(),
463 m.as_ptr(),
464 ctx.as_ptr(),
465 ))
466 .map(|_| ())
467 }
468 }
469
470 #[corresponds(EC_POINT_mul)]
477 #[deprecated(
478 since = "0.10.79",
479 note = "Unsound: ctx is mutated internally. Use mul_generator2 instead."
480 )]
481 pub fn mul_generator(
482 &mut self,
483 group: &EcGroupRef,
484 n: &BigNumRef,
485 ctx: &BigNumContextRef,
486 ) -> Result<(), ErrorStack> {
487 unsafe {
488 cvt(ffi::EC_POINT_mul(
489 group.as_ptr(),
490 self.as_ptr(),
491 n.as_ptr(),
492 ptr::null(),
493 ptr::null(),
494 ctx.as_ptr(),
495 ))
496 .map(|_| ())
497 }
498 }
499
500 #[corresponds(EC_POINT_mul)]
502 pub fn mul_generator2(
503 &mut self,
504 group: &EcGroupRef,
505 n: &BigNumRef,
506 ctx: &mut BigNumContextRef,
507 ) -> Result<(), ErrorStack> {
508 unsafe {
509 cvt(ffi::EC_POINT_mul(
510 group.as_ptr(),
511 self.as_ptr(),
512 n.as_ptr(),
513 ptr::null(),
514 ptr::null(),
515 ctx.as_ptr(),
516 ))
517 .map(|_| ())
518 }
519 }
520
521 #[corresponds(EC_POINT_mul)]
523 pub fn mul_full(
524 &mut self,
525 group: &EcGroupRef,
526 n: &BigNumRef,
527 q: &EcPointRef,
528 m: &BigNumRef,
529 ctx: &mut BigNumContextRef,
530 ) -> Result<(), ErrorStack> {
531 unsafe {
532 cvt(ffi::EC_POINT_mul(
533 group.as_ptr(),
534 self.as_ptr(),
535 n.as_ptr(),
536 q.as_ptr(),
537 m.as_ptr(),
538 ctx.as_ptr(),
539 ))
540 .map(|_| ())
541 }
542 }
543
544 #[corresponds(EC_POINT_invert)]
551 #[deprecated(
552 since = "0.10.79",
553 note = "Unsound: ctx is mutated internally. Use invert2 instead."
554 )]
555 pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> {
556 unsafe {
557 cvt(ffi::EC_POINT_invert(
558 group.as_ptr(),
559 self.as_ptr(),
560 ctx.as_ptr(),
561 ))
562 .map(|_| ())
563 }
564 }
565
566 #[corresponds(EC_POINT_invert)]
568 pub fn invert2(
569 &mut self,
570 group: &EcGroupRef,
571 ctx: &mut BigNumContextRef,
572 ) -> Result<(), ErrorStack> {
573 unsafe {
574 cvt(ffi::EC_POINT_invert(
575 group.as_ptr(),
576 self.as_ptr(),
577 ctx.as_ptr(),
578 ))
579 .map(|_| ())
580 }
581 }
582
583 #[corresponds(EC_POINT_point2oct)]
585 pub fn to_bytes(
586 &self,
587 group: &EcGroupRef,
588 form: PointConversionForm,
589 ctx: &mut BigNumContextRef,
590 ) -> Result<Vec<u8>, ErrorStack> {
591 unsafe {
592 let len = ffi::EC_POINT_point2oct(
593 group.as_ptr(),
594 self.as_ptr(),
595 form.0,
596 ptr::null_mut(),
597 0,
598 ctx.as_ptr(),
599 );
600 if len == 0 {
601 return Err(ErrorStack::get());
602 }
603 let mut buf = vec![0; len];
604 let len = ffi::EC_POINT_point2oct(
605 group.as_ptr(),
606 self.as_ptr(),
607 form.0,
608 buf.as_mut_ptr(),
609 len,
610 ctx.as_ptr(),
611 );
612 if len == 0 {
613 Err(ErrorStack::get())
614 } else {
615 Ok(buf)
616 }
617 }
618 }
619
620 #[corresponds(EC_POINT_point2hex)]
622 #[cfg(not(any(boringssl, awslc)))]
623 pub fn to_hex_str(
624 &self,
625 group: &EcGroupRef,
626 form: PointConversionForm,
627 ctx: &mut BigNumContextRef,
628 ) -> Result<OpensslString, ErrorStack> {
629 unsafe {
630 let buf = cvt_p(ffi::EC_POINT_point2hex(
631 group.as_ptr(),
632 self.as_ptr(),
633 form.0,
634 ctx.as_ptr(),
635 ))?;
636 Ok(OpensslString::from_ptr(buf))
637 }
638 }
639
640 #[corresponds(EC_POINT_dup)]
642 pub fn to_owned(&self, group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
643 unsafe { cvt_p(ffi::EC_POINT_dup(self.as_ptr(), group.as_ptr())).map(EcPoint) }
644 }
645
646 #[corresponds(EC_POINT_cmp)]
648 pub fn eq(
649 &self,
650 group: &EcGroupRef,
651 other: &EcPointRef,
652 ctx: &mut BigNumContextRef,
653 ) -> Result<bool, ErrorStack> {
654 unsafe {
655 let res = cvt_n(ffi::EC_POINT_cmp(
656 group.as_ptr(),
657 self.as_ptr(),
658 other.as_ptr(),
659 ctx.as_ptr(),
660 ))?;
661 Ok(res == 0)
662 }
663 }
664
665 #[corresponds(EC_POINT_get_affine_coordinates)]
668 #[cfg(any(ossl111, boringssl, libressl, awslc))]
669 pub fn affine_coordinates(
670 &self,
671 group: &EcGroupRef,
672 x: &mut BigNumRef,
673 y: &mut BigNumRef,
674 ctx: &mut BigNumContextRef,
675 ) -> Result<(), ErrorStack> {
676 unsafe {
677 cvt(ffi::EC_POINT_get_affine_coordinates(
678 group.as_ptr(),
679 self.as_ptr(),
680 x.as_ptr(),
681 y.as_ptr(),
682 ctx.as_ptr(),
683 ))
684 .map(|_| ())
685 }
686 }
687
688 #[corresponds(EC_POINT_get_affine_coordinates_GFp)]
691 pub fn affine_coordinates_gfp(
692 &self,
693 group: &EcGroupRef,
694 x: &mut BigNumRef,
695 y: &mut BigNumRef,
696 ctx: &mut BigNumContextRef,
697 ) -> Result<(), ErrorStack> {
698 unsafe {
699 cvt(ffi::EC_POINT_get_affine_coordinates_GFp(
700 group.as_ptr(),
701 self.as_ptr(),
702 x.as_ptr(),
703 y.as_ptr(),
704 ctx.as_ptr(),
705 ))
706 .map(|_| ())
707 }
708 }
709
710 #[corresponds(EC_POINT_set_affine_coordinates)]
713 #[cfg(any(ossl111, boringssl, libressl, awslc))]
714 pub fn set_affine_coordinates(
715 &mut self,
716 group: &EcGroupRef,
717 x: &BigNumRef,
718 y: &BigNumRef,
719 ctx: &mut BigNumContextRef,
720 ) -> Result<(), ErrorStack> {
721 unsafe {
722 cvt(ffi::EC_POINT_set_affine_coordinates(
723 group.as_ptr(),
724 self.as_ptr(),
725 x.as_ptr(),
726 y.as_ptr(),
727 ctx.as_ptr(),
728 ))
729 .map(|_| ())
730 }
731 }
732
733 #[corresponds(EC_POINT_set_affine_coordinates_GFp)]
736 pub fn set_affine_coordinates_gfp(
737 &mut self,
738 group: &EcGroupRef,
739 x: &BigNumRef,
740 y: &BigNumRef,
741 ctx: &mut BigNumContextRef,
742 ) -> Result<(), ErrorStack> {
743 unsafe {
744 cvt(ffi::EC_POINT_set_affine_coordinates_GFp(
745 group.as_ptr(),
746 self.as_ptr(),
747 x.as_ptr(),
748 y.as_ptr(),
749 ctx.as_ptr(),
750 ))
751 .map(|_| ())
752 }
753 }
754
755 #[corresponds(EC_POINT_get_affine_coordinates_GF2m)]
758 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
759 pub fn affine_coordinates_gf2m(
760 &self,
761 group: &EcGroupRef,
762 x: &mut BigNumRef,
763 y: &mut BigNumRef,
764 ctx: &mut BigNumContextRef,
765 ) -> Result<(), ErrorStack> {
766 unsafe {
767 cvt(ffi::EC_POINT_get_affine_coordinates_GF2m(
768 group.as_ptr(),
769 self.as_ptr(),
770 x.as_ptr(),
771 y.as_ptr(),
772 ctx.as_ptr(),
773 ))
774 .map(|_| ())
775 }
776 }
777
778 #[corresponds(EC_POINT_is_at_infinity)]
780 pub fn is_infinity(&self, group: &EcGroupRef) -> bool {
781 unsafe {
782 let res = ffi::EC_POINT_is_at_infinity(group.as_ptr(), self.as_ptr());
783 res == 1
784 }
785 }
786
787 #[corresponds(EC_POINT_is_on_curve)]
789 pub fn is_on_curve(
790 &self,
791 group: &EcGroupRef,
792 ctx: &mut BigNumContextRef,
793 ) -> Result<bool, ErrorStack> {
794 unsafe {
795 let res = cvt_n(ffi::EC_POINT_is_on_curve(
796 group.as_ptr(),
797 self.as_ptr(),
798 ctx.as_ptr(),
799 ))?;
800 Ok(res == 1)
801 }
802 }
803}
804
805impl EcPoint {
806 #[corresponds(EC_POINT_new)]
808 pub fn new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
809 unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) }
810 }
811
812 #[corresponds(EC_POINT_oct2point)]
814 pub fn from_bytes(
815 group: &EcGroupRef,
816 buf: &[u8],
817 ctx: &mut BigNumContextRef,
818 ) -> Result<EcPoint, ErrorStack> {
819 let point = EcPoint::new(group)?;
820 unsafe {
821 cvt(ffi::EC_POINT_oct2point(
822 group.as_ptr(),
823 point.as_ptr(),
824 buf.as_ptr(),
825 buf.len(),
826 ctx.as_ptr(),
827 ))?;
828 }
829 Ok(point)
830 }
831
832 #[corresponds(EC_POINT_hex2point)]
834 #[cfg(not(any(boringssl, awslc)))]
835 pub fn from_hex_str(
836 group: &EcGroupRef,
837 s: &str,
838 ctx: &mut BigNumContextRef,
839 ) -> Result<EcPoint, ErrorStack> {
840 let point = EcPoint::new(group)?;
841 unsafe {
842 let c_str = CString::new(s.as_bytes()).unwrap();
843 cvt_p(ffi::EC_POINT_hex2point(
844 group.as_ptr(),
845 c_str.as_ptr() as *const _,
846 point.as_ptr(),
847 ctx.as_ptr(),
848 ))?;
849 }
850 Ok(point)
851 }
852}
853
854generic_foreign_type_and_impl_send_sync! {
855 type CType = ffi::EC_KEY;
856 fn drop = ffi::EC_KEY_free;
857
858 pub struct EcKey<T>;
860 pub struct EcKeyRef<T>;
862}
863
864impl<T> EcKeyRef<T>
865where
866 T: HasPrivate,
867{
868 private_key_to_pem! {
869 #[corresponds(PEM_write_bio_ECPrivateKey)]
873 private_key_to_pem,
874 #[corresponds(PEM_write_bio_ECPrivateKey)]
878 private_key_to_pem_passphrase,
879 ffi::PEM_write_bio_ECPrivateKey
880 }
881
882 to_der! {
883 #[corresponds(i2d_ECPrivateKey)]
885 private_key_to_der,
886 ffi::i2d_ECPrivateKey
887 }
888
889 #[corresponds(EC_KEY_get0_private_key)]
891 pub fn private_key(&self) -> &BigNumRef {
892 unsafe {
893 let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr());
894 BigNumRef::from_const_ptr(ptr)
895 }
896 }
897}
898
899impl<T> EcKeyRef<T>
900where
901 T: HasPublic,
902{
903 #[corresponds(EC_KEY_get0_public_key)]
905 pub fn public_key(&self) -> &EcPointRef {
906 unsafe {
907 let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr());
908 EcPointRef::from_const_ptr(ptr)
909 }
910 }
911
912 to_pem! {
913 #[corresponds(PEM_write_bio_EC_PUBKEY)]
917 public_key_to_pem,
918 ffi::PEM_write_bio_EC_PUBKEY
919 }
920
921 to_der! {
922 #[corresponds(i2d_EC_PUBKEY)]
924 public_key_to_der,
925 ffi::i2d_EC_PUBKEY
926 }
927}
928
929impl<T> EcKeyRef<T>
930where
931 T: HasParams,
932{
933 #[corresponds(EC_KEY_get0_group)]
935 pub fn group(&self) -> &EcGroupRef {
936 unsafe {
937 let ptr = ffi::EC_KEY_get0_group(self.as_ptr());
938 EcGroupRef::from_const_ptr(ptr)
939 }
940 }
941
942 #[corresponds(EC_KEY_check_key)]
944 pub fn check_key(&self) -> Result<(), ErrorStack> {
945 unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) }
946 }
947}
948
949impl<T> ToOwned for EcKeyRef<T> {
950 type Owned = EcKey<T>;
951
952 fn to_owned(&self) -> EcKey<T> {
953 unsafe {
954 let r = ffi::EC_KEY_up_ref(self.as_ptr());
955 assert!(r == 1);
956 EcKey::from_ptr(self.as_ptr())
957 }
958 }
959}
960
961impl EcKey<Params> {
962 #[corresponds(EC_KEY_new_by_curve_name)]
967 pub fn from_curve_name(nid: Nid) -> Result<EcKey<Params>, ErrorStack> {
968 unsafe {
969 init();
970 cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p))
971 }
972 }
973
974 #[corresponds(EC_KEY_set_group)]
976 pub fn from_group(group: &EcGroupRef) -> Result<EcKey<Params>, ErrorStack> {
977 unsafe {
978 cvt_p(ffi::EC_KEY_new())
979 .map(|p| EcKey::from_ptr(p))
980 .and_then(|key| {
981 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
982 })
983 }
984 }
985}
986
987impl EcKey<Public> {
988 #[corresponds(EC_KEY_set_public_key)]
1016 pub fn from_public_key(
1017 group: &EcGroupRef,
1018 public_key: &EcPointRef,
1019 ) -> Result<EcKey<Public>, ErrorStack> {
1020 unsafe {
1021 cvt_p(ffi::EC_KEY_new())
1022 .map(|p| EcKey::from_ptr(p))
1023 .and_then(|key| {
1024 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
1025 })
1026 .and_then(|key| {
1027 cvt(ffi::EC_KEY_set_public_key(
1028 key.as_ptr(),
1029 public_key.as_ptr(),
1030 ))
1031 .map(|_| key)
1032 })
1033 }
1034 }
1035
1036 #[corresponds(EC_KEY_set_public_key_affine_coordinates)]
1038 pub fn from_public_key_affine_coordinates(
1039 group: &EcGroupRef,
1040 x: &BigNumRef,
1041 y: &BigNumRef,
1042 ) -> Result<EcKey<Public>, ErrorStack> {
1043 unsafe {
1044 cvt_p(ffi::EC_KEY_new())
1045 .map(|p| EcKey::from_ptr(p))
1046 .and_then(|key| {
1047 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
1048 })
1049 .and_then(|key| {
1050 cvt(ffi::EC_KEY_set_public_key_affine_coordinates(
1051 key.as_ptr(),
1052 x.as_ptr(),
1053 y.as_ptr(),
1054 ))
1055 .map(|_| key)
1056 })
1057 }
1058 }
1059
1060 from_pem! {
1061 #[corresponds(PEM_read_bio_EC_PUBKEY)]
1065 public_key_from_pem,
1066 EcKey<Public>,
1067 ffi::PEM_read_bio_EC_PUBKEY
1068 }
1069
1070 from_der! {
1071 #[corresponds(d2i_EC_PUBKEY)]
1073 public_key_from_der,
1074 EcKey<Public>,
1075 ffi::d2i_EC_PUBKEY
1076 }
1077}
1078
1079impl EcKey<Private> {
1080 #[corresponds(EC_KEY_generate_key)]
1109 pub fn generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack> {
1110 unsafe {
1111 cvt_p(ffi::EC_KEY_new())
1112 .map(|p| EcKey::from_ptr(p))
1113 .and_then(|key| {
1114 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
1115 })
1116 .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key))
1117 }
1118 }
1119
1120 #[corresponds(EC_KEY_set_private_key)]
1122 pub fn from_private_components(
1123 group: &EcGroupRef,
1124 private_number: &BigNumRef,
1125 public_key: &EcPointRef,
1126 ) -> Result<EcKey<Private>, ErrorStack> {
1127 unsafe {
1128 cvt_p(ffi::EC_KEY_new())
1129 .map(|p| EcKey::from_ptr(p))
1130 .and_then(|key| {
1131 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
1132 })
1133 .and_then(|key| {
1134 cvt(ffi::EC_KEY_set_private_key(
1135 key.as_ptr(),
1136 private_number.as_ptr(),
1137 ))
1138 .map(|_| key)
1139 })
1140 .and_then(|key| {
1141 cvt(ffi::EC_KEY_set_public_key(
1142 key.as_ptr(),
1143 public_key.as_ptr(),
1144 ))
1145 .map(|_| key)
1146 })
1147 }
1148 }
1149
1150 private_key_from_pem! {
1151 #[corresponds(PEM_read_bio_ECPrivateKey)]
1155 private_key_from_pem,
1156
1157 #[corresponds(PEM_read_bio_ECPrivateKey)]
1161 private_key_from_pem_passphrase,
1162
1163 #[corresponds(PEM_read_bio_ECPrivateKey)]
1169 private_key_from_pem_callback,
1170 EcKey<Private>,
1171 ffi::PEM_read_bio_ECPrivateKey
1172 }
1173
1174 from_der! {
1175 #[corresponds(d2i_ECPrivateKey)]
1177 private_key_from_der,
1178 EcKey<Private>,
1179 ffi::d2i_ECPrivateKey
1180 }
1181}
1182
1183impl<T> Clone for EcKey<T> {
1184 fn clone(&self) -> EcKey<T> {
1185 (**self).to_owned()
1186 }
1187}
1188
1189impl<T> fmt::Debug for EcKey<T> {
1190 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1191 write!(f, "EcKey")
1192 }
1193}
1194
1195#[cfg(test)]
1196mod test {
1197 use hex::FromHex;
1198
1199 use super::*;
1200 use crate::bn::{BigNum, BigNumContext};
1201 use crate::nid::Nid;
1202 use crate::symm::Cipher;
1203
1204 #[test]
1205 fn key_new_by_curve_name() {
1206 EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1207 }
1208
1209 #[test]
1210 fn generate() {
1211 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1212 EcKey::generate(&group).unwrap();
1213 }
1214
1215 #[test]
1216 fn test_password_callback_oversize_return_is_rejected() {
1217 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1222 let key = EcKey::generate(&group).unwrap();
1223 let encrypted = key
1224 .private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"correct-pw")
1225 .unwrap();
1226
1227 let result = EcKey::private_key_from_pem_callback(&encrypted, |buf| {
1228 buf[..10].copy_from_slice(b"correct-pw");
1229 Ok(buf.len() * 10)
1230 });
1231 assert!(result.is_err());
1232 }
1233
1234 #[test]
1235 fn ec_group_from_components() {
1236 let p = BigNum::from_hex_str(
1238 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1239 )
1240 .unwrap();
1241 let a = BigNum::from_hex_str(
1242 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1243 )
1244 .unwrap();
1245 let b = BigNum::from_hex_str(
1246 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1247 )
1248 .unwrap();
1249 let mut ctx = BigNumContext::new().unwrap();
1250
1251 let _curve = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1252 }
1253
1254 fn set_affine_coords_test(
1255 set_affine_coords: fn(
1256 &mut EcPointRef,
1257 &EcGroupRef,
1258 &BigNumRef,
1259 &BigNumRef,
1260 &mut BigNumContextRef,
1261 ) -> Result<(), ErrorStack>,
1262 ) {
1263 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1265 let mut ctx = BigNumContext::new().unwrap();
1266 let mut gen_point = EcPoint::new(&group).unwrap();
1267 let gen_x = BigNum::from_hex_str(
1268 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1269 )
1270 .unwrap();
1271 let gen_y = BigNum::from_hex_str(
1272 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1273 )
1274 .unwrap();
1275 set_affine_coords(&mut gen_point, &group, &gen_x, &gen_y, &mut ctx).unwrap();
1276
1277 assert!(gen_point.is_on_curve(&group, &mut ctx).unwrap());
1278 }
1279
1280 #[test]
1281 fn ec_point_set_affine_gfp() {
1282 set_affine_coords_test(EcPointRef::set_affine_coordinates_gfp)
1283 }
1284
1285 #[test]
1286 #[cfg(any(ossl111, boringssl, libressl, awslc))]
1287 fn ec_point_set_affine() {
1288 set_affine_coords_test(EcPointRef::set_affine_coordinates)
1289 }
1290
1291 #[test]
1292 fn ec_group_set_generator() {
1293 let mut ctx = BigNumContext::new().unwrap();
1295 let p = BigNum::from_hex_str(
1296 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1297 )
1298 .unwrap();
1299 let a = BigNum::from_hex_str(
1300 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1301 )
1302 .unwrap();
1303 let b = BigNum::from_hex_str(
1304 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1305 )
1306 .unwrap();
1307
1308 let mut group = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1309
1310 let mut gen_point = EcPoint::new(&group).unwrap();
1311 let gen_x = BigNum::from_hex_str(
1312 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1313 )
1314 .unwrap();
1315 let gen_y = BigNum::from_hex_str(
1316 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1317 )
1318 .unwrap();
1319 gen_point
1320 .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx)
1321 .unwrap();
1322
1323 let order = BigNum::from_hex_str(
1324 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
1325 )
1326 .unwrap();
1327 let cofactor = BigNum::from_hex_str("01").unwrap();
1328 group.set_generator(gen_point, order, cofactor).unwrap();
1329 let mut constructed_order = BigNum::new().unwrap();
1330 group.order(&mut constructed_order, &mut ctx).unwrap();
1331
1332 let named_group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1333 let mut named_order = BigNum::new().unwrap();
1334 named_group.order(&mut named_order, &mut ctx).unwrap();
1335
1336 assert_eq!(
1337 constructed_order.ucmp(&named_order),
1338 std::cmp::Ordering::Equal
1339 );
1340 }
1341
1342 #[test]
1343 fn cofactor() {
1344 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1345 let mut ctx = BigNumContext::new().unwrap();
1346 let mut cofactor = BigNum::new().unwrap();
1347 group.cofactor(&mut cofactor, &mut ctx).unwrap();
1348 let one = BigNum::from_u32(1).unwrap();
1349 assert_eq!(cofactor, one);
1350 }
1351
1352 #[test]
1353 #[allow(clippy::redundant_clone)]
1354 fn dup() {
1355 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1356 let key = EcKey::generate(&group).unwrap();
1357 drop(key.clone());
1358 }
1359
1360 #[test]
1361 fn point_new() {
1362 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1363 EcPoint::new(&group).unwrap();
1364 }
1365
1366 #[test]
1367 fn point_bytes() {
1368 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1369 let key = EcKey::generate(&group).unwrap();
1370 let point = key.public_key();
1371 let mut ctx = BigNumContext::new().unwrap();
1372 let bytes = point
1373 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1374 .unwrap();
1375 let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1376 assert!(point.eq(&group, &point2, &mut ctx).unwrap());
1377 }
1378
1379 #[test]
1380 #[cfg(not(any(boringssl, awslc)))]
1381 fn point_hex_str() {
1382 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1383 let key = EcKey::generate(&group).unwrap();
1384 let point = key.public_key();
1385 let mut ctx = BigNumContext::new().unwrap();
1386 let hex = point
1387 .to_hex_str(&group, PointConversionForm::COMPRESSED, &mut ctx)
1388 .unwrap();
1389 let point2 = EcPoint::from_hex_str(&group, &hex, &mut ctx).unwrap();
1390 assert!(point.eq(&group, &point2, &mut ctx).unwrap());
1391 }
1392
1393 #[test]
1394 fn point_owned() {
1395 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1396 let key = EcKey::generate(&group).unwrap();
1397 let point = key.public_key();
1398 let owned = point.to_owned(&group).unwrap();
1399 let mut ctx = BigNumContext::new().unwrap();
1400 assert!(owned.eq(&group, point, &mut ctx).unwrap());
1401 }
1402
1403 #[test]
1404 fn mul_generator() {
1405 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1406 let key = EcKey::generate(&group).unwrap();
1407 let mut ctx = BigNumContext::new().unwrap();
1408 let mut public_key = EcPoint::new(&group).unwrap();
1409 public_key
1410 .mul_generator2(&group, key.private_key(), &mut ctx)
1411 .unwrap();
1412 assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap());
1413 }
1414
1415 #[test]
1416 fn generator() {
1417 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1418 let gen = group.generator_opt().unwrap();
1419 let one = BigNum::from_u32(1).unwrap();
1420 let mut ctx = BigNumContext::new().unwrap();
1421 let mut ecp = EcPoint::new(&group).unwrap();
1422 ecp.mul_generator2(&group, &one, &mut ctx).unwrap();
1423 assert!(ecp.eq(&group, gen, &mut ctx).unwrap());
1424 }
1425
1426 #[test]
1427 fn generator_opt_none_on_custom_group() {
1428 let p = BigNum::from_hex_str(
1430 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1431 )
1432 .unwrap();
1433 let a = BigNum::from_hex_str(
1434 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1435 )
1436 .unwrap();
1437 let b = BigNum::from_hex_str(
1438 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1439 )
1440 .unwrap();
1441 let mut ctx = BigNumContext::new().unwrap();
1442
1443 let mut group = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1444 assert!(group.generator_opt().is_none());
1445
1446 let mut gen_point = EcPoint::new(&group).unwrap();
1447 let gen_x = BigNum::from_hex_str(
1448 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1449 )
1450 .unwrap();
1451 let gen_y = BigNum::from_hex_str(
1452 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1453 )
1454 .unwrap();
1455 gen_point
1456 .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx)
1457 .unwrap();
1458 let order = BigNum::from_hex_str(
1459 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
1460 )
1461 .unwrap();
1462 let cofactor = BigNum::from_hex_str("01").unwrap();
1463 group.set_generator(gen_point, order, cofactor).unwrap();
1464
1465 assert!(group.generator_opt().is_some());
1466 }
1467
1468 #[test]
1469 #[should_panic(expected = "EC_GROUP has no generator set")]
1470 #[allow(deprecated)]
1471 fn generator_panics_on_custom_group() {
1472 let p = BigNum::from_hex_str(
1474 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1475 )
1476 .unwrap();
1477 let a = BigNum::from_hex_str(
1478 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1479 )
1480 .unwrap();
1481 let b = BigNum::from_hex_str(
1482 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1483 )
1484 .unwrap();
1485 let mut ctx = BigNumContext::new().unwrap();
1486
1487 let group = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1488 let _ = group.generator();
1489 }
1490
1491 #[test]
1492 fn key_from_public_key() {
1493 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1494 let key = EcKey::generate(&group).unwrap();
1495 let mut ctx = BigNumContext::new().unwrap();
1496 let bytes = key
1497 .public_key()
1498 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1499 .unwrap();
1500
1501 drop(key);
1502 let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1503 let ec_key = EcKey::from_public_key(&group, &public_key).unwrap();
1504 assert!(ec_key.check_key().is_ok());
1505 }
1506
1507 #[test]
1508 fn key_from_private_components() {
1509 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1510 let key = EcKey::generate(&group).unwrap();
1511
1512 let dup_key =
1513 EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap();
1514 dup_key.check_key().unwrap();
1515
1516 assert!(key.private_key() == dup_key.private_key());
1517 }
1518
1519 #[test]
1520 fn key_from_affine_coordinates() {
1521 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1522 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1523 .unwrap();
1524 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1525 .unwrap();
1526
1527 let xbn = BigNum::from_slice(&x).unwrap();
1528 let ybn = BigNum::from_slice(&y).unwrap();
1529
1530 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1531 assert!(ec_key.check_key().is_ok());
1532 }
1533
1534 #[cfg(any(ossl111, boringssl, libressl, awslc))]
1535 #[test]
1536 fn get_affine_coordinates() {
1537 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1538 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1539 .unwrap();
1540 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1541 .unwrap();
1542
1543 let xbn = BigNum::from_slice(&x).unwrap();
1544 let ybn = BigNum::from_slice(&y).unwrap();
1545
1546 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1547
1548 let mut xbn2 = BigNum::new().unwrap();
1549 let mut ybn2 = BigNum::new().unwrap();
1550 let mut ctx = BigNumContext::new().unwrap();
1551 let ec_key_pk = ec_key.public_key();
1552 ec_key_pk
1553 .affine_coordinates(&group, &mut xbn2, &mut ybn2, &mut ctx)
1554 .unwrap();
1555 assert_eq!(xbn2, xbn);
1556 assert_eq!(ybn2, ybn);
1557 }
1558
1559 #[test]
1560 fn get_affine_coordinates_gfp() {
1561 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1562 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1563 .unwrap();
1564 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1565 .unwrap();
1566
1567 let xbn = BigNum::from_slice(&x).unwrap();
1568 let ybn = BigNum::from_slice(&y).unwrap();
1569
1570 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1571
1572 let mut xbn2 = BigNum::new().unwrap();
1573 let mut ybn2 = BigNum::new().unwrap();
1574 let mut ctx = BigNumContext::new().unwrap();
1575 let ec_key_pk = ec_key.public_key();
1576 ec_key_pk
1577 .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx)
1578 .unwrap();
1579 assert_eq!(xbn2, xbn);
1580 assert_eq!(ybn2, ybn);
1581 }
1582
1583 #[test]
1584 fn is_infinity() {
1585 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1586 let mut ctx = BigNumContext::new().unwrap();
1587 let g = group.generator_opt().unwrap();
1588 assert!(!g.is_infinity(&group));
1589
1590 let mut order = BigNum::new().unwrap();
1591 group.order(&mut order, &mut ctx).unwrap();
1592 let mut inf = EcPoint::new(&group).unwrap();
1593 inf.mul_generator2(&group, &order, &mut ctx).unwrap();
1594 assert!(inf.is_infinity(&group));
1595 }
1596
1597 #[test]
1598 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
1599 fn is_on_curve() {
1600 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1601 let mut ctx = BigNumContext::new().unwrap();
1602 let g = group.generator_opt().unwrap();
1603 assert!(g.is_on_curve(&group, &mut ctx).unwrap());
1604
1605 let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap();
1606 assert!(!g.is_on_curve(&group2, &mut ctx).unwrap());
1607 }
1608
1609 #[test]
1610 #[cfg(any(ossl111, boringssl, libressl, awslc))]
1611 fn asn1_flag() {
1612 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1613 let flag = group.asn1_flag();
1614 assert_eq!(flag, Asn1Flag::NAMED_CURVE);
1615 }
1616
1617 #[test]
1618 fn test_debug_standard_group() {
1619 let group = EcGroup::from_curve_name(Nid::SECP521R1).unwrap();
1620
1621 assert_eq!(
1622 format!("{:?}", group),
1623 "EcGroup { curve_name: \"secp521r1\" }"
1624 );
1625 }
1626
1627 #[test]
1628 fn test_debug_custom_group() {
1629 let mut p = BigNum::new().unwrap();
1630 let mut a = BigNum::new().unwrap();
1631 let mut b = BigNum::new().unwrap();
1632 let mut ctx = BigNumContext::new().unwrap();
1633
1634 EcGroup::from_curve_name(Nid::SECP521R1)
1635 .unwrap()
1636 .components_gfp(&mut p, &mut a, &mut b, &mut ctx)
1637 .unwrap();
1638
1639 let group = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1641
1642 assert_eq!(
1643 format!("{:?}", group),
1644 "EcGroup { p: \"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", a: \"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC\", b: \"51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00\" }"
1645 );
1646 }
1647}