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