Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4e72db6

Browse files
committedNov 8, 2023
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 4e72db6

14 files changed

+1012
-312
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 string 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+
}

‎src/ecdsa/recovery.rs

+37-16
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
//! signature.
55
//!
66
7-
use core::ptr;
7+
use core::{fmt, ptr};
88

99
use self::super_ffi::CPtr;
10-
use super::ffi as super_ffi;
10+
use super::{ffi as super_ffi, SignatureError};
1111
use crate::ecdsa::Signature;
12+
use crate::error::SysError;
1213
use crate::ffi::recovery as ffi;
13-
use crate::{key, Error, Message, Secp256k1, Signing, Verification};
14+
use crate::{key, Message, Secp256k1, Signing, Verification};
1415

1516
/// A tag used for recovering the public key from a compact signature.
1617
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -23,10 +24,10 @@ pub struct RecoverableSignature(ffi::RecoverableSignature);
2324
impl RecoveryId {
2425
#[inline]
2526
/// Allows library users to create valid recovery IDs from i32.
26-
pub fn from_i32(id: i32) -> Result<RecoveryId, Error> {
27+
pub fn from_i32(id: i32) -> Result<RecoveryId, InvalidRecoveryIdError> {
2728
match id {
2829
0..=3 => Ok(RecoveryId(id)),
29-
_ => Err(Error::InvalidRecoveryId),
30+
other => Err(InvalidRecoveryIdError(other)),
3031
}
3132
}
3233

@@ -39,16 +40,19 @@ impl RecoverableSignature {
3940
#[inline]
4041
/// Converts a compact-encoded byte slice to a signature. This
4142
/// representation is nonstandard and defined by the libsecp256k1 library.
42-
pub fn from_compact(data: &[u8], recid: RecoveryId) -> Result<RecoverableSignature, Error> {
43+
pub fn from_compact(
44+
data: &[u8],
45+
recid: RecoveryId,
46+
) -> Result<RecoverableSignature, SignatureError> {
4347
if data.is_empty() {
44-
return Err(Error::InvalidSignature);
48+
return Err(SignatureError::EmptySlice);
4549
}
4650

4751
let mut ret = ffi::RecoverableSignature::new();
4852

4953
unsafe {
5054
if data.len() != 64 {
51-
Err(Error::InvalidSignature)
55+
Err(SignatureError::invalid_length(data.len()))
5256
} else if ffi::secp256k1_ecdsa_recoverable_signature_parse_compact(
5357
super_ffi::secp256k1_context_no_precomp,
5458
&mut ret,
@@ -58,7 +62,7 @@ impl RecoverableSignature {
5862
{
5963
Ok(RecoverableSignature(ret))
6064
} else {
61-
Err(Error::InvalidSignature)
65+
Err(SignatureError::Sys(SysError {}))
6266
}
6367
}
6468
}
@@ -113,7 +117,7 @@ impl RecoverableSignature {
113117
/// verify-capable context.
114118
#[inline]
115119
#[cfg(feature = "global-context")]
116-
pub fn recover(&self, msg: &Message) -> Result<key::PublicKey, Error> {
120+
pub fn recover(&self, msg: &Message) -> Result<key::PublicKey, SignatureError> {
117121
crate::SECP256K1.recover_ecdsa(msg, self)
118122
}
119123
}
@@ -191,7 +195,7 @@ impl<C: Verification> Secp256k1<C> {
191195
&self,
192196
msg: &Message,
193197
sig: &RecoverableSignature,
194-
) -> Result<key::PublicKey, Error> {
198+
) -> Result<key::PublicKey, SignatureError> {
195199
unsafe {
196200
let mut pk = super_ffi::PublicKey::new();
197201
if ffi::secp256k1_ecdsa_recover(
@@ -201,22 +205,39 @@ impl<C: Verification> Secp256k1<C> {
201205
msg.as_c_ptr(),
202206
) != 1
203207
{
204-
return Err(Error::InvalidSignature);
208+
return Err(SignatureError::Sys(SysError {}));
205209
}
206210
Ok(key::PublicKey::from(pk))
207211
}
208212
}
209213
}
210214

215+
/// Recovery ID is invalid.
216+
#[derive(Debug, Clone, PartialEq, Eq)]
217+
#[non_exhaustive]
218+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
219+
pub struct InvalidRecoveryIdError(pub i32);
220+
221+
impl fmt::Display for InvalidRecoveryIdError {
222+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
223+
write!(f, "recovery ID is invalid: {}", self.0)
224+
}
225+
}
226+
227+
#[cfg(feature = "std")]
228+
impl std::error::Error for InvalidRecoveryIdError {
229+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
230+
}
231+
211232
#[cfg(test)]
212233
#[allow(unused_imports)]
213234
mod tests {
214235
#[cfg(target_arch = "wasm32")]
215236
use wasm_bindgen_test::wasm_bindgen_test as test;
216237

217-
use super::{RecoverableSignature, RecoveryId};
238+
use super::*;
218239
use crate::constants::ONE;
219-
use crate::{Error, Message, Secp256k1, SecretKey};
240+
use crate::{Message, Secp256k1, SecretKey};
220241

221242
#[test]
222243
#[cfg(feature = "rand-std")]
@@ -316,7 +337,7 @@ mod tests {
316337

317338
let msg = crate::random_32_bytes(&mut rand::thread_rng());
318339
let msg = Message::from_digest_slice(&msg).unwrap();
319-
assert_eq!(s.verify_ecdsa(&msg, &sig, &pk), Err(Error::IncorrectSignature));
340+
assert_eq!(s.verify_ecdsa(&msg, &sig, &pk), Err(SysError {}));
320341

321342
let recovered_key = s.recover_ecdsa(&msg, &sigr).unwrap();
322343
assert!(recovered_key != pk);
@@ -366,7 +387,7 @@ mod tests {
366387

367388
// Zero is not a valid sig
368389
let sig = RecoverableSignature::from_compact(&[0; 64], RecoveryId(0)).unwrap();
369-
assert_eq!(s.recover_ecdsa(&msg, &sig), Err(Error::InvalidSignature));
390+
assert_eq!(s.recover_ecdsa(&msg, &sig), Err(SignatureError::Sys(SysError {})));
370391
// ...but 111..111 is
371392
let sig = RecoverableSignature::from_compact(&[1; 64], RecoveryId(0)).unwrap();
372393
assert!(s.recover_ecdsa(&msg, &sig).is_ok());

‎src/ecdsa/serialized_signature.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ use core::{fmt, ops};
1313

1414
pub use into_iter::IntoIter;
1515

16-
use super::Signature;
17-
use crate::Error;
16+
use super::{Signature, SignatureError};
1817

1918
pub(crate) const MAX_LEN: usize = 72;
2019

@@ -123,13 +122,13 @@ impl<'a> From<&'a Signature> for SerializedSignature {
123122
}
124123

125124
impl TryFrom<SerializedSignature> for Signature {
126-
type Error = Error;
125+
type Error = SignatureError;
127126

128127
fn try_from(value: SerializedSignature) -> Result<Self, Self::Error> { value.to_signature() }
129128
}
130129

131130
impl<'a> TryFrom<&'a SerializedSignature> for Signature {
132-
type Error = Error;
131+
type Error = SignatureError;
133132

134133
fn try_from(value: &'a SerializedSignature) -> Result<Self, Self::Error> {
135134
value.to_signature()
@@ -164,7 +163,7 @@ impl SerializedSignature {
164163
/// Convert the serialized signature into the Signature struct.
165164
/// (This DER deserializes it)
166165
#[inline]
167-
pub fn to_signature(&self) -> Result<Signature, Error> { Signature::from_der(self) }
166+
pub fn to_signature(&self) -> Result<Signature, SignatureError> { Signature::from_der(self) }
168167

169168
/// Create a SerializedSignature from a Signature.
170169
/// (this DER serializes it)

‎src/ellswift.rs

+20-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use core::str::FromStr;
4242
use ffi::CPtr;
4343
use secp256k1_sys::types::{c_int, c_uchar, c_void};
4444

45-
use crate::{constants, ffi, hex, Error, PublicKey, Secp256k1, SecretKey, Verification};
45+
use crate::{constants, ffi, hex, PublicKey, Secp256k1, SecretKey, Verification};
4646

4747
unsafe extern "C" fn hash_callback<F>(
4848
output: *mut c_uchar,
@@ -288,14 +288,14 @@ impl ElligatorSwiftParty {
288288
}
289289

290290
impl FromStr for ElligatorSwift {
291-
type Err = Error;
291+
type Err = ParseError;
292292

293293
fn from_str(hex: &str) -> Result<Self, Self::Err> {
294294
let mut ser = [0u8; 64];
295295
let parsed = hex::from_hex(hex, &mut ser);
296296
match parsed {
297297
Ok(64) => Ok(ElligatorSwift::from_array(ser)),
298-
_ => Err(Error::InvalidEllSwift),
298+
_ => Err(ParseError),
299299
}
300300
}
301301
}
@@ -320,6 +320,23 @@ impl ffi::CPtr for ElligatorSwift {
320320
fn as_c_ptr(&self) -> *const Self::Target { self.0.as_c_ptr() }
321321
}
322322

323+
/// Error converting from a hex string.
324+
#[derive(Debug, Clone, PartialEq, Eq)]
325+
#[non_exhaustive]
326+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
327+
pub struct ParseError;
328+
329+
impl core::fmt::Display for ParseError {
330+
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
331+
write!(f, "error converting hex to ellswift")
332+
}
333+
}
334+
335+
#[cfg(feature = "std")]
336+
impl std::error::Error for ParseError {
337+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
338+
}
339+
323340
#[cfg(test)]
324341
mod tests {
325342
use core::str::FromStr;

‎src/error.rs

+378
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,378 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
//! Error types and conversion functions.
4+
5+
use core::fmt;
6+
7+
use crate::context::NotEnoughMemoryError;
8+
use crate::hex::{FromHexError, ToHexError};
9+
use crate::key::error::{
10+
ParityValueError, PublicKeyError, PublicKeySumError, SecretKeyError, TweakError,
11+
XOnlyTweakError,
12+
};
13+
use crate::{ecdh, ecdsa, ellswift, scalar, schnorr, MessageLengthError};
14+
15+
/// Implements `From<E> for $error` for all the errors in this crate.
16+
///
17+
/// Either pass in the variant to use or have a variant `Secp256k1` on `$error`.
18+
///
19+
/// # Examples
20+
///
21+
/// ```
22+
/// # #[cfg(feature = "rand-std")] {
23+
/// use secp256k1::{PublicKey, SecretKey, Secp256k1};
24+
///
25+
/// // Use the a general `secp256k1::Error`.
26+
///
27+
/// /// Foo error.
28+
/// pub struct FooError;
29+
///
30+
/// // A custom error enum in your application.
31+
/// pub enum Error {
32+
/// Foo(FooError),
33+
/// Secp256k1(secp256k1::Error),
34+
/// }
35+
/// secp256k1::impl_from_for_all_crate_errors_for!(Error);
36+
///
37+
/// impl From<FooError> for Error {
38+
/// fn from(e: FooError) -> Self { Self::Foo(e) }
39+
/// }
40+
///
41+
/// /// Some useful function.
42+
/// pub fn foo() -> Result<(), FooError> {
43+
/// // Do some stuff.
44+
/// Err(FooError)
45+
/// }
46+
///
47+
/// // Call any secp256k1 function and convert to a single general error variant.
48+
/// fn bar() -> Result<(), Error> {
49+
/// let secp = Secp256k1::new();
50+
/// let key_data = [0_u8; 32]; // Dummy data.
51+
/// let _ = SecretKey::from_slice(&key_data)?;
52+
/// let _ = PublicKey::from_slice(&key_data)?;
53+
/// let _ = foo()?;
54+
/// Ok(())
55+
/// }
56+
/// # }
57+
/// ```
58+
// To find all errors in this crate use (note: -v 'git grep' to remove this comment):
59+
//
60+
// git grep -e 'impl std::error' | grep -v 'git grep' | cut -d ' ' -f 4 | sort
61+
//
62+
#[macro_export]
63+
macro_rules! impl_from_for_all_crate_errors_for {
64+
($error:ty) => {
65+
$crate::impl_from_for_all_crate_errors_for!($error, Secp256k1);
66+
};
67+
($error:ty, $variant:ident) => {
68+
impl From<$crate::Error> for $error {
69+
fn from(e: $crate::Error) -> Self { Self::$variant(e) }
70+
}
71+
72+
#[cfg(feature = "recovery")]
73+
impl From<$crate::ecdsa::InvalidRecoveryIdError> for $error {
74+
fn from(e: $crate::ecdsa::InvalidRecoveryIdError) -> Self { Self::$variant(e.into()) }
75+
}
76+
77+
impl From<$crate::MessageLengthError> for $error {
78+
fn from(e: $crate::MessageLengthError) -> Self { Self::$variant(e.into()) }
79+
}
80+
81+
impl From<$crate::NotEnoughMemoryError> for $error {
82+
fn from(e: $crate::NotEnoughMemoryError) -> Self { Self::$variant(e.into()) }
83+
}
84+
85+
impl From<$crate::scalar::OutOfRangeError> for $error {
86+
fn from(e: $crate::scalar::OutOfRangeError) -> Self { Self::$variant(e.into()) }
87+
}
88+
89+
impl From<$crate::ParityValueError> for $error {
90+
fn from(e: $crate::ParityValueError) -> Self { Self::$variant(e.into()) }
91+
}
92+
93+
impl From<$crate::PublicKeyError> for $error {
94+
fn from(e: $crate::PublicKeyError) -> Self { Self::$variant(e.into()) }
95+
}
96+
97+
impl From<$crate::PublicKeySumError> for $error {
98+
fn from(e: $crate::PublicKeySumError) -> Self { Self::$variant(e.into()) }
99+
}
100+
101+
impl From<$crate::SecretKeyError> for $error {
102+
fn from(e: $crate::SecretKeyError) -> Self { Self::$variant(e.into()) }
103+
}
104+
105+
impl From<$crate::schnorr::SignatureError> for $error {
106+
fn from(e: $crate::schnorr::SignatureError) -> Self { Self::$variant(e.into()) }
107+
}
108+
109+
impl From<$crate::ecdsa::SignatureError> for $error {
110+
fn from(e: $crate::ecdsa::SignatureError) -> Self { Self::$variant(e.into()) }
111+
}
112+
113+
impl From<$crate::ecdsa::SignatureParseError> for $error {
114+
fn from(e: $crate::ecdsa::SignatureParseError) -> Self { Self::$variant(e.into()) }
115+
}
116+
117+
impl From<$crate::SysError> for $error {
118+
fn from(e: $crate::SysError) -> Self { Self::$variant(e.into()) }
119+
}
120+
121+
impl From<$crate::FromHexError> for $error {
122+
fn from(e: $crate::FromHexError) -> Self { Self::$variant(e.into()) }
123+
}
124+
125+
impl From<$crate::ToHexError> for $error {
126+
fn from(e: $crate::ToHexError) -> Self { Self::$variant(e.into()) }
127+
}
128+
129+
impl From<$crate::TweakError> for $error {
130+
fn from(e: $crate::TweakError) -> Self { Self::$variant(e.into()) }
131+
}
132+
133+
impl From<$crate::XOnlyTweakError> for $error {
134+
fn from(e: $crate::XOnlyTweakError) -> Self { Self::$variant(e.into()) }
135+
}
136+
137+
impl From<$crate::ellswift::ParseError> for $error {
138+
fn from(e: $crate::ellswift::ParseError) -> Self { Self::$variant(e.into()) }
139+
}
140+
};
141+
}
142+
143+
/// This is a general purpose error type that can be used to wrap all the errors in this crate.
144+
///
145+
/// Every error types in this crate can be converted (using `?`) to this type. We also support
146+
/// converting from any of the inner error types to this type, irrespective of the level of nesting.
147+
#[derive(Debug, Clone, PartialEq, Eq)]
148+
#[allow(missing_copy_implementations)] // For forward compatibility (combined with non_exhaustive).
149+
#[non_exhaustive]
150+
pub enum Error {
151+
/// Error decoding from hex string.
152+
FromHex(FromHexError),
153+
/// Invalid recovery ID (ECDSA).
154+
#[cfg(feature = "recovery")]
155+
RecoveryId(ecdsa::InvalidRecoveryIdError),
156+
/// Messages must be 32 bytes long.
157+
MessageLength(MessageLengthError),
158+
/// Not enough preallocated memory for the requested buffer size.
159+
NotEnoughMemory(NotEnoughMemoryError),
160+
/// Value of scalar is invalid - larger than the curve order.
161+
InvalidScalar(scalar::OutOfRangeError),
162+
/// Invalid value for parity - must be 0 or 1.
163+
ParityValue(ParityValueError),
164+
/// Public key is invalid.
165+
PublicKey(PublicKeyError),
166+
/// Public key summation is invalid.
167+
PublicKeySum(PublicKeySumError),
168+
/// Secret key is invalid.
169+
SecretKey(SecretKeyError),
170+
/// Schnorr signature is invalid.
171+
SchnorrSignature(schnorr::SignatureError),
172+
/// ECDSA signature is invalid.
173+
EcdsaSignature(ecdsa::SignatureError),
174+
/// ECDSA signature string invalid.
175+
EcdsaSignatureParse(ecdsa::SignatureParseError),
176+
/// Error calling into the FFI layer.
177+
Sys(SysError),
178+
/// Error encoding as hex string.
179+
ToHex(ToHexError),
180+
/// Invalid key tweak.
181+
Tweak(TweakError),
182+
/// X-only pubic key tweak failed.
183+
XOnlyTweak(XOnlyTweakError),
184+
/// Error converting hex string to ellswift.
185+
Ellswift(ellswift::ParseError),
186+
/// Invalid slice length.
187+
InvalidSliceLength(InvalidSliceLengthError),
188+
}
189+
190+
impl fmt::Display for Error {
191+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
192+
use Error::*;
193+
194+
// TODO: Check what gets out put in std and no-std builds an verify it is
195+
// useful and does not contain redundant content.
196+
match *self {
197+
FromHex(ref e) => write_err!(f, "from hex"; e),
198+
#[cfg(feature = "recovery")]
199+
RecoveryId(ref e) => write_err!(f, "invalid recovery ID (ECDSA)"; e),
200+
MessageLength(ref e) => write_err!(f, "invalid message length"; e),
201+
NotEnoughMemory(ref e) => write_err!(f, "not enough memory"; e),
202+
InvalidScalar(ref e) => write_err!(f, ""; e),
203+
ParityValue(ref e) => write_err!(f, "invalid parity"; e),
204+
PublicKey(ref e) => write_err!(f, "invalid public key"; e),
205+
PublicKeySum(ref e) => write_err!(f, "invalid public key sum"; e),
206+
SecretKey(ref e) => write_err!(f, "invalid secret key"; e),
207+
SchnorrSignature(ref e) => write_err!(f, "invalid schnorr sig"; e),
208+
EcdsaSignature(ref e) => write_err!(f, "invalid ECDSA sig"; e),
209+
EcdsaSignatureParse(ref e) => write_err!(f, "invalid ECDSA sig string"; e),
210+
Sys(ref e) => write_err!(f, "sys"; e),
211+
ToHex(ref e) => write_err!(f, "to hex"; e),
212+
Tweak(ref e) => write_err!(f, "invalid tweak"; e),
213+
XOnlyTweak(ref e) => write_err!(f, "x-only tweak error"; e),
214+
Ellswift(ref e) => write_err!(f, "ellswift error"; e),
215+
InvalidSliceLength(ref e) => write_err!(f, "invalid slice"; e),
216+
}
217+
}
218+
}
219+
220+
#[cfg(feature = "std")]
221+
impl std::error::Error for Error {
222+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
223+
use Error::*;
224+
225+
match *self {
226+
FromHex(ref e) => Some(e),
227+
#[cfg(feature = "recovery")]
228+
RecoveryId(ref e) => Some(e),
229+
MessageLength(ref e) => Some(e),
230+
NotEnoughMemory(ref e) => Some(e),
231+
InvalidScalar(ref e) => Some(e),
232+
ParityValue(ref e) => Some(e),
233+
PublicKey(ref e) => Some(e),
234+
PublicKeySum(ref e) => Some(e),
235+
SecretKey(ref e) => Some(e),
236+
SchnorrSignature(ref e) => Some(e),
237+
EcdsaSignature(ref e) => Some(e),
238+
EcdsaSignatureParse(ref e) => Some(e),
239+
Sys(ref e) => Some(e),
240+
ToHex(ref e) => Some(e),
241+
Tweak(ref e) => Some(e),
242+
XOnlyTweak(ref e) => Some(e),
243+
Ellswift(ref e) => Some(e),
244+
InvalidSliceLength(ref e) => Some(e),
245+
}
246+
}
247+
}
248+
249+
impl From<FromHexError> for Error {
250+
fn from(e: FromHexError) -> Self { Self::FromHex(e) }
251+
}
252+
253+
#[cfg(feature = "recovery")]
254+
impl From<ecdsa::InvalidRecoveryIdError> for Error {
255+
fn from(e: ecdsa::InvalidRecoveryIdError) -> Self { Self::RecoveryId(e) }
256+
}
257+
258+
impl From<MessageLengthError> for Error {
259+
fn from(e: MessageLengthError) -> Self { Self::MessageLength(e) }
260+
}
261+
262+
impl From<NotEnoughMemoryError> for Error {
263+
fn from(e: NotEnoughMemoryError) -> Self { Self::NotEnoughMemory(e) }
264+
}
265+
266+
impl From<scalar::OutOfRangeError> for Error {
267+
fn from(e: scalar::OutOfRangeError) -> Self { Self::InvalidScalar(e) }
268+
}
269+
270+
impl From<ParityValueError> for Error {
271+
fn from(e: ParityValueError) -> Self { Self::ParityValue(e) }
272+
}
273+
274+
impl From<PublicKeyError> for Error {
275+
fn from(e: PublicKeyError) -> Self { Self::PublicKey(e) }
276+
}
277+
278+
impl From<PublicKeySumError> for Error {
279+
fn from(e: PublicKeySumError) -> Self { Self::PublicKeySum(e) }
280+
}
281+
282+
impl From<SecretKeyError> for Error {
283+
fn from(e: SecretKeyError) -> Self { Self::SecretKey(e) }
284+
}
285+
286+
impl From<schnorr::SignatureError> for Error {
287+
fn from(e: schnorr::SignatureError) -> Self { Self::SchnorrSignature(e) }
288+
}
289+
290+
impl From<ecdsa::SignatureError> for Error {
291+
fn from(e: ecdsa::SignatureError) -> Self { Self::EcdsaSignature(e) }
292+
}
293+
294+
impl From<ecdsa::SignatureParseError> for Error {
295+
fn from(e: ecdsa::SignatureParseError) -> Self { Self::EcdsaSignatureParse(e) }
296+
}
297+
298+
impl From<SysError> for Error {
299+
fn from(e: SysError) -> Self { Self::Sys(e) }
300+
}
301+
302+
impl From<ToHexError> for Error {
303+
fn from(e: ToHexError) -> Self { Self::ToHex(e) }
304+
}
305+
306+
impl From<TweakError> for Error {
307+
fn from(e: TweakError) -> Self { Self::Tweak(e) }
308+
}
309+
310+
impl From<XOnlyTweakError> for Error {
311+
fn from(e: XOnlyTweakError) -> Self { Self::XOnlyTweak(e) }
312+
}
313+
314+
impl From<ellswift::ParseError> for Error {
315+
fn from(e: ellswift::ParseError) -> Self { Self::Ellswift(e) }
316+
}
317+
318+
impl From<ecdh::InvalidSliceLengthError> for Error {
319+
fn from(e: ecdh::InvalidSliceLengthError) -> Self { Self::InvalidSliceLength(e) }
320+
}
321+
322+
/// Error parsing a slice.
323+
#[derive(Debug, Clone, PartialEq, Eq)]
324+
#[non_exhaustive]
325+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
326+
pub struct InvalidSliceLengthError {
327+
pub(crate) got: usize,
328+
pub(crate) expected: usize,
329+
}
330+
331+
impl core::fmt::Display for InvalidSliceLengthError {
332+
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
333+
write!(f, "invalid slice length {}, expected {}", self.got, self.expected)
334+
}
335+
}
336+
337+
#[cfg(feature = "std")]
338+
impl std::error::Error for InvalidSliceLengthError {
339+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
340+
}
341+
342+
/// Error calling into the FFI layer.
343+
// TODO: Do we want to include the error code returned for C function calls?
344+
#[derive(Debug, Clone, PartialEq, Eq)]
345+
#[non_exhaustive]
346+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
347+
pub struct SysError {}
348+
349+
impl core::fmt::Display for SysError {
350+
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
351+
f.write_str("FFI call failed")
352+
}
353+
}
354+
355+
#[cfg(feature = "std")]
356+
impl std::error::Error for SysError {
357+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
358+
}
359+
360+
/// Formats error. If `std` feature is OFF appends error source (delimited by `: `). We do this
361+
/// because `e.source()` is only available in std builds, without this macro the error source is
362+
/// lost for no-std builds.
363+
macro_rules! write_err {
364+
($writer:expr, $string:literal $(, $args:expr),*; $source:expr) => {
365+
{
366+
#[cfg(feature = "std")]
367+
{
368+
let _ = &$source; // Prevents clippy warnings.
369+
write!($writer, $string $(, $args)*)
370+
}
371+
#[cfg(not(feature = "std"))]
372+
{
373+
write!($writer, concat!($string, ": {}") $(, $args)*, $source)
374+
}
375+
}
376+
}
377+
}
378+
pub(crate) use write_err;

‎src/hex.rs

+143-6
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,21 @@
44
55
use core::str;
66

7+
use crate::error::write_err;
8+
79
/// Utility function used to parse hex into a target u8 buffer. Returns
810
/// the number of bytes converted or an error if it encounters an invalid
911
/// character or unexpected end of string.
10-
pub(crate) fn from_hex(hex: &str, target: &mut [u8]) -> Result<usize, ()> {
11-
if hex.len() % 2 == 1 || hex.len() > target.len() * 2 {
12-
return Err(());
12+
pub(crate) fn from_hex(hex: &str, target: &mut [u8]) -> Result<usize, FromHexError> {
13+
if hex.len() % 2 == 1 {
14+
return Err(FromHexError::UnevenLength(UnevenLengthError { len: hex.len() }));
15+
}
16+
17+
if hex.len() > target.len() * 2 {
18+
return Err(FromHexError::BufferTooSmall(BufferTooSmallError {
19+
hex: hex.len(),
20+
buffer: target.len(),
21+
}));
1322
}
1423

1524
let mut b = 0;
@@ -20,7 +29,7 @@ pub(crate) fn from_hex(hex: &str, target: &mut [u8]) -> Result<usize, ()> {
2029
b'A'..=b'F' => b |= c - b'A' + 10,
2130
b'a'..=b'f' => b |= c - b'a' + 10,
2231
b'0'..=b'9' => b |= c - b'0',
23-
_ => return Err(()),
32+
byte => return Err(FromHexError::InvalidByte(InvalidByteError { invalid: byte })),
2433
}
2534
if (idx & 1) == 1 {
2635
target[idx / 2] = b;
@@ -35,10 +44,10 @@ pub(crate) fn from_hex(hex: &str, target: &mut [u8]) -> Result<usize, ()> {
3544
/// a reference to the target buffer as an str. Returns an error if the target
3645
/// buffer isn't big enough.
3746
#[inline]
38-
pub(crate) fn to_hex<'a>(src: &[u8], target: &'a mut [u8]) -> Result<&'a str, ()> {
47+
pub(crate) fn to_hex<'a>(src: &[u8], target: &'a mut [u8]) -> Result<&'a str, ToHexError> {
3948
let hex_len = src.len() * 2;
4049
if target.len() < hex_len {
41-
return Err(());
50+
return Err(ToHexError { hex: hex_len, buffer: target.len() });
4251
}
4352
const HEX_TABLE: [u8; 16] = *b"0123456789abcdef";
4453

@@ -52,3 +61,131 @@ pub(crate) fn to_hex<'a>(src: &[u8], target: &'a mut [u8]) -> Result<&'a str, ()
5261
debug_assert!(str::from_utf8(result).is_ok());
5362
return unsafe { Ok(str::from_utf8_unchecked(result)) };
5463
}
64+
65+
/// Error converting from a hex string.
66+
#[derive(Debug, Clone, PartialEq, Eq)]
67+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
68+
#[non_exhaustive]
69+
pub enum FromHexError {
70+
/// Hex string length uneven.
71+
UnevenLength(UnevenLengthError),
72+
/// Target data buffer too small to decode hex.
73+
BufferTooSmall(BufferTooSmallError),
74+
/// Byte is not valid hex ASCII.
75+
InvalidByte(InvalidByteError),
76+
}
77+
78+
impl core::fmt::Display for FromHexError {
79+
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
80+
use FromHexError::*;
81+
82+
match *self {
83+
UnevenLength(ref e) => write_err!(f, "uneven length, converting from hex"; e),
84+
BufferTooSmall(ref e) => write_err!(f, "buffer too small, converting from hex"; e),
85+
InvalidByte(ref e) => write_err!(f, "invalid byte, convening from hex"; e),
86+
}
87+
}
88+
}
89+
90+
#[cfg(feature = "std")]
91+
impl std::error::Error for FromHexError {
92+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
93+
use FromHexError::*;
94+
95+
match *self {
96+
UnevenLength(ref e) => Some(e),
97+
BufferTooSmall(ref e) => Some(e),
98+
InvalidByte(ref e) => Some(e),
99+
}
100+
}
101+
}
102+
103+
/// Hex string length uneven.
104+
#[derive(Debug, Clone, PartialEq, Eq)]
105+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
106+
#[non_exhaustive]
107+
pub struct UnevenLengthError {
108+
len: usize,
109+
}
110+
111+
impl core::fmt::Display for UnevenLengthError {
112+
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
113+
write!(f, "hex string uneven: {}", self.len)
114+
}
115+
}
116+
117+
#[cfg(feature = "std")]
118+
impl std::error::Error for UnevenLengthError {
119+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
120+
}
121+
122+
/// Target data buffer too small to decode hex.
123+
#[derive(Debug, Clone, PartialEq, Eq)]
124+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
125+
#[non_exhaustive]
126+
pub struct BufferTooSmallError {
127+
/// Length of the hex string.
128+
hex: usize,
129+
/// Size of the target data buffer.
130+
buffer: usize,
131+
}
132+
133+
impl core::fmt::Display for BufferTooSmallError {
134+
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
135+
write!(
136+
f,
137+
"buffer too small to decode hex (hex length: {}, buffer size: {})",
138+
self.hex, self.buffer
139+
)
140+
}
141+
}
142+
143+
#[cfg(feature = "std")]
144+
impl std::error::Error for BufferTooSmallError {
145+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
146+
}
147+
148+
/// Byte is not valid hex ASCII.
149+
#[derive(Debug, Clone, PartialEq, Eq)]
150+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
151+
#[non_exhaustive]
152+
pub struct InvalidByteError {
153+
invalid: u8,
154+
}
155+
156+
impl core::fmt::Display for InvalidByteError {
157+
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
158+
write!(f, "byte is not valid hex ASCII: {:x}", self.invalid)
159+
}
160+
}
161+
162+
#[cfg(feature = "std")]
163+
impl std::error::Error for InvalidByteError {
164+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
165+
}
166+
167+
/// Buffer too small to encode hex data.
168+
#[derive(Debug, Clone, PartialEq, Eq)]
169+
#[non_exhaustive]
170+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
171+
pub struct ToHexError {
172+
/// Required length of the encoded hex string.
173+
hex: usize,
174+
/// Size of the buffer (must be equal or larger that hex length).
175+
buffer: usize,
176+
}
177+
178+
impl core::fmt::Display for ToHexError {
179+
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
180+
write!(
181+
f,
182+
"buffer too small to encode hex (required: {}, buffer: {})",
183+
self.hex, self.buffer
184+
)
185+
}
186+
}
187+
188+
#[cfg(feature = "std")]
189+
impl std::error::Error for ToHexError {
190+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
191+
}

‎src/key/error.rs

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
//! Error types for the `key` module.
4+
5+
use core::fmt;
6+
7+
use crate::error::write_err;
8+
9+
/// X-only public key tweak is invalid.
10+
#[derive(Debug, Clone, PartialEq, Eq)]
11+
#[non_exhaustive]
12+
pub enum XOnlyTweakError {
13+
/// Invalid tweak.
14+
Tweak(TweakError),
15+
/// Invalid public key.
16+
PublicKey(PublicKeyError),
17+
/// Invalid parity value.
18+
ParityValue(ParityValueError),
19+
}
20+
21+
impl fmt::Display for XOnlyTweakError {
22+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23+
use XOnlyTweakError::*;
24+
25+
// TODO: Check what gets out put in std and no-std builds an verify it useful and does not
26+
// contain redundant content.
27+
match *self {
28+
Tweak(ref e) => write_err!(f, "invalid tweak"; e),
29+
PublicKey(ref e) => write_err!(f, "invalid public key"; e),
30+
ParityValue(ref e) => write_err!(f, "invalid parity value"; e),
31+
}
32+
}
33+
}
34+
35+
#[cfg(feature = "std")]
36+
impl std::error::Error for XOnlyTweakError {
37+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
38+
use XOnlyTweakError::*;
39+
40+
match *self {
41+
Tweak(ref e) => Some(e),
42+
PublicKey(ref e) => Some(e),
43+
ParityValue(ref e) => Some(e),
44+
}
45+
}
46+
}
47+
48+
impl From<TweakError> for XOnlyTweakError {
49+
fn from(e: TweakError) -> Self { Self::Tweak(e) }
50+
}
51+
52+
impl From<PublicKeyError> for XOnlyTweakError {
53+
fn from(e: PublicKeyError) -> Self { Self::PublicKey(e) }
54+
}
55+
56+
impl From<ParityValueError> for XOnlyTweakError {
57+
fn from(e: ParityValueError) -> Self { Self::ParityValue(e) }
58+
}
59+
60+
/// Secret key is invalid.
61+
#[derive(Debug, Clone, PartialEq, Eq)]
62+
#[non_exhaustive]
63+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
64+
pub struct SecretKeyError;
65+
66+
impl core::fmt::Display for SecretKeyError {
67+
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
68+
f.write_str("secret key is invalid")
69+
}
70+
}
71+
72+
#[cfg(feature = "std")]
73+
impl std::error::Error for SecretKeyError {
74+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
75+
}
76+
77+
/// Public key is invalid.
78+
#[derive(Debug, Clone, PartialEq, Eq)]
79+
#[non_exhaustive]
80+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
81+
pub struct PublicKeyError;
82+
83+
impl core::fmt::Display for PublicKeyError {
84+
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
85+
f.write_str("public key is invalid")
86+
}
87+
}
88+
89+
#[cfg(feature = "std")]
90+
impl std::error::Error for PublicKeyError {
91+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
92+
}
93+
94+
/// Public key summation is invalid.
95+
#[derive(Debug, Clone, PartialEq, Eq)]
96+
#[non_exhaustive]
97+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
98+
pub struct PublicKeySumError;
99+
100+
impl core::fmt::Display for PublicKeySumError {
101+
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
102+
f.write_str("public key summation is invalid")
103+
}
104+
}
105+
106+
#[cfg(feature = "std")]
107+
impl std::error::Error for PublicKeySumError {
108+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
109+
}
110+
111+
/// Invalid key tweak.
112+
#[derive(Debug, Clone, PartialEq, Eq)]
113+
#[non_exhaustive]
114+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
115+
pub struct TweakError;
116+
117+
impl core::fmt::Display for TweakError {
118+
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
119+
f.write_str("invalid key tweak")
120+
}
121+
}
122+
123+
#[cfg(feature = "std")]
124+
impl std::error::Error for TweakError {
125+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
126+
}
127+
128+
/// Invalid value for parity - must be 0 or 1.
129+
#[derive(Debug, Clone, PartialEq, Eq)]
130+
#[non_exhaustive]
131+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
132+
pub struct ParityValueError(pub i32);
133+
134+
impl fmt::Display for ParityValueError {
135+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
136+
write!(f, "invalid value {} for parity - must be 0 or 1", self.0)
137+
}
138+
}
139+
140+
#[cfg(feature = "std")]
141+
impl std::error::Error for ParityValueError {
142+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
143+
}

‎src/key.rs ‎src/key/mod.rs

+82-102
Large diffs are not rendered by default.

‎src/lib.rs

+42-109
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ pub mod constants;
166166
pub mod ecdh;
167167
pub mod ecdsa;
168168
pub mod ellswift;
169+
pub mod error;
169170
pub mod scalar;
170171
pub mod schnorr;
171172
#[cfg(feature = "serde")]
@@ -175,22 +176,33 @@ use core::marker::PhantomData;
175176
use core::ptr::NonNull;
176177
use core::{fmt, mem};
177178

178-
#[cfg(feature = "global-context")]
179-
pub use context::global::SECP256K1;
180179
#[cfg(feature = "hashes")]
181180
use hashes::Hash;
181+
182+
use crate::ffi::types::AlignedType;
183+
use crate::ffi::CPtr;
184+
185+
#[rustfmt::skip] // Keep public re-exports separate.
186+
pub use crate::{
187+
context::*, // Includes NotEnoughMemoryError
188+
hex::{FromHexError, ToHexError},
189+
key::{PublicKey, SecretKey, *},
190+
scalar::Scalar,
191+
key::error::{
192+
ParityValueError, PublicKeyError, PublicKeySumError, SecretKeyError, TweakError,
193+
XOnlyTweakError,
194+
},
195+
error::{Error, SysError, InvalidSliceLengthError},
196+
};
197+
198+
#[cfg(feature = "global-context")]
199+
pub use context::global::SECP256K1;
182200
#[cfg(feature = "rand")]
183201
pub use rand;
184202
pub use secp256k1_sys as ffi;
185203
#[cfg(feature = "serde")]
186204
pub use serde;
187205

188-
pub use crate::context::*;
189-
use crate::ffi::types::AlignedType;
190-
use crate::ffi::CPtr;
191-
pub use crate::key::{PublicKey, SecretKey, *};
192-
pub use crate::scalar::Scalar;
193-
194206
/// Trait describing something that promises to be a 32-byte random number; in particular,
195207
/// it has negligible probability of being zero or overflowing the group order. Such objects
196208
/// may be converted to `Message`s without any error paths.
@@ -229,7 +241,7 @@ impl Message {
229241
/// [secure signature](https://twitter.com/pwuille/status/1063582706288586752).
230242
#[inline]
231243
#[deprecated(since = "0.28.0", note = "use from_digest_slice instead")]
232-
pub fn from_slice(digest: &[u8]) -> Result<Message, Error> {
244+
pub fn from_slice(digest: &[u8]) -> Result<Message, MessageLengthError> {
233245
Message::from_digest_slice(digest)
234246
}
235247

@@ -258,14 +270,14 @@ impl Message {
258270
///
259271
/// [secure signature]: https://twitter.com/pwuille/status/1063582706288586752
260272
#[inline]
261-
pub fn from_digest_slice(digest: &[u8]) -> Result<Message, Error> {
273+
pub fn from_digest_slice(digest: &[u8]) -> Result<Message, MessageLengthError> {
262274
match digest.len() {
263275
constants::MESSAGE_SIZE => {
264276
let mut ret = [0u8; constants::MESSAGE_SIZE];
265277
ret[..].copy_from_slice(digest);
266278
Ok(Message(ret))
267279
}
268-
_ => Err(Error::InvalidMessage),
280+
len => Err(MessageLengthError(len)),
269281
}
270282
}
271283

@@ -311,76 +323,21 @@ impl fmt::Display for Message {
311323
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
312324
}
313325

314-
/// The main error type for this library.
315-
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug)]
316-
pub enum Error {
317-
/// Signature failed verification.
318-
IncorrectSignature,
319-
/// Bad sized message ("messages" are actually fixed-sized digests [`constants::MESSAGE_SIZE`]).
320-
InvalidMessage,
321-
/// Bad public key.
322-
InvalidPublicKey,
323-
/// Bad signature.
324-
InvalidSignature,
325-
/// Bad secret key.
326-
InvalidSecretKey,
327-
/// Bad shared secret.
328-
InvalidSharedSecret,
329-
/// Bad recovery id.
330-
InvalidRecoveryId,
331-
/// Tried to add/multiply by an invalid tweak.
332-
InvalidTweak,
333-
/// Didn't pass enough memory to context creation with preallocated memory.
334-
NotEnoughMemory,
335-
/// Bad set of public keys.
336-
InvalidPublicKeySum,
337-
/// The only valid parity values are 0 or 1.
338-
InvalidParityValue(key::InvalidParityValue),
339-
/// Bad EllSwift value
340-
InvalidEllSwift,
341-
}
326+
/// Messages must be 32 bytes long.
327+
#[derive(Debug, Clone, PartialEq, Eq)]
328+
#[non_exhaustive]
329+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
330+
pub struct MessageLengthError(pub usize);
342331

343-
impl fmt::Display for Error {
332+
impl fmt::Display for MessageLengthError {
344333
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
345-
use Error::*;
346-
347-
match *self {
348-
IncorrectSignature => f.write_str("signature failed verification"),
349-
InvalidMessage => f.write_str("message was not 32 bytes (do you need to hash?)"),
350-
InvalidPublicKey => f.write_str("malformed public key"),
351-
InvalidSignature => f.write_str("malformed signature"),
352-
InvalidSecretKey => f.write_str("malformed or out-of-range secret key"),
353-
InvalidSharedSecret => f.write_str("malformed or out-of-range shared secret"),
354-
InvalidRecoveryId => f.write_str("bad recovery id"),
355-
InvalidTweak => f.write_str("bad tweak"),
356-
NotEnoughMemory => f.write_str("not enough memory allocated"),
357-
InvalidPublicKeySum => f.write_str(
358-
"the sum of public keys was invalid or the input vector lengths was less than 1",
359-
),
360-
InvalidParityValue(e) => write_err!(f, "couldn't create parity"; e),
361-
InvalidEllSwift => f.write_str("malformed EllSwift value"),
362-
}
334+
write!(f, "messages must be 32 bytes long, got: {}", self.0)
363335
}
364336
}
365337

366338
#[cfg(feature = "std")]
367-
impl std::error::Error for Error {
368-
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
369-
match self {
370-
Error::IncorrectSignature => None,
371-
Error::InvalidMessage => None,
372-
Error::InvalidPublicKey => None,
373-
Error::InvalidSignature => None,
374-
Error::InvalidSecretKey => None,
375-
Error::InvalidSharedSecret => None,
376-
Error::InvalidRecoveryId => None,
377-
Error::InvalidTweak => None,
378-
Error::NotEnoughMemory => None,
379-
Error::InvalidPublicKeySum => None,
380-
Error::InvalidParityValue(error) => Some(error),
381-
Error::InvalidEllSwift => None,
382-
}
383-
}
339+
impl std::error::Error for MessageLengthError {
340+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
384341
}
385342

386343
/// The secp256k1 engine, used to execute all signature operations.
@@ -499,6 +456,10 @@ mod tests {
499456
use wasm_bindgen_test::wasm_bindgen_test as test;
500457

501458
use super::*;
459+
use crate::error::SysError;
460+
use crate::{constants, ecdsa, hex, Message};
461+
#[cfg(feature = "alloc")]
462+
use crate::{ffi, PublicKey, Secp256k1, SecretKey};
502463

503464
macro_rules! hex {
504465
($hex:expr) => {{
@@ -814,60 +775,32 @@ mod tests {
814775

815776
let msg = crate::random_32_bytes(&mut rand::thread_rng());
816777
let msg = Message::from_digest_slice(&msg).unwrap();
817-
assert_eq!(s.verify_ecdsa(&msg, &sig, &pk), Err(Error::IncorrectSignature));
778+
assert_eq!(s.verify_ecdsa(&msg, &sig, &pk), Err(SysError {}));
818779
}
819780

820781
#[test]
821782
fn test_bad_slice() {
822783
assert_eq!(
823784
ecdsa::Signature::from_der(&[0; constants::MAX_SIGNATURE_SIZE + 1]),
824-
Err(Error::InvalidSignature)
785+
Err(ecdsa::SignatureError::Sys(SysError {}))
825786
);
826787
assert_eq!(
827788
ecdsa::Signature::from_der(&[0; constants::MAX_SIGNATURE_SIZE]),
828-
Err(Error::InvalidSignature)
789+
Err(ecdsa::SignatureError::Sys(SysError {}))
829790
);
830791

831792
assert_eq!(
832793
Message::from_digest_slice(&[0; constants::MESSAGE_SIZE - 1]),
833-
Err(Error::InvalidMessage)
794+
Err(MessageLengthError(31))
834795
);
835796
assert_eq!(
836797
Message::from_digest_slice(&[0; constants::MESSAGE_SIZE + 1]),
837-
Err(Error::InvalidMessage)
798+
Err(MessageLengthError(33))
838799
);
839800
assert!(Message::from_digest_slice(&[0; constants::MESSAGE_SIZE]).is_ok());
840801
assert!(Message::from_digest_slice(&[1; constants::MESSAGE_SIZE]).is_ok());
841802
}
842803

843-
#[test]
844-
#[cfg(feature = "rand-std")]
845-
fn test_hex() {
846-
use rand::RngCore;
847-
848-
let mut rng = rand::thread_rng();
849-
const AMOUNT: usize = 1024;
850-
for i in 0..AMOUNT {
851-
// 255 isn't a valid utf8 character.
852-
let mut hex_buf = [255u8; AMOUNT * 2];
853-
let mut src_buf = [0u8; AMOUNT];
854-
let mut result_buf = [0u8; AMOUNT];
855-
let src = &mut src_buf[0..i];
856-
rng.fill_bytes(src);
857-
858-
let hex = hex::to_hex(src, &mut hex_buf).unwrap();
859-
assert_eq!(hex::from_hex(hex, &mut result_buf).unwrap(), i);
860-
assert_eq!(src, &result_buf[..i]);
861-
}
862-
863-
assert!(hex::to_hex(&[1; 2], &mut [0u8; 3]).is_err());
864-
assert!(hex::to_hex(&[1; 2], &mut [0u8; 4]).is_ok());
865-
assert!(hex::from_hex("deadbeaf", &mut [0u8; 3]).is_err());
866-
assert!(hex::from_hex("deadbeaf", &mut [0u8; 4]).is_ok());
867-
assert!(hex::from_hex("a", &mut [0u8; 4]).is_err());
868-
assert!(hex::from_hex("ag", &mut [0u8; 4]).is_err());
869-
}
870-
871804
#[test]
872805
#[cfg(not(secp256k1_fuzz))] // fuzz-sigs have fixed size/format
873806
#[cfg(any(feature = "alloc", feature = "std"))]
@@ -904,7 +837,7 @@ mod tests {
904837
let msg = Message::from_digest_slice(&msg[..]).unwrap();
905838

906839
// without normalization we expect this will fail
907-
assert_eq!(secp.verify_ecdsa(&msg, &sig, &pk), Err(Error::IncorrectSignature));
840+
assert_eq!(secp.verify_ecdsa(&msg, &sig, &pk), Err(SysError {}));
908841
// after normalization it should pass
909842
sig.normalize_s();
910843
assert_eq!(secp.verify_ecdsa(&msg, &sig, &pk), Ok(()));

‎src/macros.rs

-19
Original file line numberDiff line numberDiff line change
@@ -70,25 +70,6 @@ macro_rules! impl_non_secure_erase {
7070
};
7171
}
7272

73-
/// Formats error. If `std` feature is OFF appends error source (delimited by `: `). We do this
74-
/// because `e.source()` is only available in std builds, without this macro the error source is
75-
/// lost for no-std builds.
76-
macro_rules! write_err {
77-
($writer:expr, $string:literal $(, $args:expr),*; $source:expr) => {
78-
{
79-
#[cfg(feature = "std")]
80-
{
81-
let _ = &$source; // Prevents clippy warnings.
82-
write!($writer, $string $(, $args)*)
83-
}
84-
#[cfg(not(feature = "std"))]
85-
{
86-
write!($writer, concat!($string, ": {}") $(, $args)*, $source)
87-
}
88-
}
89-
}
90-
}
91-
9273
/// Implements fast unstable comparison methods for `$ty`.
9374
macro_rules! impl_fast_comparisons {
9475
($ty:ident) => {

‎src/scalar.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,10 @@ impl From<crate::SecretKey> for Scalar {
123123
}
124124

125125
/// Error returned when the value of scalar is invalid - larger than the curve order.
126-
// Intentionally doesn't implement `Copy` to improve forward compatibility.
127-
// Same reason for `non_exhaustive`.
128-
#[allow(missing_copy_implementations)]
129-
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
126+
#[derive(Debug, Clone, PartialEq, Eq)]
130127
#[non_exhaustive]
131-
pub struct OutOfRangeError {}
128+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
129+
pub struct OutOfRangeError;
132130

133131
impl fmt::Display for OutOfRangeError {
134132
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -137,4 +135,6 @@ impl fmt::Display for OutOfRangeError {
137135
}
138136

139137
#[cfg(feature = "std")]
140-
impl std::error::Error for OutOfRangeError {}
138+
impl std::error::Error for OutOfRangeError {
139+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
140+
}

‎src/schnorr.rs

+31-16
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::ffi::{self, CPtr};
1212
use crate::key::{Keypair, XOnlyPublicKey};
1313
#[cfg(feature = "global-context")]
1414
use crate::SECP256K1;
15-
use crate::{constants, hex, impl_array_newtype, Error, Message, Secp256k1, Signing, Verification};
15+
use crate::{constants, hex, impl_array_newtype, Message, Secp256k1, Signing, Verification};
1616

1717
/// Represents a schnorr signature.
1818
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -61,28 +61,28 @@ impl fmt::Display for Signature {
6161
}
6262

6363
impl str::FromStr for Signature {
64-
type Err = Error;
64+
type Err = SignatureError;
6565
fn from_str(s: &str) -> Result<Self, Self::Err> {
6666
let mut res = [0u8; constants::SCHNORR_SIGNATURE_SIZE];
6767
match hex::from_hex(s, &mut res) {
6868
Ok(constants::SCHNORR_SIGNATURE_SIZE) =>
6969
Signature::from_slice(&res[0..constants::SCHNORR_SIGNATURE_SIZE]),
70-
_ => Err(Error::InvalidSignature),
70+
_ => Err(SignatureError),
7171
}
7272
}
7373
}
7474

7575
impl Signature {
7676
/// Creates a `Signature` directly from a slice.
7777
#[inline]
78-
pub fn from_slice(data: &[u8]) -> Result<Signature, Error> {
78+
pub fn from_slice(data: &[u8]) -> Result<Signature, SignatureError> {
7979
match data.len() {
8080
constants::SCHNORR_SIGNATURE_SIZE => {
8181
let mut ret = [0u8; constants::SCHNORR_SIGNATURE_SIZE];
8282
ret[..].copy_from_slice(data);
8383
Ok(Signature(ret))
8484
}
85-
_ => Err(Error::InvalidSignature),
85+
_ => Err(SignatureError),
8686
}
8787
}
8888

@@ -93,7 +93,7 @@ impl Signature {
9393
/// Verifies a schnorr signature for `msg` using `pk` and the global [`SECP256K1`] context.
9494
#[inline]
9595
#[cfg(feature = "global-context")]
96-
pub fn verify(&self, msg: &Message, pk: &XOnlyPublicKey) -> Result<(), Error> {
96+
pub fn verify(&self, msg: &Message, pk: &XOnlyPublicKey) -> Result<(), SignatureError> {
9797
SECP256K1.verify_schnorr(self, msg, pk)
9898
}
9999
}
@@ -166,7 +166,7 @@ impl<C: Verification> Secp256k1<C> {
166166
sig: &Signature,
167167
msg: &Message,
168168
pubkey: &XOnlyPublicKey,
169-
) -> Result<(), Error> {
169+
) -> Result<(), SignatureError> {
170170
unsafe {
171171
let ret = ffi::secp256k1_schnorrsig_verify(
172172
self.ctx.as_ptr(),
@@ -179,12 +179,27 @@ impl<C: Verification> Secp256k1<C> {
179179
if ret == 1 {
180180
Ok(())
181181
} else {
182-
Err(Error::InvalidSignature)
182+
Err(SignatureError)
183183
}
184184
}
185185
}
186186
}
187187

188+
/// Signature is invalid.
189+
#[derive(Debug, Clone, PartialEq, Eq)]
190+
#[non_exhaustive]
191+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
192+
pub struct SignatureError;
193+
194+
impl fmt::Display for SignatureError {
195+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("signature is invalid") }
196+
}
197+
198+
#[cfg(feature = "std")]
199+
impl std::error::Error for SignatureError {
200+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
201+
}
202+
188203
#[cfg(test)]
189204
#[allow(unused_imports)]
190205
mod tests {
@@ -196,8 +211,8 @@ mod tests {
196211
use wasm_bindgen_test::wasm_bindgen_test as test;
197212

198213
use super::*;
214+
use crate::key::error::PublicKeyError;
199215
use crate::schnorr::{Keypair, Signature, XOnlyPublicKey};
200-
use crate::Error::InvalidPublicKey;
201216
use crate::{constants, hex, Message, Secp256k1, SecretKey};
202217

203218
#[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
@@ -308,8 +323,8 @@ mod tests {
308323

309324
#[test]
310325
fn test_pubkey_from_slice() {
311-
assert_eq!(XOnlyPublicKey::from_slice(&[]), Err(InvalidPublicKey));
312-
assert_eq!(XOnlyPublicKey::from_slice(&[1, 2, 3]), Err(InvalidPublicKey));
326+
assert_eq!(XOnlyPublicKey::from_slice(&[]), Err(PublicKeyError));
327+
assert_eq!(XOnlyPublicKey::from_slice(&[1, 2, 3]), Err(PublicKeyError));
313328
let pk = XOnlyPublicKey::from_slice(&[
314329
0xB3, 0x3C, 0xC9, 0xED, 0xC0, 0x96, 0xD0, 0xA8, 0x34, 0x16, 0x96, 0x4B, 0xD3, 0xC6,
315330
0x24, 0x7B, 0x8F, 0xEC, 0xD2, 0x56, 0xE4, 0xEF, 0xA7, 0x87, 0x0D, 0x2C, 0x85, 0x4B,
@@ -349,26 +364,26 @@ mod tests {
349364
// Bad sizes
350365
assert_eq!(
351366
XOnlyPublicKey::from_slice(&[0; constants::SCHNORR_PUBLIC_KEY_SIZE - 1]),
352-
Err(InvalidPublicKey)
367+
Err(PublicKeyError)
353368
);
354369
assert_eq!(
355370
XOnlyPublicKey::from_slice(&[0; constants::SCHNORR_PUBLIC_KEY_SIZE + 1]),
356-
Err(InvalidPublicKey)
371+
Err(PublicKeyError)
357372
);
358373

359374
// Bad parse
360375
assert_eq!(
361376
XOnlyPublicKey::from_slice(&[0xff; constants::SCHNORR_PUBLIC_KEY_SIZE]),
362-
Err(InvalidPublicKey)
377+
Err(PublicKeyError)
363378
);
364379
// In fuzzing mode restrictions on public key validity are much more
365380
// relaxed, thus the invalid check below is expected to fail.
366381
#[cfg(not(secp256k1_fuzz))]
367382
assert_eq!(
368383
XOnlyPublicKey::from_slice(&[0x55; constants::SCHNORR_PUBLIC_KEY_SIZE]),
369-
Err(InvalidPublicKey)
384+
Err(PublicKeyError)
370385
);
371-
assert_eq!(XOnlyPublicKey::from_slice(&[]), Err(InvalidPublicKey));
386+
assert_eq!(XOnlyPublicKey::from_slice(&[]), Err(PublicKeyError));
372387
}
373388

374389
#[test]

0 commit comments

Comments
 (0)
Please sign in to comment.