|
1 | 1 | //! Structs and functionality related to the ECDSA signature algorithm.
|
2 | 2 |
|
3 |
| -use core::{fmt, str, ops}; |
4 |
| -use Error; |
| 3 | +use core::{fmt, str, ops, ptr, mem}; |
| 4 | + |
| 5 | +use {Signing, Verification, Message, PublicKey, Secp256k1, SecretKey, from_hex, Error, ffi}; |
5 | 6 | use ffi::CPtr;
|
6 |
| -use ffi; |
7 |
| -use from_hex; |
8 | 7 |
|
9 | 8 | #[cfg(feature = "recovery")]
|
10 | 9 | mod recovery;
|
@@ -305,3 +304,199 @@ impl<'de> ::serde::Deserialize<'de> for Signature {
|
305 | 304 | }
|
306 | 305 | }
|
307 | 306 | }
|
| 307 | + |
| 308 | +impl<C: Signing> Secp256k1<C> { |
| 309 | + |
| 310 | + /// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce |
| 311 | + /// Requires a signing-capable context. |
| 312 | + #[deprecated(since = "0.21.0", note = "Use sign_ecdsa instead.")] |
| 313 | + pub fn sign(&self, msg: &Message, sk: &SecretKey) -> Signature { |
| 314 | + self.sign_ecdsa(msg, sk) |
| 315 | + } |
| 316 | + |
| 317 | + /// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce |
| 318 | + /// Requires a signing-capable context. |
| 319 | + pub fn sign_ecdsa(&self, msg: &Message, sk: &SecretKey) -> Signature { |
| 320 | + unsafe { |
| 321 | + let mut ret = ffi::Signature::new(); |
| 322 | + // We can assume the return value because it's not possible to construct |
| 323 | + // an invalid signature from a valid `Message` and `SecretKey` |
| 324 | + assert_eq!(ffi::secp256k1_ecdsa_sign(self.ctx, &mut ret, msg.as_c_ptr(), |
| 325 | + sk.as_c_ptr(), ffi::secp256k1_nonce_function_rfc6979, |
| 326 | + ptr::null()), 1); |
| 327 | + Signature::from(ret) |
| 328 | + } |
| 329 | + } |
| 330 | + |
| 331 | + fn sign_grind_with_check( |
| 332 | + &self, msg: &Message, |
| 333 | + sk: &SecretKey, |
| 334 | + check: impl Fn(&ffi::Signature) -> bool) -> Signature { |
| 335 | + let mut entropy_p : *const ffi::types::c_void = ptr::null(); |
| 336 | + let mut counter : u32 = 0; |
| 337 | + let mut extra_entropy = [0u8; 32]; |
| 338 | + loop { |
| 339 | + unsafe { |
| 340 | + let mut ret = ffi::Signature::new(); |
| 341 | + // We can assume the return value because it's not possible to construct |
| 342 | + // an invalid signature from a valid `Message` and `SecretKey` |
| 343 | + assert_eq!(ffi::secp256k1_ecdsa_sign(self.ctx, &mut ret, msg.as_c_ptr(), |
| 344 | + sk.as_c_ptr(), ffi::secp256k1_nonce_function_rfc6979, |
| 345 | + entropy_p), 1); |
| 346 | + if check(&ret) { |
| 347 | + return Signature::from(ret); |
| 348 | + } |
| 349 | + |
| 350 | + counter += 1; |
| 351 | + // From 1.32 can use `to_le_bytes` instead |
| 352 | + let le_counter = counter.to_le(); |
| 353 | + let le_counter_bytes : [u8; 4] = mem::transmute(le_counter); |
| 354 | + for (i, b) in le_counter_bytes.iter().enumerate() { |
| 355 | + extra_entropy[i] = *b; |
| 356 | + } |
| 357 | + |
| 358 | + entropy_p = extra_entropy.as_ptr() as *const ffi::types::c_void; |
| 359 | + |
| 360 | + // When fuzzing, these checks will usually spinloop forever, so just short-circuit them. |
| 361 | + #[cfg(fuzzing)] |
| 362 | + return Signature::from(ret); |
| 363 | + } |
| 364 | + } |
| 365 | + } |
| 366 | + |
| 367 | + /// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce |
| 368 | + /// and "grinds" the nonce by passing extra entropy if necessary to produce |
| 369 | + /// a signature that is less than 71 - bytes_to_grund bytes. The number |
| 370 | + /// of signing operation performed by this function is exponential in the |
| 371 | + /// number of bytes grinded. |
| 372 | + /// Requires a signing capable context. |
| 373 | + #[deprecated(since = "0.21.0", note = "Use sign_ecdsa_grind_r instead.")] |
| 374 | + pub fn sign_grind_r(&self, msg: &Message, sk: &SecretKey, bytes_to_grind: usize) -> Signature { |
| 375 | + self.sign_ecdsa_grind_r(msg, sk, bytes_to_grind) |
| 376 | + } |
| 377 | + |
| 378 | + /// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce |
| 379 | + /// and "grinds" the nonce by passing extra entropy if necessary to produce |
| 380 | + /// a signature that is less than 71 - bytes_to_grund bytes. The number |
| 381 | + /// of signing operation performed by this function is exponential in the |
| 382 | + /// number of bytes grinded. |
| 383 | + /// Requires a signing capable context. |
| 384 | + pub fn sign_ecdsa_grind_r(&self, msg: &Message, sk: &SecretKey, bytes_to_grind: usize) -> Signature { |
| 385 | + let len_check = |s : &ffi::Signature| der_length_check(s, 71 - bytes_to_grind); |
| 386 | + return self.sign_grind_with_check(msg, sk, len_check); |
| 387 | + } |
| 388 | + |
| 389 | + /// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce |
| 390 | + /// and "grinds" the nonce by passing extra entropy if necessary to produce |
| 391 | + /// a signature that is less than 71 bytes and compatible with the low r |
| 392 | + /// signature implementation of bitcoin core. In average, this function |
| 393 | + /// will perform two signing operations. |
| 394 | + /// Requires a signing capable context. |
| 395 | + #[deprecated(since = "0.21.0", note = "Use sign_ecdsa_grind_r instead.")] |
| 396 | + pub fn sign_low_r(&self, msg: &Message, sk: &SecretKey) -> Signature { |
| 397 | + return self.sign_grind_with_check(msg, sk, compact_sig_has_zero_first_bit) |
| 398 | + } |
| 399 | + |
| 400 | + /// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce |
| 401 | + /// and "grinds" the nonce by passing extra entropy if necessary to produce |
| 402 | + /// a signature that is less than 71 bytes and compatible with the low r |
| 403 | + /// signature implementation of bitcoin core. In average, this function |
| 404 | + /// will perform two signing operations. |
| 405 | + /// Requires a signing capable context. |
| 406 | + pub fn sign_ecdsa_low_r(&self, msg: &Message, sk: &SecretKey) -> Signature { |
| 407 | + return self.sign_grind_with_check(msg, sk, compact_sig_has_zero_first_bit) |
| 408 | + } |
| 409 | +} |
| 410 | + |
| 411 | +impl<C: Verification> Secp256k1<C> { |
| 412 | + /// Checks that `sig` is a valid ECDSA signature for `msg` using the public |
| 413 | + /// key `pubkey`. Returns `Ok(())` on success. Note that this function cannot |
| 414 | + /// be used for Bitcoin consensus checking since there may exist signatures |
| 415 | + /// which OpenSSL would verify but not libsecp256k1, or vice-versa. Requires a |
| 416 | + /// verify-capable context. |
| 417 | + /// |
| 418 | + /// ```rust |
| 419 | + /// # #[cfg(feature="rand")] { |
| 420 | + /// # use secp256k1::rand::rngs::OsRng; |
| 421 | + /// # use secp256k1::{Secp256k1, Message, Error}; |
| 422 | + /// # |
| 423 | + /// # let secp = Secp256k1::new(); |
| 424 | + /// # let mut rng = OsRng::new().expect("OsRng"); |
| 425 | + /// # let (secret_key, public_key) = secp.generate_keypair(&mut rng); |
| 426 | + /// # |
| 427 | + /// let message = Message::from_slice(&[0xab; 32]).expect("32 bytes"); |
| 428 | + /// let sig = secp.sign(&message, &secret_key); |
| 429 | + /// assert_eq!(secp.verify(&message, &sig, &public_key), Ok(())); |
| 430 | + /// |
| 431 | + /// let message = Message::from_slice(&[0xcd; 32]).expect("32 bytes"); |
| 432 | + /// assert_eq!(secp.verify(&message, &sig, &public_key), Err(Error::IncorrectSignature)); |
| 433 | + /// # } |
| 434 | + /// ``` |
| 435 | + #[inline] |
| 436 | + #[deprecated(since = "0.21.0", note = "Use verify_ecdsa instead")] |
| 437 | + pub fn verify(&self, msg: &Message, sig: &Signature, pk: &PublicKey) -> Result<(), Error> { |
| 438 | + self.verify_ecdsa(msg, sig, pk) |
| 439 | + } |
| 440 | + |
| 441 | + /// Checks that `sig` is a valid ECDSA signature for `msg` using the public |
| 442 | + /// key `pubkey`. Returns `Ok(())` on success. Note that this function cannot |
| 443 | + /// be used for Bitcoin consensus checking since there may exist signatures |
| 444 | + /// which OpenSSL would verify but not libsecp256k1, or vice-versa. Requires a |
| 445 | + /// verify-capable context. |
| 446 | + /// |
| 447 | + /// ```rust |
| 448 | + /// # #[cfg(feature="rand")] { |
| 449 | + /// # use secp256k1::rand::rngs::OsRng; |
| 450 | + /// # use secp256k1::{Secp256k1, Message, Error}; |
| 451 | + /// # |
| 452 | + /// # let secp = Secp256k1::new(); |
| 453 | + /// # let mut rng = OsRng::new().expect("OsRng"); |
| 454 | + /// # let (secret_key, public_key) = secp.generate_keypair(&mut rng); |
| 455 | + /// # |
| 456 | + /// let message = Message::from_slice(&[0xab; 32]).expect("32 bytes"); |
| 457 | + /// let sig = secp.sign_ecdsa(&message, &secret_key); |
| 458 | + /// assert_eq!(secp.verify_ecdsa(&message, &sig, &public_key), Ok(())); |
| 459 | + /// |
| 460 | + /// let message = Message::from_slice(&[0xcd; 32]).expect("32 bytes"); |
| 461 | + /// assert_eq!(secp.verify_ecdsa(&message, &sig, &public_key), Err(Error::IncorrectSignature)); |
| 462 | + /// # } |
| 463 | + /// ``` |
| 464 | + #[inline] |
| 465 | + pub fn verify_ecdsa(&self, msg: &Message, sig: &Signature, pk: &PublicKey) -> Result<(), Error> { |
| 466 | + unsafe { |
| 467 | + if ffi::secp256k1_ecdsa_verify(self.ctx, sig.as_c_ptr(), msg.as_c_ptr(), pk.as_c_ptr()) == 0 { |
| 468 | + Err(Error::IncorrectSignature) |
| 469 | + } else { |
| 470 | + Ok(()) |
| 471 | + } |
| 472 | + } |
| 473 | + } |
| 474 | +} |
| 475 | + |
| 476 | +pub(crate) fn compact_sig_has_zero_first_bit(sig: &ffi::Signature) -> bool { |
| 477 | + let mut compact = [0u8; 64]; |
| 478 | + unsafe { |
| 479 | + let err = ffi::secp256k1_ecdsa_signature_serialize_compact( |
| 480 | + ffi::secp256k1_context_no_precomp, |
| 481 | + compact.as_mut_c_ptr(), |
| 482 | + sig, |
| 483 | + ); |
| 484 | + debug_assert!(err == 1); |
| 485 | + } |
| 486 | + compact[0] < 0x80 |
| 487 | +} |
| 488 | + |
| 489 | +pub(crate) fn der_length_check(sig: &ffi::Signature, max_len: usize) -> bool { |
| 490 | + let mut ser_ret = [0u8; 72]; |
| 491 | + let mut len: usize = ser_ret.len(); |
| 492 | + unsafe { |
| 493 | + let err = ffi::secp256k1_ecdsa_signature_serialize_der( |
| 494 | + ffi::secp256k1_context_no_precomp, |
| 495 | + ser_ret.as_mut_c_ptr(), |
| 496 | + &mut len, |
| 497 | + sig, |
| 498 | + ); |
| 499 | + debug_assert!(err == 1); |
| 500 | + } |
| 501 | + len <= max_len |
| 502 | +} |
0 commit comments