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