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, 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(boringssl))] { 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://www.openssl.org/docs/manmaster/crypto/EC_GROUP_get_seed_len.html 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://www.openssl.org/docs/manmaster/man3/EC_GROUP_order_bits.html 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 EcGroupRef { 169 /// Places the components of a curve over a prime field in the provided `BigNum`s. 170 /// The components make up the formula `y^2 mod p = x^3 + ax + b mod p`. 171 #[corresponds(EC_GROUP_get_curve_GFp)] 172 pub fn components_gfp( 173 &self, 174 p: &mut BigNumRef, 175 a: &mut BigNumRef, 176 b: &mut BigNumRef, 177 ctx: &mut BigNumContextRef, 178 ) -> Result<(), ErrorStack> { 179 unsafe { 180 cvt(ffi::EC_GROUP_get_curve_GFp( 181 self.as_ptr(), 182 p.as_ptr(), 183 a.as_ptr(), 184 b.as_ptr(), 185 ctx.as_ptr(), 186 )) 187 .map(|_| ()) 188 } 189 } 190 191 /// Places the components of a curve over a binary field in the provided `BigNum`s. 192 /// The components make up the formula `y^2 + xy = x^3 + ax^2 + b`. 193 /// 194 /// In this form `p` relates to the irreducible polynomial. Each bit represents 195 /// a term in the polynomial. It will be set to 3 `1`s or 5 `1`s depending on 196 /// using a trinomial or pentanomial. 197 #[corresponds(EC_GROUP_get_curve_GF2m)] 198 #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_EC2M")))] 199 pub fn components_gf2m( 200 &self, 201 p: &mut BigNumRef, 202 a: &mut BigNumRef, 203 b: &mut BigNumRef, 204 ctx: &mut BigNumContextRef, 205 ) -> Result<(), ErrorStack> { 206 unsafe { 207 cvt(ffi::EC_GROUP_get_curve_GF2m( 208 self.as_ptr(), 209 p.as_ptr(), 210 a.as_ptr(), 211 b.as_ptr(), 212 ctx.as_ptr(), 213 )) 214 .map(|_| ()) 215 } 216 } 217 218 /// Places the cofactor of the group in the provided `BigNum`. 219 #[corresponds(EC_GROUP_get_cofactor)] 220 pub fn cofactor( 221 &self, 222 cofactor: &mut BigNumRef, 223 ctx: &mut BigNumContextRef, 224 ) -> Result<(), ErrorStack> { 225 unsafe { 226 cvt(ffi::EC_GROUP_get_cofactor( 227 self.as_ptr(), 228 cofactor.as_ptr(), 229 ctx.as_ptr(), 230 )) 231 .map(|_| ()) 232 } 233 } 234 235 /// Returns the degree of the curve. 236 #[corresponds(EC_GROUP_get_degree)] 237 pub fn degree(&self) -> u32 { 238 unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 } 239 } 240 241 /// Returns the number of bits in the group order. 242 #[corresponds(EC_GROUP_order_bits)] 243 #[cfg(ossl110)] 244 pub fn order_bits(&self) -> u32 { 245 unsafe { ffi::EC_GROUP_order_bits(self.as_ptr()) as u32 } 246 } 247 248 /// Returns the generator for the given curve as an [`EcPoint`]. 249 #[corresponds(EC_GROUP_get0_generator)] 250 pub fn generator(&self) -> &EcPointRef { 251 unsafe { 252 let ptr = ffi::EC_GROUP_get0_generator(self.as_ptr()); 253 EcPointRef::from_const_ptr(ptr) 254 } 255 } 256 257 /// Sets the generator point for the given curve 258 #[corresponds(EC_GROUP_set_generator)] 259 pub fn set_generator( 260 &mut self, 261 generator: EcPoint, 262 order: BigNum, 263 cofactor: BigNum, 264 ) -> Result<(), ErrorStack> { 265 unsafe { 266 cvt(ffi::EC_GROUP_set_generator( 267 self.as_ptr(), 268 generator.as_ptr(), 269 order.as_ptr(), 270 cofactor.as_ptr(), 271 )) 272 .map(|_| ()) 273 } 274 } 275 276 /// Places the order of the curve in the provided `BigNum`. 277 #[corresponds(EC_GROUP_get_order)] 278 pub fn order( 279 &self, 280 order: &mut BigNumRef, 281 ctx: &mut BigNumContextRef, 282 ) -> Result<(), ErrorStack> { 283 unsafe { 284 cvt(ffi::EC_GROUP_get_order( 285 self.as_ptr(), 286 order.as_ptr(), 287 ctx.as_ptr(), 288 )) 289 .map(|_| ()) 290 } 291 } 292 293 /// Sets the flag determining if the group corresponds to a named curve or must be explicitly 294 /// parameterized. 295 /// 296 /// This defaults to `EXPLICIT_CURVE` in OpenSSL 1.0.1 and 1.0.2, but `NAMED_CURVE` in OpenSSL 297 /// 1.1.0. 298 #[corresponds(EC_GROUP_set_asn1_flag)] 299 pub fn set_asn1_flag(&mut self, flag: Asn1Flag) { 300 unsafe { 301 ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0); 302 } 303 } 304 305 /// Gets the flag determining if the group corresponds to a named curve. 306 #[corresponds(EC_GROUP_get_asn1_flag)] 307 pub fn asn1_flag(&self) -> Asn1Flag { 308 unsafe { Asn1Flag(ffi::EC_GROUP_get_asn1_flag(self.as_ptr())) } 309 } 310 311 /// Returns the name of the curve, if a name is associated. 312 #[corresponds(EC_GROUP_get_curve_name)] 313 pub fn curve_name(&self) -> Option<Nid> { 314 let nid = unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) }; 315 if nid > 0 { 316 Some(Nid::from_raw(nid)) 317 } else { 318 None 319 } 320 } 321} 322 323foreign_type_and_impl_send_sync! { 324 type CType = ffi::EC_POINT; 325 fn drop = ffi::EC_POINT_free; 326 327 /// Represents a point on the curve 328 pub struct EcPoint; 329 /// A reference a borrowed [`EcPoint`]. 330 pub struct EcPointRef; 331} 332 333impl EcPointRef { 334 /// Computes `a + b`, storing the result in `self`. 335 #[corresponds(EC_POINT_add)] 336 pub fn add( 337 &mut self, 338 group: &EcGroupRef, 339 a: &EcPointRef, 340 b: &EcPointRef, 341 ctx: &mut BigNumContextRef, 342 ) -> Result<(), ErrorStack> { 343 unsafe { 344 cvt(ffi::EC_POINT_add( 345 group.as_ptr(), 346 self.as_ptr(), 347 a.as_ptr(), 348 b.as_ptr(), 349 ctx.as_ptr(), 350 )) 351 .map(|_| ()) 352 } 353 } 354 355 /// Computes `q * m`, storing the result in `self`. 356 #[corresponds(EC_POINT_mul)] 357 pub fn mul( 358 &mut self, 359 group: &EcGroupRef, 360 q: &EcPointRef, 361 m: &BigNumRef, 362 // FIXME should be &mut 363 ctx: &BigNumContextRef, 364 ) -> Result<(), ErrorStack> { 365 unsafe { 366 cvt(ffi::EC_POINT_mul( 367 group.as_ptr(), 368 self.as_ptr(), 369 ptr::null(), 370 q.as_ptr(), 371 m.as_ptr(), 372 ctx.as_ptr(), 373 )) 374 .map(|_| ()) 375 } 376 } 377 378 /// Computes `generator * n`, storing the result in `self`. 379 #[corresponds(EC_POINT_mul)] 380 pub fn mul_generator( 381 &mut self, 382 group: &EcGroupRef, 383 n: &BigNumRef, 384 // FIXME should be &mut 385 ctx: &BigNumContextRef, 386 ) -> Result<(), ErrorStack> { 387 unsafe { 388 cvt(ffi::EC_POINT_mul( 389 group.as_ptr(), 390 self.as_ptr(), 391 n.as_ptr(), 392 ptr::null(), 393 ptr::null(), 394 ctx.as_ptr(), 395 )) 396 .map(|_| ()) 397 } 398 } 399 400 /// Computes `generator * n + q * m`, storing the result in `self`. 401 #[corresponds(EC_POINT_mul)] 402 pub fn mul_full( 403 &mut self, 404 group: &EcGroupRef, 405 n: &BigNumRef, 406 q: &EcPointRef, 407 m: &BigNumRef, 408 ctx: &mut BigNumContextRef, 409 ) -> Result<(), ErrorStack> { 410 unsafe { 411 cvt(ffi::EC_POINT_mul( 412 group.as_ptr(), 413 self.as_ptr(), 414 n.as_ptr(), 415 q.as_ptr(), 416 m.as_ptr(), 417 ctx.as_ptr(), 418 )) 419 .map(|_| ()) 420 } 421 } 422 423 /// Inverts `self`. 424 #[corresponds(EC_POINT_invert)] 425 // FIXME should be mutable 426 pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> { 427 unsafe { 428 cvt(ffi::EC_POINT_invert( 429 group.as_ptr(), 430 self.as_ptr(), 431 ctx.as_ptr(), 432 )) 433 .map(|_| ()) 434 } 435 } 436 437 /// Serializes the point to a binary representation. 438 #[corresponds(EC_POINT_point2oct)] 439 pub fn to_bytes( 440 &self, 441 group: &EcGroupRef, 442 form: PointConversionForm, 443 ctx: &mut BigNumContextRef, 444 ) -> Result<Vec<u8>, ErrorStack> { 445 unsafe { 446 let len = ffi::EC_POINT_point2oct( 447 group.as_ptr(), 448 self.as_ptr(), 449 form.0, 450 ptr::null_mut(), 451 0, 452 ctx.as_ptr(), 453 ); 454 if len == 0 { 455 return Err(ErrorStack::get()); 456 } 457 let mut buf = vec![0; len]; 458 let len = ffi::EC_POINT_point2oct( 459 group.as_ptr(), 460 self.as_ptr(), 461 form.0, 462 buf.as_mut_ptr(), 463 len, 464 ctx.as_ptr(), 465 ); 466 if len == 0 { 467 Err(ErrorStack::get()) 468 } else { 469 Ok(buf) 470 } 471 } 472 } 473 474 /// Serializes the point to a hexadecimal string representation. 475 #[corresponds(EC_POINT_point2hex)] 476 #[cfg(not(boringssl))] 477 pub fn to_hex_str( 478 &self, 479 group: &EcGroupRef, 480 form: PointConversionForm, 481 ctx: &mut BigNumContextRef, 482 ) -> Result<OpensslString, ErrorStack> { 483 unsafe { 484 let buf = cvt_p(ffi::EC_POINT_point2hex( 485 group.as_ptr(), 486 self.as_ptr(), 487 form.0, 488 ctx.as_ptr(), 489 ))?; 490 Ok(OpensslString::from_ptr(buf)) 491 } 492 } 493 494 /// Creates a new point on the specified curve with the same value. 495 #[corresponds(EC_POINT_dup)] 496 pub fn to_owned(&self, group: &EcGroupRef) -> Result<EcPoint, ErrorStack> { 497 unsafe { cvt_p(ffi::EC_POINT_dup(self.as_ptr(), group.as_ptr())).map(EcPoint) } 498 } 499 500 /// Determines if this point is equal to another. 501 #[corresponds(EC_POINT_cmp)] 502 pub fn eq( 503 &self, 504 group: &EcGroupRef, 505 other: &EcPointRef, 506 ctx: &mut BigNumContextRef, 507 ) -> Result<bool, ErrorStack> { 508 unsafe { 509 let res = cvt_n(ffi::EC_POINT_cmp( 510 group.as_ptr(), 511 self.as_ptr(), 512 other.as_ptr(), 513 ctx.as_ptr(), 514 ))?; 515 Ok(res == 0) 516 } 517 } 518 519 /// Places affine coordinates of a curve over a prime field in the provided 520 /// `x` and `y` `BigNum`s. 521 #[corresponds(EC_POINT_get_affine_coordinates)] 522 #[cfg(any(ossl111, boringssl, libressl350))] 523 pub fn affine_coordinates( 524 &self, 525 group: &EcGroupRef, 526 x: &mut BigNumRef, 527 y: &mut BigNumRef, 528 ctx: &mut BigNumContextRef, 529 ) -> Result<(), ErrorStack> { 530 unsafe { 531 cvt(ffi::EC_POINT_get_affine_coordinates( 532 group.as_ptr(), 533 self.as_ptr(), 534 x.as_ptr(), 535 y.as_ptr(), 536 ctx.as_ptr(), 537 )) 538 .map(|_| ()) 539 } 540 } 541 542 /// Places affine coordinates of a curve over a prime field in the provided 543 /// `x` and `y` `BigNum`s 544 #[corresponds(EC_POINT_get_affine_coordinates_GFp)] 545 pub fn affine_coordinates_gfp( 546 &self, 547 group: &EcGroupRef, 548 x: &mut BigNumRef, 549 y: &mut BigNumRef, 550 ctx: &mut BigNumContextRef, 551 ) -> Result<(), ErrorStack> { 552 unsafe { 553 cvt(ffi::EC_POINT_get_affine_coordinates_GFp( 554 group.as_ptr(), 555 self.as_ptr(), 556 x.as_ptr(), 557 y.as_ptr(), 558 ctx.as_ptr(), 559 )) 560 .map(|_| ()) 561 } 562 } 563 564 /// Sets affine coordinates of a curve over a prime field using the provided 565 /// `x` and `y` `BigNum`s 566 #[corresponds(EC_POINT_set_affine_coordinates_GFp)] 567 pub fn set_affine_coordinates_gfp( 568 &mut self, 569 group: &EcGroupRef, 570 x: &BigNumRef, 571 y: &BigNumRef, 572 ctx: &mut BigNumContextRef, 573 ) -> Result<(), ErrorStack> { 574 unsafe { 575 cvt(ffi::EC_POINT_set_affine_coordinates_GFp( 576 group.as_ptr(), 577 self.as_ptr(), 578 x.as_ptr(), 579 y.as_ptr(), 580 ctx.as_ptr(), 581 )) 582 .map(|_| ()) 583 } 584 } 585 586 /// Places affine coordinates of a curve over a binary field in the provided 587 /// `x` and `y` `BigNum`s 588 #[corresponds(EC_POINT_get_affine_coordinates_GF2m)] 589 #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_EC2M")))] 590 pub fn affine_coordinates_gf2m( 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_GF2m( 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 /// Checks if point is infinity 610 #[corresponds(EC_POINT_is_at_infinity)] 611 pub fn is_infinity(&self, group: &EcGroupRef) -> bool { 612 unsafe { 613 let res = ffi::EC_POINT_is_at_infinity(group.as_ptr(), self.as_ptr()); 614 res == 1 615 } 616 } 617 618 /// Checks if point is on a given curve 619 #[corresponds(EC_POINT_is_on_curve)] 620 pub fn is_on_curve( 621 &self, 622 group: &EcGroupRef, 623 ctx: &mut BigNumContextRef, 624 ) -> Result<bool, ErrorStack> { 625 unsafe { 626 let res = cvt_n(ffi::EC_POINT_is_on_curve( 627 group.as_ptr(), 628 self.as_ptr(), 629 ctx.as_ptr(), 630 ))?; 631 Ok(res == 1) 632 } 633 } 634} 635 636impl EcPoint { 637 /// Creates a new point on the specified curve. 638 #[corresponds(EC_POINT_new)] 639 pub fn new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack> { 640 unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) } 641 } 642 643 /// Creates point from a binary representation 644 #[corresponds(EC_POINT_oct2point)] 645 pub fn from_bytes( 646 group: &EcGroupRef, 647 buf: &[u8], 648 ctx: &mut BigNumContextRef, 649 ) -> Result<EcPoint, ErrorStack> { 650 let point = EcPoint::new(group)?; 651 unsafe { 652 cvt(ffi::EC_POINT_oct2point( 653 group.as_ptr(), 654 point.as_ptr(), 655 buf.as_ptr(), 656 buf.len(), 657 ctx.as_ptr(), 658 ))?; 659 } 660 Ok(point) 661 } 662 663 /// Creates point from a hexadecimal string representation 664 #[corresponds(EC_POINT_hex2point)] 665 #[cfg(not(boringssl))] 666 pub fn from_hex_str( 667 group: &EcGroupRef, 668 s: &str, 669 ctx: &mut BigNumContextRef, 670 ) -> Result<EcPoint, ErrorStack> { 671 let point = EcPoint::new(group)?; 672 unsafe { 673 let c_str = CString::new(s.as_bytes()).unwrap(); 674 cvt_p(ffi::EC_POINT_hex2point( 675 group.as_ptr(), 676 c_str.as_ptr() as *const _, 677 point.as_ptr(), 678 ctx.as_ptr(), 679 ))?; 680 } 681 Ok(point) 682 } 683} 684 685generic_foreign_type_and_impl_send_sync! { 686 type CType = ffi::EC_KEY; 687 fn drop = ffi::EC_KEY_free; 688 689 /// Public and optional private key on the given curve. 690 pub struct EcKey<T>; 691 /// A reference to an [`EcKey`]. 692 pub struct EcKeyRef<T>; 693} 694 695impl<T> EcKeyRef<T> 696where 697 T: HasPrivate, 698{ 699 private_key_to_pem! { 700 /// Serializes the private key to a PEM-encoded ECPrivateKey structure. 701 /// 702 /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. 703 #[corresponds(PEM_write_bio_ECPrivateKey)] 704 private_key_to_pem, 705 /// Serializes the private key to a PEM-encoded encrypted ECPrivateKey structure. 706 /// 707 /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. 708 #[corresponds(PEM_write_bio_ECPrivateKey)] 709 private_key_to_pem_passphrase, 710 ffi::PEM_write_bio_ECPrivateKey 711 } 712 713 to_der! { 714 /// Serializes the private key into a DER-encoded ECPrivateKey structure. 715 #[corresponds(i2d_ECPrivateKey)] 716 private_key_to_der, 717 ffi::i2d_ECPrivateKey 718 } 719 720 /// Returns the private key value. 721 #[corresponds(EC_KEY_get0_private_key)] 722 pub fn private_key(&self) -> &BigNumRef { 723 unsafe { 724 let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); 725 BigNumRef::from_const_ptr(ptr) 726 } 727 } 728} 729 730impl<T> EcKeyRef<T> 731where 732 T: HasPublic, 733{ 734 /// Returns the public key. 735 #[corresponds(EC_KEY_get0_public_key)] 736 pub fn public_key(&self) -> &EcPointRef { 737 unsafe { 738 let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); 739 EcPointRef::from_const_ptr(ptr) 740 } 741 } 742 743 to_pem! { 744 /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. 745 /// 746 /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. 747 #[corresponds(PEM_write_bio_EC_PUBKEY)] 748 public_key_to_pem, 749 ffi::PEM_write_bio_EC_PUBKEY 750 } 751 752 to_der! { 753 /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. 754 #[corresponds(i2d_EC_PUBKEY)] 755 public_key_to_der, 756 ffi::i2d_EC_PUBKEY 757 } 758} 759 760impl<T> EcKeyRef<T> 761where 762 T: HasParams, 763{ 764 /// Returns the key's group. 765 #[corresponds(EC_KEY_get0_group)] 766 pub fn group(&self) -> &EcGroupRef { 767 unsafe { 768 let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); 769 EcGroupRef::from_const_ptr(ptr) 770 } 771 } 772 773 /// Checks the key for validity. 774 #[corresponds(EC_KEY_check_key)] 775 pub fn check_key(&self) -> Result<(), ErrorStack> { 776 unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) } 777 } 778} 779 780impl<T> ToOwned for EcKeyRef<T> { 781 type Owned = EcKey<T>; 782 783 fn to_owned(&self) -> EcKey<T> { 784 unsafe { 785 let r = ffi::EC_KEY_up_ref(self.as_ptr()); 786 assert!(r == 1); 787 EcKey::from_ptr(self.as_ptr()) 788 } 789 } 790} 791 792impl EcKey<Params> { 793 /// Constructs an `EcKey` corresponding to a known curve. 794 /// 795 /// It will not have an associated public or private key. This kind of key is primarily useful 796 /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`. 797 #[corresponds(EC_KEY_new_by_curve_name)] 798 pub fn from_curve_name(nid: Nid) -> Result<EcKey<Params>, ErrorStack> { 799 unsafe { 800 init(); 801 cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p)) 802 } 803 } 804 805 /// Constructs an `EcKey` corresponding to a curve. 806 #[corresponds(EC_KEY_set_group)] 807 pub fn from_group(group: &EcGroupRef) -> Result<EcKey<Params>, ErrorStack> { 808 unsafe { 809 cvt_p(ffi::EC_KEY_new()) 810 .map(|p| EcKey::from_ptr(p)) 811 .and_then(|key| { 812 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) 813 }) 814 } 815 } 816} 817 818impl EcKey<Public> { 819 /// Constructs an `EcKey` from the specified group with the associated [`EcPoint`]: `public_key`. 820 /// 821 /// This will only have the associated `public_key`. 822 /// 823 /// # Example 824 /// 825 /// ``` 826 /// # fn main() -> Result<(), Box<dyn std::error::Error>> { 827 /// use openssl::bn::BigNumContext; 828 /// use openssl::ec::*; 829 /// use openssl::nid::Nid; 830 /// use openssl::pkey::PKey; 831 /// 832 /// let group = EcGroup::from_curve_name(Nid::SECP384R1)?; 833 /// let mut ctx = BigNumContext::new()?; 834 /// 835 /// // get bytes from somewhere 836 /// let public_key = // ... 837 /// # EcKey::generate(&group)?.public_key().to_bytes(&group, 838 /// # PointConversionForm::COMPRESSED, &mut ctx)?; 839 /// 840 /// // create an EcKey from the binary form of a EcPoint 841 /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx)?; 842 /// let key = EcKey::from_public_key(&group, &point)?; 843 /// key.check_key()?; 844 /// # Ok(()) } 845 /// ``` 846 #[corresponds(EC_KEY_set_public_key)] 847 pub fn from_public_key( 848 group: &EcGroupRef, 849 public_key: &EcPointRef, 850 ) -> Result<EcKey<Public>, ErrorStack> { 851 unsafe { 852 cvt_p(ffi::EC_KEY_new()) 853 .map(|p| EcKey::from_ptr(p)) 854 .and_then(|key| { 855 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) 856 }) 857 .and_then(|key| { 858 cvt(ffi::EC_KEY_set_public_key( 859 key.as_ptr(), 860 public_key.as_ptr(), 861 )) 862 .map(|_| key) 863 }) 864 } 865 } 866 867 /// Constructs a public key from its affine coordinates. 868 #[corresponds(EC_KEY_set_public_key_affine_coordinates)] 869 pub fn from_public_key_affine_coordinates( 870 group: &EcGroupRef, 871 x: &BigNumRef, 872 y: &BigNumRef, 873 ) -> Result<EcKey<Public>, ErrorStack> { 874 unsafe { 875 cvt_p(ffi::EC_KEY_new()) 876 .map(|p| EcKey::from_ptr(p)) 877 .and_then(|key| { 878 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) 879 }) 880 .and_then(|key| { 881 cvt(ffi::EC_KEY_set_public_key_affine_coordinates( 882 key.as_ptr(), 883 x.as_ptr(), 884 y.as_ptr(), 885 )) 886 .map(|_| key) 887 }) 888 } 889 } 890 891 from_pem! { 892 /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a EC key. 893 /// 894 /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. 895 #[corresponds(PEM_read_bio_EC_PUBKEY)] 896 public_key_from_pem, 897 EcKey<Public>, 898 ffi::PEM_read_bio_EC_PUBKEY 899 } 900 901 from_der! { 902 /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a EC key. 903 #[corresponds(d2i_EC_PUBKEY)] 904 public_key_from_der, 905 EcKey<Public>, 906 ffi::d2i_EC_PUBKEY 907 } 908} 909 910impl EcKey<Private> { 911 /// Generates a new public/private key pair on the specified curve. 912 /// 913 /// # Examples 914 /// 915 /// ``` 916 /// # fn main() -> Result<(), Box<dyn std::error::Error>> { 917 /// use openssl::bn::BigNumContext; 918 /// use openssl::nid::Nid; 919 /// use openssl::ec::{EcGroup, EcKey, PointConversionForm}; 920 /// 921 /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve 922 /// let group = EcGroup::from_curve_name(nid)?; 923 /// let key = EcKey::generate(&group)?; 924 /// 925 /// let mut ctx = BigNumContext::new()?; 926 /// 927 /// let public_key = &key.public_key().to_bytes( 928 /// &group, 929 /// PointConversionForm::COMPRESSED, 930 /// &mut ctx, 931 /// )?; 932 /// assert_eq!(public_key.len(), 33); 933 /// assert_ne!(public_key[0], 0x04); 934 /// 935 /// let private_key = key.private_key().to_vec(); 936 /// assert!(private_key.len() >= 31); 937 /// # Ok(()) } 938 /// ``` 939 #[corresponds(EC_KEY_generate_key)] 940 pub fn generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack> { 941 unsafe { 942 cvt_p(ffi::EC_KEY_new()) 943 .map(|p| EcKey::from_ptr(p)) 944 .and_then(|key| { 945 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) 946 }) 947 .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key)) 948 } 949 } 950 951 /// Constructs an public/private key pair given a curve, a private key and a public key point. 952 #[corresponds(EC_KEY_set_private_key)] 953 pub fn from_private_components( 954 group: &EcGroupRef, 955 private_number: &BigNumRef, 956 public_key: &EcPointRef, 957 ) -> Result<EcKey<Private>, ErrorStack> { 958 unsafe { 959 cvt_p(ffi::EC_KEY_new()) 960 .map(|p| EcKey::from_ptr(p)) 961 .and_then(|key| { 962 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) 963 }) 964 .and_then(|key| { 965 cvt(ffi::EC_KEY_set_private_key( 966 key.as_ptr(), 967 private_number.as_ptr(), 968 )) 969 .map(|_| key) 970 }) 971 .and_then(|key| { 972 cvt(ffi::EC_KEY_set_public_key( 973 key.as_ptr(), 974 public_key.as_ptr(), 975 )) 976 .map(|_| key) 977 }) 978 } 979 } 980 981 private_key_from_pem! { 982 /// Deserializes a private key from a PEM-encoded ECPrivateKey structure. 983 /// 984 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. 985 #[corresponds(PEM_read_bio_ECPrivateKey)] 986 private_key_from_pem, 987 988 /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. 989 /// 990 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. 991 #[corresponds(PEM_read_bio_ECPrivateKey)] 992 private_key_from_pem_passphrase, 993 994 /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. 995 /// 996 /// The callback should fill the password into the provided buffer and return its length. 997 /// 998 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. 999 #[corresponds(PEM_read_bio_ECPrivateKey)] 1000 private_key_from_pem_callback, 1001 EcKey<Private>, 1002 ffi::PEM_read_bio_ECPrivateKey 1003 } 1004 1005 from_der! { 1006 /// Decodes a DER-encoded elliptic curve private key structure. 1007 #[corresponds(d2i_ECPrivateKey)] 1008 private_key_from_der, 1009 EcKey<Private>, 1010 ffi::d2i_ECPrivateKey 1011 } 1012} 1013 1014impl<T> Clone for EcKey<T> { 1015 fn clone(&self) -> EcKey<T> { 1016 (**self).to_owned() 1017 } 1018} 1019 1020impl<T> fmt::Debug for EcKey<T> { 1021 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1022 write!(f, "EcKey") 1023 } 1024} 1025 1026#[cfg(test)] 1027mod test { 1028 use hex::FromHex; 1029 1030 use super::*; 1031 use crate::bn::{BigNum, BigNumContext}; 1032 use crate::nid::Nid; 1033 1034 #[test] 1035 fn key_new_by_curve_name() { 1036 EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1037 } 1038 1039 #[test] 1040 fn generate() { 1041 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1042 EcKey::generate(&group).unwrap(); 1043 } 1044 1045 #[test] 1046 fn ec_group_from_components() { 1047 // parameters are from secp256r1 1048 let p = BigNum::from_hex_str( 1049 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", 1050 ) 1051 .unwrap(); 1052 let a = BigNum::from_hex_str( 1053 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", 1054 ) 1055 .unwrap(); 1056 let b = BigNum::from_hex_str( 1057 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", 1058 ) 1059 .unwrap(); 1060 let mut ctx = BigNumContext::new().unwrap(); 1061 1062 let _curve = EcGroup::from_components(p, a, b, &mut ctx).unwrap(); 1063 } 1064 1065 #[test] 1066 fn ec_point_set_affine() { 1067 // parameters are from secp256r1 1068 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1069 let mut ctx = BigNumContext::new().unwrap(); 1070 let mut gen_point = EcPoint::new(&group).unwrap(); 1071 let gen_x = BigNum::from_hex_str( 1072 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", 1073 ) 1074 .unwrap(); 1075 let gen_y = BigNum::from_hex_str( 1076 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", 1077 ) 1078 .unwrap(); 1079 gen_point 1080 .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx) 1081 .unwrap(); 1082 assert!(gen_point.is_on_curve(&group, &mut ctx).unwrap()); 1083 } 1084 1085 #[test] 1086 fn ec_group_set_generator() { 1087 // parameters are from secp256r1 1088 let mut ctx = BigNumContext::new().unwrap(); 1089 let p = BigNum::from_hex_str( 1090 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", 1091 ) 1092 .unwrap(); 1093 let a = BigNum::from_hex_str( 1094 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", 1095 ) 1096 .unwrap(); 1097 let b = BigNum::from_hex_str( 1098 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", 1099 ) 1100 .unwrap(); 1101 1102 let mut group = EcGroup::from_components(p, a, b, &mut ctx).unwrap(); 1103 1104 let mut gen_point = EcPoint::new(&group).unwrap(); 1105 let gen_x = BigNum::from_hex_str( 1106 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", 1107 ) 1108 .unwrap(); 1109 let gen_y = BigNum::from_hex_str( 1110 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", 1111 ) 1112 .unwrap(); 1113 gen_point 1114 .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx) 1115 .unwrap(); 1116 1117 let order = BigNum::from_hex_str( 1118 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 1119 ) 1120 .unwrap(); 1121 let cofactor = BigNum::from_hex_str("01").unwrap(); 1122 group.set_generator(gen_point, order, cofactor).unwrap(); 1123 let mut constructed_order = BigNum::new().unwrap(); 1124 group.order(&mut constructed_order, &mut ctx).unwrap(); 1125 1126 let named_group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1127 let mut named_order = BigNum::new().unwrap(); 1128 named_group.order(&mut named_order, &mut ctx).unwrap(); 1129 1130 assert_eq!( 1131 constructed_order.ucmp(&named_order), 1132 std::cmp::Ordering::Equal 1133 ); 1134 } 1135 1136 #[test] 1137 fn cofactor() { 1138 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1139 let mut ctx = BigNumContext::new().unwrap(); 1140 let mut cofactor = BigNum::new().unwrap(); 1141 group.cofactor(&mut cofactor, &mut ctx).unwrap(); 1142 let one = BigNum::from_u32(1).unwrap(); 1143 assert_eq!(cofactor, one); 1144 } 1145 1146 #[test] 1147 #[allow(clippy::redundant_clone)] 1148 fn dup() { 1149 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1150 let key = EcKey::generate(&group).unwrap(); 1151 drop(key.clone()); 1152 } 1153 1154 #[test] 1155 fn point_new() { 1156 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1157 EcPoint::new(&group).unwrap(); 1158 } 1159 1160 #[test] 1161 fn point_bytes() { 1162 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1163 let key = EcKey::generate(&group).unwrap(); 1164 let point = key.public_key(); 1165 let mut ctx = BigNumContext::new().unwrap(); 1166 let bytes = point 1167 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) 1168 .unwrap(); 1169 let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); 1170 assert!(point.eq(&group, &point2, &mut ctx).unwrap()); 1171 } 1172 1173 #[test] 1174 #[cfg(not(boringssl))] 1175 fn point_hex_str() { 1176 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1177 let key = EcKey::generate(&group).unwrap(); 1178 let point = key.public_key(); 1179 let mut ctx = BigNumContext::new().unwrap(); 1180 let hex = point 1181 .to_hex_str(&group, PointConversionForm::COMPRESSED, &mut ctx) 1182 .unwrap(); 1183 let point2 = EcPoint::from_hex_str(&group, &hex, &mut ctx).unwrap(); 1184 assert!(point.eq(&group, &point2, &mut ctx).unwrap()); 1185 } 1186 1187 #[test] 1188 fn point_owned() { 1189 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1190 let key = EcKey::generate(&group).unwrap(); 1191 let point = key.public_key(); 1192 let owned = point.to_owned(&group).unwrap(); 1193 let mut ctx = BigNumContext::new().unwrap(); 1194 assert!(owned.eq(&group, point, &mut ctx).unwrap()); 1195 } 1196 1197 #[test] 1198 fn mul_generator() { 1199 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1200 let key = EcKey::generate(&group).unwrap(); 1201 let mut ctx = BigNumContext::new().unwrap(); 1202 let mut public_key = EcPoint::new(&group).unwrap(); 1203 public_key 1204 .mul_generator(&group, key.private_key(), &ctx) 1205 .unwrap(); 1206 assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap()); 1207 } 1208 1209 #[test] 1210 fn generator() { 1211 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1212 let gen = group.generator(); 1213 let one = BigNum::from_u32(1).unwrap(); 1214 let mut ctx = BigNumContext::new().unwrap(); 1215 let mut ecp = EcPoint::new(&group).unwrap(); 1216 ecp.mul_generator(&group, &one, &ctx).unwrap(); 1217 assert!(ecp.eq(&group, gen, &mut ctx).unwrap()); 1218 } 1219 1220 #[test] 1221 fn key_from_public_key() { 1222 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1223 let key = EcKey::generate(&group).unwrap(); 1224 let mut ctx = BigNumContext::new().unwrap(); 1225 let bytes = key 1226 .public_key() 1227 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) 1228 .unwrap(); 1229 1230 drop(key); 1231 let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); 1232 let ec_key = EcKey::from_public_key(&group, &public_key).unwrap(); 1233 assert!(ec_key.check_key().is_ok()); 1234 } 1235 1236 #[test] 1237 fn key_from_private_components() { 1238 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1239 let key = EcKey::generate(&group).unwrap(); 1240 1241 let dup_key = 1242 EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap(); 1243 dup_key.check_key().unwrap(); 1244 1245 assert!(key.private_key() == dup_key.private_key()); 1246 } 1247 1248 #[test] 1249 fn key_from_affine_coordinates() { 1250 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1251 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") 1252 .unwrap(); 1253 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") 1254 .unwrap(); 1255 1256 let xbn = BigNum::from_slice(&x).unwrap(); 1257 let ybn = BigNum::from_slice(&y).unwrap(); 1258 1259 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); 1260 assert!(ec_key.check_key().is_ok()); 1261 } 1262 1263 #[cfg(any(ossl111, boringssl, libressl350))] 1264 #[test] 1265 fn get_affine_coordinates() { 1266 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1267 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") 1268 .unwrap(); 1269 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") 1270 .unwrap(); 1271 1272 let xbn = BigNum::from_slice(&x).unwrap(); 1273 let ybn = BigNum::from_slice(&y).unwrap(); 1274 1275 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); 1276 1277 let mut xbn2 = BigNum::new().unwrap(); 1278 let mut ybn2 = BigNum::new().unwrap(); 1279 let mut ctx = BigNumContext::new().unwrap(); 1280 let ec_key_pk = ec_key.public_key(); 1281 ec_key_pk 1282 .affine_coordinates(&group, &mut xbn2, &mut ybn2, &mut ctx) 1283 .unwrap(); 1284 assert_eq!(xbn2, xbn); 1285 assert_eq!(ybn2, ybn); 1286 } 1287 1288 #[test] 1289 fn get_affine_coordinates_gfp() { 1290 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1291 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") 1292 .unwrap(); 1293 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") 1294 .unwrap(); 1295 1296 let xbn = BigNum::from_slice(&x).unwrap(); 1297 let ybn = BigNum::from_slice(&y).unwrap(); 1298 1299 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); 1300 1301 let mut xbn2 = BigNum::new().unwrap(); 1302 let mut ybn2 = BigNum::new().unwrap(); 1303 let mut ctx = BigNumContext::new().unwrap(); 1304 let ec_key_pk = ec_key.public_key(); 1305 ec_key_pk 1306 .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx) 1307 .unwrap(); 1308 assert_eq!(xbn2, xbn); 1309 assert_eq!(ybn2, ybn); 1310 } 1311 1312 #[test] 1313 fn is_infinity() { 1314 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1315 let mut ctx = BigNumContext::new().unwrap(); 1316 let g = group.generator(); 1317 assert!(!g.is_infinity(&group)); 1318 1319 let mut order = BigNum::new().unwrap(); 1320 group.order(&mut order, &mut ctx).unwrap(); 1321 let mut inf = EcPoint::new(&group).unwrap(); 1322 inf.mul_generator(&group, &order, &ctx).unwrap(); 1323 assert!(inf.is_infinity(&group)); 1324 } 1325 1326 #[test] 1327 #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_EC2M")))] 1328 fn is_on_curve() { 1329 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1330 let mut ctx = BigNumContext::new().unwrap(); 1331 let g = group.generator(); 1332 assert!(g.is_on_curve(&group, &mut ctx).unwrap()); 1333 1334 let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap(); 1335 assert!(!g.is_on_curve(&group2, &mut ctx).unwrap()); 1336 } 1337 1338 #[test] 1339 #[cfg(any(boringssl, ossl111, libressl350))] 1340 fn asn1_flag() { 1341 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1342 let flag = group.asn1_flag(); 1343 assert_eq!(flag, Asn1Flag::NAMED_CURVE); 1344 } 1345} 1346