1use crate::ffi;
19use foreign_types::{ForeignType, ForeignTypeRef};
20use libc::c_int;
21use openssl_macros::corresponds;
22use std::fmt;
23use std::ptr;
24
25use crate::bn::{BigNumContextRef, BigNumRef};
26use crate::error::ErrorStack;
27use crate::nid::Nid;
28use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public};
29use crate::{cvt, cvt_n, cvt_p, init};
30
31#[derive(Copy, Clone)]
41pub struct PointConversionForm(ffi::point_conversion_form_t);
42
43impl PointConversionForm {
44 pub const COMPRESSED: PointConversionForm =
46 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED);
47
48 pub const UNCOMPRESSED: PointConversionForm =
50 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED);
51
52 pub const HYBRID: PointConversionForm =
54 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID);
55}
56
57#[derive(Copy, Clone)]
61pub struct Asn1Flag(c_int);
62
63impl Asn1Flag {
64 pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0);
78
79 pub const NAMED_CURVE: Asn1Flag = Asn1Flag(ffi::OPENSSL_EC_NAMED_CURVE);
88}
89
90foreign_type_and_impl_send_sync! {
91 type CType = ffi::EC_GROUP;
92 fn drop = ffi::EC_GROUP_free;
93
94 pub struct EcGroup;
111}
112
113impl EcGroup {
114 #[corresponds(EC_GROUP_new)]
116 pub fn from_curve_name(nid: Nid) -> Result<EcGroup, ErrorStack> {
117 unsafe {
118 init();
119 cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(|p| EcGroup::from_ptr(p))
120 }
121 }
122}
123
124impl EcGroupRef {
125 pub fn components_gfp(
132 &self,
133 p: &mut BigNumRef,
134 a: &mut BigNumRef,
135 b: &mut BigNumRef,
136 ctx: &mut BigNumContextRef,
137 ) -> Result<(), ErrorStack> {
138 unsafe {
139 cvt(ffi::EC_GROUP_get_curve_GFp(
140 self.as_ptr(),
141 p.as_ptr(),
142 a.as_ptr(),
143 b.as_ptr(),
144 ctx.as_ptr(),
145 ))
146 .map(|_| ())
147 }
148 }
149
150 #[corresponds(EC_GROUP_get_cofactor)]
152 pub fn cofactor(
153 &self,
154 cofactor: &mut BigNumRef,
155 ctx: &mut BigNumContextRef,
156 ) -> Result<(), ErrorStack> {
157 unsafe {
158 cvt(ffi::EC_GROUP_get_cofactor(
159 self.as_ptr(),
160 cofactor.as_ptr(),
161 ctx.as_ptr(),
162 ))
163 .map(|_| ())
164 }
165 }
166
167 #[corresponds(EC_GROUP_get_degree)]
169 #[allow(clippy::unnecessary_cast)]
170 pub fn degree(&self) -> u32 {
171 unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 }
172 }
173
174 #[corresponds(EC_GROUP_order_bits)]
176 pub fn order_bits(&self) -> u32 {
177 unsafe { ffi::EC_GROUP_order_bits(self.as_ptr()) as u32 }
178 }
179
180 #[corresponds(EC_GROUP_get0_generator)]
182 pub fn generator(&self) -> &EcPointRef {
183 unsafe {
184 let ptr = ffi::EC_GROUP_get0_generator(self.as_ptr());
185 EcPointRef::from_ptr(ptr as *mut _)
186 }
187 }
188
189 #[corresponds(EC_GROUP_get_order)]
191 pub fn order(
192 &self,
193 order: &mut BigNumRef,
194 ctx: &mut BigNumContextRef,
195 ) -> Result<(), ErrorStack> {
196 unsafe {
197 cvt(ffi::EC_GROUP_get_order(
198 self.as_ptr(),
199 order.as_ptr(),
200 ctx.as_ptr(),
201 ))
202 .map(|_| ())
203 }
204 }
205
206 pub fn set_asn1_flag(&mut self, flag: Asn1Flag) {
212 unsafe {
213 ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0);
214 }
215 }
216
217 #[corresponds(EC_GROUP_get_curve_name)]
219 pub fn curve_name(&self) -> Option<Nid> {
220 let nid = unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) };
221 if nid > 0 {
222 Some(Nid::from_raw(nid))
223 } else {
224 None
225 }
226 }
227}
228
229foreign_type_and_impl_send_sync! {
230 type CType = ffi::EC_POINT;
231 fn drop = ffi::EC_POINT_free;
232
233 pub struct EcPoint;
239}
240
241impl EcPointRef {
242 #[corresponds(EC_POINT_add)]
244 pub fn add(
245 &mut self,
246 group: &EcGroupRef,
247 a: &EcPointRef,
248 b: &EcPointRef,
249 ctx: &mut BigNumContextRef,
250 ) -> Result<(), ErrorStack> {
251 unsafe {
252 cvt(ffi::EC_POINT_add(
253 group.as_ptr(),
254 self.as_ptr(),
255 a.as_ptr(),
256 b.as_ptr(),
257 ctx.as_ptr(),
258 ))
259 .map(|_| ())
260 }
261 }
262
263 #[corresponds(EC_POINT_mul)]
265 pub fn mul(
266 &mut self,
267 group: &EcGroupRef,
268 q: &EcPointRef,
269 m: &BigNumRef,
270 ctx: &BigNumContextRef,
272 ) -> Result<(), ErrorStack> {
273 unsafe {
274 cvt(ffi::EC_POINT_mul(
275 group.as_ptr(),
276 self.as_ptr(),
277 ptr::null(),
278 q.as_ptr(),
279 m.as_ptr(),
280 ctx.as_ptr(),
281 ))
282 .map(|_| ())
283 }
284 }
285
286 pub fn mul_generator(
288 &mut self,
289 group: &EcGroupRef,
290 n: &BigNumRef,
291 ctx: &BigNumContextRef,
293 ) -> Result<(), ErrorStack> {
294 unsafe {
295 cvt(ffi::EC_POINT_mul(
296 group.as_ptr(),
297 self.as_ptr(),
298 n.as_ptr(),
299 ptr::null(),
300 ptr::null(),
301 ctx.as_ptr(),
302 ))
303 .map(|_| ())
304 }
305 }
306
307 pub fn mul_full(
309 &mut self,
310 group: &EcGroupRef,
311 n: &BigNumRef,
312 q: &EcPointRef,
313 m: &BigNumRef,
314 ctx: &mut BigNumContextRef,
315 ) -> Result<(), ErrorStack> {
316 unsafe {
317 cvt(ffi::EC_POINT_mul(
318 group.as_ptr(),
319 self.as_ptr(),
320 n.as_ptr(),
321 q.as_ptr(),
322 m.as_ptr(),
323 ctx.as_ptr(),
324 ))
325 .map(|_| ())
326 }
327 }
328
329 #[corresponds(EC_POINT_invert)]
331 pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> {
332 unsafe {
333 cvt(ffi::EC_POINT_invert(
334 group.as_ptr(),
335 self.as_ptr(),
336 ctx.as_ptr(),
337 ))
338 .map(|_| ())
339 }
340 }
341
342 #[corresponds(EC_POINT_point2oct)]
344 pub fn to_bytes(
345 &self,
346 group: &EcGroupRef,
347 form: PointConversionForm,
348 ctx: &mut BigNumContextRef,
349 ) -> Result<Vec<u8>, ErrorStack> {
350 unsafe {
351 let len = ffi::EC_POINT_point2oct(
352 group.as_ptr(),
353 self.as_ptr(),
354 form.0,
355 ptr::null_mut(),
356 0,
357 ctx.as_ptr(),
358 );
359 if len == 0 {
360 return Err(ErrorStack::get());
361 }
362 let mut buf = vec![0; len];
363 let len = ffi::EC_POINT_point2oct(
364 group.as_ptr(),
365 self.as_ptr(),
366 form.0,
367 buf.as_mut_ptr(),
368 len,
369 ctx.as_ptr(),
370 );
371 if len == 0 {
372 Err(ErrorStack::get())
373 } else {
374 Ok(buf)
375 }
376 }
377 }
378
379 #[corresponds(EC_POINT_dup)]
381 pub fn to_owned(&self, group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
382 unsafe {
383 cvt_p(ffi::EC_POINT_dup(self.as_ptr(), group.as_ptr())).map(|p| EcPoint::from_ptr(p))
384 }
385 }
386
387 pub fn eq(
393 &self,
394 group: &EcGroupRef,
395 other: &EcPointRef,
396 ctx: &mut BigNumContextRef,
397 ) -> Result<bool, ErrorStack> {
398 unsafe {
399 let res = cvt_n(ffi::EC_POINT_cmp(
400 group.as_ptr(),
401 self.as_ptr(),
402 other.as_ptr(),
403 ctx.as_ptr(),
404 ))?;
405 Ok(res == 0)
406 }
407 }
408
409 #[corresponds(EC_POINT_get_affine_coordinates_GFp)]
412 pub fn affine_coordinates_gfp(
413 &self,
414 group: &EcGroupRef,
415 x: &mut BigNumRef,
416 y: &mut BigNumRef,
417 ctx: &mut BigNumContextRef,
418 ) -> Result<(), ErrorStack> {
419 unsafe {
420 cvt(ffi::EC_POINT_get_affine_coordinates_GFp(
421 group.as_ptr(),
422 self.as_ptr(),
423 x.as_ptr(),
424 y.as_ptr(),
425 ctx.as_ptr(),
426 ))
427 .map(|_| ())
428 }
429 }
430}
431
432impl EcPoint {
433 #[corresponds(EC_POINT_new)]
435 pub fn new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
436 unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(|p| EcPoint::from_ptr(p)) }
437 }
438
439 #[corresponds(EC_POINT_oct2point)]
441 pub fn from_bytes(
442 group: &EcGroupRef,
443 buf: &[u8],
444 ctx: &mut BigNumContextRef,
445 ) -> Result<EcPoint, ErrorStack> {
446 let point = EcPoint::new(group)?;
447 unsafe {
448 cvt(ffi::EC_POINT_oct2point(
449 group.as_ptr(),
450 point.as_ptr(),
451 buf.as_ptr(),
452 buf.len(),
453 ctx.as_ptr(),
454 ))?;
455 }
456 Ok(point)
457 }
458}
459
460generic_foreign_type_and_impl_send_sync! {
461 type CType = ffi::EC_KEY;
462 fn drop = ffi::EC_KEY_free;
463
464 pub struct EcKey<T>;
467
468 pub struct EcKeyRef<T>;
472}
473
474impl<T> EcKeyRef<T>
475where
476 T: HasPrivate,
477{
478 private_key_to_pem! {
479 #[corresponds(PEM_write_bio_ECPrivateKey)]
483 private_key_to_pem,
484 #[corresponds(PEM_write_bio_ECPrivateKey)]
488 private_key_to_pem_passphrase,
489 ffi::PEM_write_bio_ECPrivateKey
490 }
491
492 to_der! {
493 #[corresponds(i2d_ECPrivateKey)]
495 private_key_to_der,
496 ffi::i2d_ECPrivateKey
497 }
498
499 #[corresponds(EC_KEY_get0_private_key)]
501 pub fn private_key(&self) -> &BigNumRef {
502 unsafe {
503 let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr());
504 BigNumRef::from_ptr(ptr as *mut _)
505 }
506 }
507}
508
509impl<T> EcKeyRef<T>
510where
511 T: HasPublic,
512{
513 #[corresponds(EC_KEY_get0_public_key)]
515 pub fn public_key(&self) -> &EcPointRef {
516 unsafe {
517 let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr());
518 EcPointRef::from_ptr(ptr as *mut _)
519 }
520 }
521
522 to_pem! {
523 #[corresponds(PEM_write_bio_EC_PUBKEY)]
527 public_key_to_pem,
528 ffi::PEM_write_bio_EC_PUBKEY
529 }
530
531 to_der! {
532 #[corresponds(i2d_EC_PUBKEY)]
534 public_key_to_der,
535 ffi::i2d_EC_PUBKEY
536 }
537}
538
539impl<T> EcKeyRef<T>
540where
541 T: HasParams,
542{
543 #[corresponds(EC_KEY_get0_group)]
545 pub fn group(&self) -> &EcGroupRef {
546 unsafe {
547 let ptr = ffi::EC_KEY_get0_group(self.as_ptr());
548 EcGroupRef::from_ptr(ptr as *mut _)
549 }
550 }
551
552 #[corresponds(EC_KEY_check_key)]
554 pub fn check_key(&self) -> Result<(), ErrorStack> {
555 unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) }
556 }
557}
558
559impl<T> ToOwned for EcKeyRef<T> {
560 type Owned = EcKey<T>;
561
562 fn to_owned(&self) -> EcKey<T> {
563 unsafe {
564 let r = ffi::EC_KEY_up_ref(self.as_ptr());
565 assert!(r == 1);
566 EcKey::from_ptr(self.as_ptr())
567 }
568 }
569}
570
571impl EcKey<Params> {
572 #[corresponds(EC_KEY_new_by_curve_name)]
577 pub fn from_curve_name(nid: Nid) -> Result<EcKey<Params>, ErrorStack> {
578 unsafe {
579 init();
580 cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p))
581 }
582 }
583
584 #[corresponds(EC_KEY_set_group)]
586 pub fn from_group(group: &EcGroupRef) -> Result<EcKey<Params>, ErrorStack> {
587 unsafe {
588 cvt_p(ffi::EC_KEY_new())
589 .map(|p| EcKey::from_ptr(p))
590 .and_then(|key| {
591 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
592 })
593 }
594 }
595}
596
597impl EcKey<Public> {
598 pub fn from_public_key(
620 group: &EcGroupRef,
621 public_key: &EcPointRef,
622 ) -> Result<EcKey<Public>, ErrorStack> {
623 unsafe {
624 cvt_p(ffi::EC_KEY_new())
625 .map(|p| EcKey::from_ptr(p))
626 .and_then(|key| {
627 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
628 })
629 .and_then(|key| {
630 cvt(ffi::EC_KEY_set_public_key(
631 key.as_ptr(),
632 public_key.as_ptr(),
633 ))
634 .map(|_| key)
635 })
636 }
637 }
638
639 pub fn from_public_key_affine_coordinates(
641 group: &EcGroupRef,
642 x: &BigNumRef,
643 y: &BigNumRef,
644 ) -> Result<EcKey<Public>, ErrorStack> {
645 unsafe {
646 cvt_p(ffi::EC_KEY_new())
647 .map(|p| EcKey::from_ptr(p))
648 .and_then(|key| {
649 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
650 })
651 .and_then(|key| {
652 cvt(ffi::EC_KEY_set_public_key_affine_coordinates(
653 key.as_ptr(),
654 x.as_ptr(),
655 y.as_ptr(),
656 ))
657 .map(|_| key)
658 })
659 }
660 }
661
662 from_pem! {
663 #[corresponds(PEM_read_bio_EC_PUBKEY)]
667 public_key_from_pem,
668 EcKey<Public>,
669 ffi::PEM_read_bio_EC_PUBKEY
670 }
671
672 from_der! {
673 #[corresponds(d2i_EC_PUBKEY)]
675 public_key_from_der,
676 EcKey<Public>,
677 ffi::d2i_EC_PUBKEY,
678 ::libc::c_long
679 }
680}
681
682impl EcKey<Private> {
683 pub fn generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack> {
685 unsafe {
686 cvt_p(ffi::EC_KEY_new())
687 .map(|p| EcKey::from_ptr(p))
688 .and_then(|key| {
689 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
690 })
691 .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key))
692 }
693 }
694
695 pub fn from_private_components(
697 group: &EcGroupRef,
698 private_number: &BigNumRef,
699 public_key: &EcPointRef,
700 ) -> Result<EcKey<Private>, ErrorStack> {
701 unsafe {
702 cvt_p(ffi::EC_KEY_new())
703 .map(|p| EcKey::from_ptr(p))
704 .and_then(|key| {
705 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
706 })
707 .and_then(|key| {
708 cvt(ffi::EC_KEY_set_private_key(
709 key.as_ptr(),
710 private_number.as_ptr(),
711 ))
712 .map(|_| key)
713 })
714 .and_then(|key| {
715 cvt(ffi::EC_KEY_set_public_key(
716 key.as_ptr(),
717 public_key.as_ptr(),
718 ))
719 .map(|_| key)
720 })
721 }
722 }
723
724 private_key_from_pem! {
725 #[corresponds(PEM_read_bio_ECPrivateKey)]
729 private_key_from_pem,
730
731 #[corresponds(PEM_read_bio_ECPrivateKey)]
735 private_key_from_pem_passphrase,
736
737 #[corresponds(PEM_read_bio_ECPrivateKey)]
743 private_key_from_pem_callback,
744 EcKey<Private>,
745 ffi::PEM_read_bio_ECPrivateKey
746 }
747
748 from_der! {
749 #[corresponds(d2i_ECPrivateKey)]
751 private_key_from_der,
752 EcKey<Private>,
753 ffi::d2i_ECPrivateKey,
754 ::libc::c_long
755 }
756}
757
758impl<T> Clone for EcKey<T> {
759 fn clone(&self) -> EcKey<T> {
760 (**self).to_owned()
761 }
762}
763
764impl<T> fmt::Debug for EcKey<T> {
765 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
766 write!(f, "EcKey")
767 }
768}
769
770#[cfg(test)]
771mod test {
772 use hex::FromHex;
773
774 use super::*;
775 use crate::bn::{BigNum, BigNumContext};
776 use crate::nid::Nid;
777
778 #[test]
779 fn key_new_by_curve_name() {
780 EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
781 }
782
783 #[test]
784 fn generate() {
785 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
786 EcKey::generate(&group).unwrap();
787 }
788
789 #[test]
790 fn cofactor() {
791 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
792 let mut ctx = BigNumContext::new().unwrap();
793 let mut cofactor = BigNum::new().unwrap();
794 group.cofactor(&mut cofactor, &mut ctx).unwrap();
795 let one = BigNum::from_u32(1).unwrap();
796 assert_eq!(cofactor, one);
797 }
798
799 #[test]
800 #[allow(clippy::redundant_clone)]
801 fn dup() {
802 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
803 let key = EcKey::generate(&group).unwrap();
804 drop(key.clone());
805 }
806
807 #[test]
808 fn point_new() {
809 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
810 EcPoint::new(&group).unwrap();
811 }
812
813 #[test]
814 fn point_bytes() {
815 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
816 let key = EcKey::generate(&group).unwrap();
817 let point = key.public_key();
818 let mut ctx = BigNumContext::new().unwrap();
819 let bytes = point
820 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
821 .unwrap();
822 let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
823 assert!(point.eq(&group, &point2, &mut ctx).unwrap());
824 }
825
826 #[test]
827 fn point_owned() {
828 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
829 let key = EcKey::generate(&group).unwrap();
830 let point = key.public_key();
831 let owned = point.to_owned(&group).unwrap();
832 let mut ctx = BigNumContext::new().unwrap();
833 assert!(owned.eq(&group, point, &mut ctx).unwrap());
834 }
835
836 #[test]
837 fn mul_generator() {
838 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
839 let key = EcKey::generate(&group).unwrap();
840 let mut ctx = BigNumContext::new().unwrap();
841 let mut public_key = EcPoint::new(&group).unwrap();
842 public_key
843 .mul_generator(&group, key.private_key(), &ctx)
844 .unwrap();
845 assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap());
846 }
847
848 #[test]
849 fn generator() {
850 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
851 let generator = group.generator();
852 let one = BigNum::from_u32(1).unwrap();
853 let mut ctx = BigNumContext::new().unwrap();
854 let mut ecp = EcPoint::new(&group).unwrap();
855 ecp.mul_generator(&group, &one, &ctx).unwrap();
856 assert!(ecp.eq(&group, generator, &mut ctx).unwrap());
857 }
858
859 #[test]
860 fn key_from_public_key() {
861 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
862 let key = EcKey::generate(&group).unwrap();
863 let mut ctx = BigNumContext::new().unwrap();
864 let bytes = key
865 .public_key()
866 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
867 .unwrap();
868
869 drop(key);
870 let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
871 let ec_key = EcKey::from_public_key(&group, &public_key).unwrap();
872 assert!(ec_key.check_key().is_ok());
873 }
874
875 #[test]
876 fn key_from_private_components() {
877 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
878 let key = EcKey::generate(&group).unwrap();
879
880 let dup_key =
881 EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap();
882 dup_key.check_key().unwrap();
883
884 assert!(key.private_key() == dup_key.private_key());
885 }
886
887 #[test]
888 fn key_from_affine_coordinates() {
889 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
890 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
891 .unwrap();
892 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
893 .unwrap();
894
895 let xbn = BigNum::from_slice(&x).unwrap();
896 let ybn = BigNum::from_slice(&y).unwrap();
897
898 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
899 assert!(ec_key.check_key().is_ok());
900 }
901
902 #[test]
903 fn get_affine_coordinates() {
904 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
905 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
906 .unwrap();
907 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
908 .unwrap();
909
910 let xbn = BigNum::from_slice(&x).unwrap();
911 let ybn = BigNum::from_slice(&y).unwrap();
912
913 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
914
915 let mut xbn2 = BigNum::new().unwrap();
916 let mut ybn2 = BigNum::new().unwrap();
917 let mut ctx = BigNumContext::new().unwrap();
918 let ec_key_pk = ec_key.public_key();
919 ec_key_pk
920 .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx)
921 .unwrap();
922 assert_eq!(xbn2, xbn);
923 assert_eq!(ybn2, ybn);
924 }
925}