Skip to content

Commit ddd3176

Browse files
committed
Split general error into specific
Currently we have a large general error type. Create specific error types for each function as needed so that a function returns ever variant available in its return type.
1 parent 7bd28e1 commit ddd3176

14 files changed

+1001
-305
lines changed

examples/sign_verify_recovery.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ extern crate secp256k1;
44
use hashes::{sha256, Hash};
55
use secp256k1::{ecdsa, Error, Message, PublicKey, Secp256k1, SecretKey, Signing, Verification};
66

7+
// Notice that we provide a general error type for this crate and conversion
8+
// functions to it from all the other error types so `?` works as expected.
79
fn recover<C: Verification>(
810
secp: &Secp256k1<C>,
911
msg: &[u8],
@@ -15,7 +17,8 @@ fn recover<C: Verification>(
1517
let id = ecdsa::RecoveryId::from_i32(recovery_id as i32)?;
1618
let sig = ecdsa::RecoverableSignature::from_compact(&sig, id)?;
1719

18-
secp.recover_ecdsa(&msg, &sig)
20+
let pk = secp.recover_ecdsa(&msg, &sig)?;
21+
Ok(pk)
1922
}
2023

2124
fn sign_recovery<C: Signing>(

src/ecdh.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ use secp256k1_sys::types::{c_int, c_uchar, c_void};
1111

1212
use crate::ffi::{self, CPtr};
1313
use crate::key::{PublicKey, SecretKey};
14-
use crate::{constants, hex, Error};
14+
use crate::{constants, hex};
15+
16+
#[rustfmt::skip] // Keep public re-exports separate.
17+
pub use crate::{
18+
error::InvalidSliceLengthError,
19+
hex::FromHexError,
20+
};
1521

1622
// The logic for displaying shared secrets relies on this (see `secret.rs`).
1723
const SHARED_SECRET_SIZE: usize = constants::SECRET_KEY_SIZE;
@@ -66,22 +72,20 @@ impl SharedSecret {
6672

6773
/// Creates a shared secret from `bytes` slice.
6874
#[inline]
69-
pub fn from_slice(bytes: &[u8]) -> Result<SharedSecret, Error> {
75+
pub fn from_slice(bytes: &[u8]) -> Result<SharedSecret, InvalidSliceLengthError> {
7076
match <[u8; SHARED_SECRET_SIZE]>::try_from(bytes) {
7177
Ok(bytes) => Ok(SharedSecret(bytes)),
72-
Err(_) => Err(Error::InvalidSharedSecret),
78+
Err(_) =>
79+
Err(InvalidSliceLengthError { got: bytes.len(), expected: SHARED_SECRET_SIZE }),
7380
}
7481
}
7582
}
7683

7784
impl str::FromStr for SharedSecret {
78-
type Err = Error;
85+
type Err = FromHexError;
7986
fn from_str(s: &str) -> Result<Self, Self::Err> {
8087
let mut res = [0u8; SHARED_SECRET_SIZE];
81-
match hex::from_hex(s, &mut res) {
82-
Ok(SHARED_SECRET_SIZE) => Ok(SharedSecret::from_bytes(res)),
83-
_ => Err(Error::InvalidSharedSecret),
84-
}
88+
hex::from_hex(s, &mut res).map(|_| SharedSecret::from_bytes(res))
8589
}
8690
}
8791

src/ecdsa/mod.rs

+110-21
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ pub mod serialized_signature;
1010
use core::{fmt, ptr, str};
1111

1212
#[cfg(feature = "recovery")]
13-
pub use self::recovery::{RecoverableSignature, RecoveryId};
13+
pub use self::recovery::{InvalidRecoveryIdError, RecoverableSignature, RecoveryId};
1414
pub use self::serialized_signature::SerializedSignature;
15+
use crate::error::{write_err, InvalidSliceLengthError, SysError};
1516
use crate::ffi::CPtr;
17+
use crate::hex::{self, FromHexError};
1618
#[cfg(feature = "global-context")]
1719
use crate::SECP256K1;
18-
use crate::{ffi, hex, Error, Message, PublicKey, Secp256k1, SecretKey, Signing, Verification};
20+
use crate::{ffi, Message, PublicKey, Secp256k1, SecretKey, Signing, Verification};
1921

2022
/// An ECDSA signature
2123
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
@@ -34,22 +36,21 @@ impl fmt::Display for Signature {
3436
}
3537

3638
impl str::FromStr for Signature {
37-
type Err = Error;
39+
type Err = SignatureParseError;
3840
fn from_str(s: &str) -> Result<Self, Self::Err> {
3941
let mut res = [0u8; 72];
40-
match hex::from_hex(s, &mut res) {
41-
Ok(x) => Signature::from_der(&res[0..x]),
42-
_ => Err(Error::InvalidSignature),
43-
}
42+
let len = hex::from_hex(s, &mut res)?;
43+
let sig = Signature::from_der(&res[0..len])?;
44+
Ok(sig)
4445
}
4546
}
4647

4748
impl Signature {
4849
#[inline]
4950
/// Converts a DER-encoded byte slice to a signature
50-
pub fn from_der(data: &[u8]) -> Result<Signature, Error> {
51+
pub fn from_der(data: &[u8]) -> Result<Signature, SignatureError> {
5152
if data.is_empty() {
52-
return Err(Error::InvalidSignature);
53+
return Err(SignatureError::EmptySlice);
5354
}
5455

5556
unsafe {
@@ -63,15 +64,15 @@ impl Signature {
6364
{
6465
Ok(Signature(ret))
6566
} else {
66-
Err(Error::InvalidSignature)
67+
Err(SignatureError::Sys(SysError {}))
6768
}
6869
}
6970
}
7071

7172
/// Converts a 64-byte compact-encoded byte slice to a signature
72-
pub fn from_compact(data: &[u8]) -> Result<Signature, Error> {
73+
pub fn from_compact(data: &[u8]) -> Result<Signature, SignatureError> {
7374
if data.len() != 64 {
74-
return Err(Error::InvalidSignature);
75+
return Err(SignatureError::invalid_length(data.len()));
7576
}
7677

7778
unsafe {
@@ -84,7 +85,7 @@ impl Signature {
8485
{
8586
Ok(Signature(ret))
8687
} else {
87-
Err(Error::InvalidSignature)
88+
Err(SignatureError::Sys(SysError {}))
8889
}
8990
}
9091
}
@@ -93,9 +94,9 @@ impl Signature {
9394
/// only useful for validating signatures in the Bitcoin blockchain from before
9495
/// 2016. It should never be used in new applications. This library does not
9596
/// support serializing to this "format"
96-
pub fn from_der_lax(data: &[u8]) -> Result<Signature, Error> {
97+
pub fn from_der_lax(data: &[u8]) -> Result<Signature, SignatureError> {
9798
if data.is_empty() {
98-
return Err(Error::InvalidSignature);
99+
return Err(SignatureError::EmptySlice);
99100
}
100101

101102
unsafe {
@@ -109,7 +110,7 @@ impl Signature {
109110
{
110111
Ok(Signature(ret))
111112
} else {
112-
Err(Error::InvalidSignature)
113+
Err(SignatureError::Sys(SysError {}))
113114
}
114115
}
115116
}
@@ -192,7 +193,7 @@ impl Signature {
192193
/// The signature must be normalized or verification will fail (see [`Signature::normalize_s`]).
193194
#[inline]
194195
#[cfg(feature = "global-context")]
195-
pub fn verify(&self, msg: &Message, pk: &PublicKey) -> Result<(), Error> {
196+
pub fn verify(&self, msg: &Message, pk: &PublicKey) -> Result<(), SysError> {
196197
SECP256K1.verify_ecdsa(msg, self, pk)
197198
}
198199
}
@@ -364,7 +365,7 @@ impl<C: Verification> Secp256k1<C> {
364365
///
365366
/// ```rust
366367
/// # #[cfg(feature = "rand-std")] {
367-
/// # use secp256k1::{rand, Secp256k1, Message, Error};
368+
/// # use secp256k1::{ecdsa, rand, Secp256k1, Message, SysError};
368369
/// #
369370
/// # let secp = Secp256k1::new();
370371
/// # let (secret_key, public_key) = secp.generate_keypair(&mut rand::thread_rng());
@@ -374,7 +375,7 @@ impl<C: Verification> Secp256k1<C> {
374375
/// assert_eq!(secp.verify_ecdsa(&message, &sig, &public_key), Ok(()));
375376
///
376377
/// let message = Message::from_digest_slice(&[0xcd; 32]).expect("32 bytes");
377-
/// assert_eq!(secp.verify_ecdsa(&message, &sig, &public_key), Err(Error::IncorrectSignature));
378+
/// assert!(matches!(secp.verify_ecdsa(&message, &sig, &public_key), Err(SysError)));
378379
/// # }
379380
/// ```
380381
#[inline]
@@ -383,7 +384,7 @@ impl<C: Verification> Secp256k1<C> {
383384
msg: &Message,
384385
sig: &Signature,
385386
pk: &PublicKey,
386-
) -> Result<(), Error> {
387+
) -> Result<(), SysError> {
387388
unsafe {
388389
if ffi::secp256k1_ecdsa_verify(
389390
self.ctx.as_ptr(),
@@ -392,7 +393,7 @@ impl<C: Verification> Secp256k1<C> {
392393
pk.as_c_ptr(),
393394
) == 0
394395
{
395-
Err(Error::IncorrectSignature)
396+
Err(SysError {})
396397
} else {
397398
Ok(())
398399
}
@@ -427,3 +428,91 @@ pub(crate) fn der_length_check(sig: &ffi::Signature, max_len: usize) -> bool {
427428
}
428429
len <= max_len
429430
}
431+
432+
/// Signature is invalid.
433+
#[derive(Debug, Clone, PartialEq, Eq)]
434+
#[non_exhaustive]
435+
pub enum SignatureError {
436+
/// Tried to create signature from an empty slice.
437+
EmptySlice,
438+
/// Tried to create signature from an invalid length slice.
439+
InvalidSliceLength(InvalidSliceLengthError),
440+
/// FFI call failed.
441+
Sys(SysError),
442+
}
443+
444+
impl SignatureError {
445+
fn invalid_length(len: usize) -> Self {
446+
InvalidSliceLengthError { got: len, expected: 64 }.into()
447+
}
448+
}
449+
450+
impl fmt::Display for SignatureError {
451+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
452+
use SignatureError::*;
453+
454+
match *self {
455+
EmptySlice => write!(f, "tried to create signature from an empty slice"),
456+
InvalidSliceLength(ref e) =>
457+
write_err!(f, "tried to create signature from an invalid length slice"; e),
458+
Sys(ref e) => write_err!(f, "sys error"; e),
459+
}
460+
}
461+
}
462+
463+
#[cfg(feature = "std")]
464+
impl std::error::Error for SignatureError {
465+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
466+
use SignatureError::*;
467+
468+
match *self {
469+
EmptySlice => None,
470+
InvalidSliceLength(ref e) => Some(e),
471+
Sys(ref e) => Some(e),
472+
}
473+
}
474+
}
475+
476+
impl From<InvalidSliceLengthError> for SignatureError {
477+
fn from(e: InvalidSliceLengthError) -> Self { Self::InvalidSliceLength(e) }
478+
}
479+
480+
/// Signature is invalid.
481+
#[derive(Debug, Clone, PartialEq, Eq)]
482+
pub enum SignatureParseError {
483+
/// Invalid hex string.
484+
Hex(FromHexError),
485+
/// Invalid signature.
486+
Sig(SignatureError),
487+
}
488+
489+
impl fmt::Display for SignatureParseError {
490+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
491+
use SignatureParseError::*;
492+
493+
match *self {
494+
Hex(ref e) => write_err!(f, "error decoding hex"; e),
495+
Sig(ref e) => write_err!(f, "invalid signature"; e),
496+
}
497+
}
498+
}
499+
500+
#[cfg(feature = "std")]
501+
impl std::error::Error for SignatureParseError {
502+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
503+
use SignatureParseError::*;
504+
505+
match *self {
506+
Hex(ref e) => Some(e),
507+
Sig(ref e) => Some(e),
508+
}
509+
}
510+
}
511+
512+
impl From<FromHexError> for SignatureParseError {
513+
fn from(e: FromHexError) -> Self { Self::Hex(e) }
514+
}
515+
516+
impl From<SignatureError> for SignatureParseError {
517+
fn from(e: SignatureError) -> Self { Self::Sig(e) }
518+
}

0 commit comments

Comments
 (0)