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 prefered. 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_GFp`] 484 /// 485 /// [`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>486 pub fn affine_coordinates_gfp( 487 &self, 488 group: &EcGroupRef, 489 x: &mut BigNumRef, 490 y: &mut BigNumRef, 491 ctx: &mut BigNumContextRef, 492 ) -> Result<(), ErrorStack> { 493 unsafe { 494 cvt(ffi::EC_POINT_get_affine_coordinates_GFp( 495 group.as_ptr(), 496 self.as_ptr(), 497 x.as_ptr(), 498 y.as_ptr(), 499 ctx.as_ptr(), 500 )) 501 .map(|_| ()) 502 } 503 } 504 505 /// Place affine coordinates of a curve over a binary field in the provided 506 /// `x` and `y` `BigNum`s 507 /// 508 /// OpenSSL documentation at [`EC_POINT_get_affine_coordinates_GF2m`] 509 /// 510 /// [`EC_POINT_get_affine_coordinates_GF2m`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_get_affine_coordinates_GF2m.html 511 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] affine_coordinates_gf2m( &self, group: &EcGroupRef, x: &mut BigNumRef, y: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>512 pub fn affine_coordinates_gf2m( 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_GF2m( 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 /// Checks if point is infinity 532 /// 533 /// OpenSSL documentation at [`EC_POINT_is_at_infinity`] 534 /// 535 /// [`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) -> bool536 pub fn is_infinity(&self, group: &EcGroupRef) -> bool { 537 unsafe { 538 let res = ffi::EC_POINT_is_at_infinity(group.as_ptr(), self.as_ptr()); 539 res == 1 540 } 541 } 542 543 /// Checks if point is on a given curve 544 /// 545 /// OpenSSL documentation at [`EC_POINT_is_on_curve`] 546 /// 547 /// [`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>548 pub fn is_on_curve( 549 &self, 550 group: &EcGroupRef, 551 ctx: &mut BigNumContextRef, 552 ) -> Result<bool, ErrorStack> { 553 unsafe { 554 let res = cvt_n(ffi::EC_POINT_is_on_curve( 555 group.as_ptr(), 556 self.as_ptr(), 557 ctx.as_ptr(), 558 ))?; 559 Ok(res == 1) 560 } 561 } 562 } 563 564 impl EcPoint { 565 /// Creates a new point on the specified curve. 566 /// 567 /// OpenSSL documentation at [`EC_POINT_new`] 568 /// 569 /// [`EC_POINT_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_new.html new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack>570 pub fn new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack> { 571 unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) } 572 } 573 574 /// Creates point from a binary representation 575 /// 576 /// OpenSSL documentation at [`EC_POINT_oct2point`] 577 /// 578 /// [`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>579 pub fn from_bytes( 580 group: &EcGroupRef, 581 buf: &[u8], 582 ctx: &mut BigNumContextRef, 583 ) -> Result<EcPoint, ErrorStack> { 584 let point = EcPoint::new(group)?; 585 unsafe { 586 cvt(ffi::EC_POINT_oct2point( 587 group.as_ptr(), 588 point.as_ptr(), 589 buf.as_ptr(), 590 buf.len(), 591 ctx.as_ptr(), 592 ))?; 593 } 594 Ok(point) 595 } 596 } 597 598 generic_foreign_type_and_impl_send_sync! { 599 type CType = ffi::EC_KEY; 600 fn drop = ffi::EC_KEY_free; 601 602 /// Public and optional Private key on the given curve 603 /// 604 /// OpenSSL documentation at [`EC_KEY_new`] 605 /// 606 /// [`EC_KEY_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new.html 607 pub struct EcKey<T>; 608 609 /// Reference to [`EcKey`] 610 /// 611 /// [`EcKey`]: struct.EcKey.html 612 pub struct EcKeyRef<T>; 613 } 614 615 impl<T> EcKeyRef<T> 616 where 617 T: HasPrivate, 618 { 619 private_key_to_pem! { 620 /// Serializes the private key to a PEM-encoded ECPrivateKey structure. 621 /// 622 /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. 623 /// 624 /// This corresponds to [`PEM_write_bio_ECPrivateKey`]. 625 /// 626 /// [`PEM_write_bio_ECPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_ECPrivateKey.html 627 private_key_to_pem, 628 /// Serializes the private key to a PEM-encoded encrypted ECPrivateKey structure. 629 /// 630 /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. 631 /// 632 /// This corresponds to [`PEM_write_bio_ECPrivateKey`]. 633 /// 634 /// [`PEM_write_bio_ECPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_ECPrivateKey.html 635 private_key_to_pem_passphrase, 636 ffi::PEM_write_bio_ECPrivateKey 637 } 638 639 to_der! { 640 /// Serializes the private key into a DER-encoded ECPrivateKey structure. 641 /// 642 /// This corresponds to [`i2d_ECPrivateKey`]. 643 /// 644 /// [`i2d_ECPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_ECPrivate_key.html 645 private_key_to_der, 646 ffi::i2d_ECPrivateKey 647 } 648 649 /// Return [`EcPoint`] associated with the private key 650 /// 651 /// OpenSSL documentation at [`EC_KEY_get0_private_key`] 652 /// 653 /// [`EC_KEY_get0_private_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_private_key.html private_key(&self) -> &BigNumRef654 pub fn private_key(&self) -> &BigNumRef { 655 unsafe { 656 let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); 657 BigNumRef::from_const_ptr(ptr) 658 } 659 } 660 } 661 662 impl<T> EcKeyRef<T> 663 where 664 T: HasPublic, 665 { 666 /// Returns the public key. 667 /// 668 /// OpenSSL documentation at [`EC_KEY_get0_public_key`] 669 /// 670 /// [`EC_KEY_get0_public_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_public_key.html public_key(&self) -> &EcPointRef671 pub fn public_key(&self) -> &EcPointRef { 672 unsafe { 673 let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); 674 EcPointRef::from_const_ptr(ptr) 675 } 676 } 677 678 to_pem! { 679 /// Serialies the public key into a PEM-encoded SubjectPublicKeyInfo structure. 680 /// 681 /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. 682 /// 683 /// This corresponds to [`PEM_write_bio_EC_PUBKEY`]. 684 /// 685 /// [`PEM_write_bio_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_EC_PUBKEY.html 686 public_key_to_pem, 687 ffi::PEM_write_bio_EC_PUBKEY 688 } 689 690 to_der! { 691 /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. 692 /// 693 /// This corresponds to [`i2d_EC_PUBKEY`]. 694 /// 695 /// [`i2d_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_EC_PUBKEY.html 696 public_key_to_der, 697 ffi::i2d_EC_PUBKEY 698 } 699 } 700 701 impl<T> EcKeyRef<T> 702 where 703 T: HasParams, 704 { 705 /// Return [`EcGroup`] of the `EcKey` 706 /// 707 /// OpenSSL documentation at [`EC_KEY_get0_group`] 708 /// 709 /// [`EC_KEY_get0_group`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_group.html group(&self) -> &EcGroupRef710 pub fn group(&self) -> &EcGroupRef { 711 unsafe { 712 let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); 713 EcGroupRef::from_const_ptr(ptr) 714 } 715 } 716 717 /// Checks the key for validity. 718 /// 719 /// OpenSSL documenation at [`EC_KEY_check_key`] 720 /// 721 /// [`EC_KEY_check_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_check_key.html check_key(&self) -> Result<(), ErrorStack>722 pub fn check_key(&self) -> Result<(), ErrorStack> { 723 unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) } 724 } 725 } 726 727 impl<T> ToOwned for EcKeyRef<T> { 728 type Owned = EcKey<T>; 729 to_owned(&self) -> EcKey<T>730 fn to_owned(&self) -> EcKey<T> { 731 unsafe { 732 let r = ffi::EC_KEY_up_ref(self.as_ptr()); 733 assert!(r == 1); 734 EcKey::from_ptr(self.as_ptr()) 735 } 736 } 737 } 738 739 impl EcKey<Params> { 740 /// Constructs an `EcKey` corresponding to a known curve. 741 /// 742 /// It will not have an associated public or private key. This kind of key is primarily useful 743 /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`. 744 /// 745 /// OpenSSL documenation at [`EC_KEY_new_by_curve_name`] 746 /// 747 /// [`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>748 pub fn from_curve_name(nid: Nid) -> Result<EcKey<Params>, ErrorStack> { 749 unsafe { 750 init(); 751 cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p)) 752 } 753 } 754 755 /// Constructs an `EcKey` corresponding to a curve. 756 /// 757 /// This corresponds to [`EC_KEY_set_group`]. 758 /// 759 /// [`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>760 pub fn from_group(group: &EcGroupRef) -> Result<EcKey<Params>, ErrorStack> { 761 unsafe { 762 cvt_p(ffi::EC_KEY_new()) 763 .map(|p| EcKey::from_ptr(p)) 764 .and_then(|key| { 765 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) 766 }) 767 } 768 } 769 } 770 771 impl EcKey<Public> { 772 /// Constructs an `EcKey` from the specified group with the associated `EcPoint`, public_key. 773 /// 774 /// This will only have the associated public_key. 775 /// 776 /// # Example 777 /// 778 /// ```no_run 779 /// use openssl::bn::BigNumContext; 780 /// use openssl::ec::*; 781 /// use openssl::nid::Nid; 782 /// use openssl::pkey::PKey; 783 /// 784 /// // get bytes from somewhere, i.e. this will not produce a valid key 785 /// let public_key: Vec<u8> = vec![]; 786 /// 787 /// // create an EcKey from the binary form of a EcPoint 788 /// let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap(); 789 /// let mut ctx = BigNumContext::new().unwrap(); 790 /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx).unwrap(); 791 /// let key = EcKey::from_public_key(&group, &point); 792 /// ``` from_public_key( group: &EcGroupRef, public_key: &EcPointRef, ) -> Result<EcKey<Public>, ErrorStack>793 pub fn from_public_key( 794 group: &EcGroupRef, 795 public_key: &EcPointRef, 796 ) -> Result<EcKey<Public>, ErrorStack> { 797 unsafe { 798 cvt_p(ffi::EC_KEY_new()) 799 .map(|p| EcKey::from_ptr(p)) 800 .and_then(|key| { 801 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) 802 }) 803 .and_then(|key| { 804 cvt(ffi::EC_KEY_set_public_key( 805 key.as_ptr(), 806 public_key.as_ptr(), 807 )) 808 .map(|_| key) 809 }) 810 } 811 } 812 813 /// Constructs a public key from its 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 /// 841 /// This corresponds to [`PEM_read_bio_EC_PUBKEY`]. 842 /// 843 /// [`PEM_read_bio_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_EC_PUBKEY.html 844 public_key_from_pem, 845 EcKey<Public>, 846 ffi::PEM_read_bio_EC_PUBKEY 847 } 848 849 from_der! { 850 /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a EC key. 851 /// 852 /// This corresponds to [`d2i_EC_PUBKEY`]. 853 /// 854 /// [`d2i_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_EC_PUBKEY.html 855 public_key_from_der, 856 EcKey<Public>, 857 ffi::d2i_EC_PUBKEY 858 } 859 } 860 861 impl EcKey<Private> { 862 /// Generates a new public/private key pair on the specified curve. generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack>863 pub fn generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack> { 864 unsafe { 865 cvt_p(ffi::EC_KEY_new()) 866 .map(|p| EcKey::from_ptr(p)) 867 .and_then(|key| { 868 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) 869 }) 870 .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key)) 871 } 872 } 873 874 /// 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>875 pub fn from_private_components( 876 group: &EcGroupRef, 877 private_number: &BigNumRef, 878 public_key: &EcPointRef, 879 ) -> Result<EcKey<Private>, ErrorStack> { 880 unsafe { 881 cvt_p(ffi::EC_KEY_new()) 882 .map(|p| EcKey::from_ptr(p)) 883 .and_then(|key| { 884 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) 885 }) 886 .and_then(|key| { 887 cvt(ffi::EC_KEY_set_private_key( 888 key.as_ptr(), 889 private_number.as_ptr(), 890 )) 891 .map(|_| key) 892 }) 893 .and_then(|key| { 894 cvt(ffi::EC_KEY_set_public_key( 895 key.as_ptr(), 896 public_key.as_ptr(), 897 )) 898 .map(|_| key) 899 }) 900 } 901 } 902 903 private_key_from_pem! { 904 /// Deserializes a private key from a PEM-encoded ECPrivateKey structure. 905 /// 906 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. 907 /// 908 /// This corresponds to `PEM_read_bio_ECPrivateKey`. 909 private_key_from_pem, 910 911 /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. 912 /// 913 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. 914 /// 915 /// This corresponds to `PEM_read_bio_ECPrivateKey`. 916 private_key_from_pem_passphrase, 917 918 /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. 919 /// 920 /// The callback should fill the password into the provided buffer and return its length. 921 /// 922 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. 923 /// 924 /// This corresponds to `PEM_read_bio_ECPrivateKey`. 925 private_key_from_pem_callback, 926 EcKey<Private>, 927 ffi::PEM_read_bio_ECPrivateKey 928 } 929 930 from_der! { 931 /// Decodes a DER-encoded elliptic curve private key structure. 932 /// 933 /// This corresponds to [`d2i_ECPrivateKey`]. 934 /// 935 /// [`d2i_ECPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_ECPrivate_key.html 936 private_key_from_der, 937 EcKey<Private>, 938 ffi::d2i_ECPrivateKey 939 } 940 } 941 942 impl<T> Clone for EcKey<T> { clone(&self) -> EcKey<T>943 fn clone(&self) -> EcKey<T> { 944 (**self).to_owned() 945 } 946 } 947 948 impl<T> fmt::Debug for EcKey<T> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result949 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 950 write!(f, "EcKey") 951 } 952 } 953 954 #[cfg(test)] 955 mod test { 956 use hex::FromHex; 957 958 use super::*; 959 use crate::bn::{BigNum, BigNumContext}; 960 use crate::nid::Nid; 961 962 #[test] key_new_by_curve_name()963 fn key_new_by_curve_name() { 964 EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 965 } 966 967 #[test] generate()968 fn generate() { 969 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 970 EcKey::generate(&group).unwrap(); 971 } 972 973 #[test] cofactor()974 fn cofactor() { 975 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 976 let mut ctx = BigNumContext::new().unwrap(); 977 let mut cofactor = BigNum::new().unwrap(); 978 group.cofactor(&mut cofactor, &mut ctx).unwrap(); 979 let one = BigNum::from_u32(1).unwrap(); 980 assert_eq!(cofactor, one); 981 } 982 983 #[test] 984 #[allow(clippy::redundant_clone)] dup()985 fn dup() { 986 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 987 let key = EcKey::generate(&group).unwrap(); 988 drop(key.clone()); 989 } 990 991 #[test] point_new()992 fn point_new() { 993 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 994 EcPoint::new(&group).unwrap(); 995 } 996 997 #[test] point_bytes()998 fn point_bytes() { 999 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1000 let key = EcKey::generate(&group).unwrap(); 1001 let point = key.public_key(); 1002 let mut ctx = BigNumContext::new().unwrap(); 1003 let bytes = point 1004 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) 1005 .unwrap(); 1006 let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); 1007 assert!(point.eq(&group, &point2, &mut ctx).unwrap()); 1008 } 1009 1010 #[test] point_owned()1011 fn point_owned() { 1012 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1013 let key = EcKey::generate(&group).unwrap(); 1014 let point = key.public_key(); 1015 let owned = point.to_owned(&group).unwrap(); 1016 let mut ctx = BigNumContext::new().unwrap(); 1017 assert!(owned.eq(&group, point, &mut ctx).unwrap()); 1018 } 1019 1020 #[test] mul_generator()1021 fn mul_generator() { 1022 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1023 let key = EcKey::generate(&group).unwrap(); 1024 let mut ctx = BigNumContext::new().unwrap(); 1025 let mut public_key = EcPoint::new(&group).unwrap(); 1026 public_key 1027 .mul_generator(&group, key.private_key(), &ctx) 1028 .unwrap(); 1029 assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap()); 1030 } 1031 1032 #[test] generator()1033 fn generator() { 1034 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1035 let gen = group.generator(); 1036 let one = BigNum::from_u32(1).unwrap(); 1037 let mut ctx = BigNumContext::new().unwrap(); 1038 let mut ecp = EcPoint::new(&group).unwrap(); 1039 ecp.mul_generator(&group, &one, &ctx).unwrap(); 1040 assert!(ecp.eq(&group, gen, &mut ctx).unwrap()); 1041 } 1042 1043 #[test] key_from_public_key()1044 fn key_from_public_key() { 1045 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1046 let key = EcKey::generate(&group).unwrap(); 1047 let mut ctx = BigNumContext::new().unwrap(); 1048 let bytes = key 1049 .public_key() 1050 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) 1051 .unwrap(); 1052 1053 drop(key); 1054 let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); 1055 let ec_key = EcKey::from_public_key(&group, &public_key).unwrap(); 1056 assert!(ec_key.check_key().is_ok()); 1057 } 1058 1059 #[test] key_from_private_components()1060 fn key_from_private_components() { 1061 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1062 let key = EcKey::generate(&group).unwrap(); 1063 1064 let dup_key = 1065 EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap(); 1066 dup_key.check_key().unwrap(); 1067 1068 assert!(key.private_key() == dup_key.private_key()); 1069 } 1070 1071 #[test] key_from_affine_coordinates()1072 fn key_from_affine_coordinates() { 1073 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1074 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") 1075 .unwrap(); 1076 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") 1077 .unwrap(); 1078 1079 let xbn = BigNum::from_slice(&x).unwrap(); 1080 let ybn = BigNum::from_slice(&y).unwrap(); 1081 1082 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); 1083 assert!(ec_key.check_key().is_ok()); 1084 } 1085 1086 #[test] get_affine_coordinates()1087 fn get_affine_coordinates() { 1088 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1089 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") 1090 .unwrap(); 1091 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") 1092 .unwrap(); 1093 1094 let xbn = BigNum::from_slice(&x).unwrap(); 1095 let ybn = BigNum::from_slice(&y).unwrap(); 1096 1097 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); 1098 1099 let mut xbn2 = BigNum::new().unwrap(); 1100 let mut ybn2 = BigNum::new().unwrap(); 1101 let mut ctx = BigNumContext::new().unwrap(); 1102 let ec_key_pk = ec_key.public_key(); 1103 ec_key_pk 1104 .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx) 1105 .unwrap(); 1106 assert_eq!(xbn2, xbn); 1107 assert_eq!(ybn2, ybn); 1108 } 1109 1110 #[test] is_infinity()1111 fn is_infinity() { 1112 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1113 let mut ctx = BigNumContext::new().unwrap(); 1114 let g = group.generator(); 1115 assert_eq!(g.is_infinity(&group), false); 1116 1117 let mut order = BigNum::new().unwrap(); 1118 group.order(&mut order, &mut ctx).unwrap(); 1119 let mut inf = EcPoint::new(&group).unwrap(); 1120 inf.mul_generator(&group, &order, &ctx).unwrap(); 1121 assert_eq!(inf.is_infinity(&group), true); 1122 } 1123 1124 #[test] is_on_curve()1125 fn is_on_curve() { 1126 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1127 let mut ctx = BigNumContext::new().unwrap(); 1128 let g = group.generator(); 1129 assert_eq!(g.is_on_curve(&group, &mut ctx).unwrap(), true); 1130 1131 let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap(); 1132 assert_eq!(g.is_on_curve(&group2, &mut ctx).unwrap(), false); 1133 } 1134 } 1135