Skip to main content

chains_sdk/
error.rs

1//! Unified error types for all signing operations.
2
3/// Errors that can occur during signing, verification, or key management.
4#[derive(Debug, thiserror::Error)]
5pub enum SignerError {
6    /// The provided private key bytes are invalid (wrong length, out of range, or malformed).
7    #[error("invalid private key: {0}")]
8    InvalidPrivateKey(String),
9
10    /// The provided public key bytes are invalid or not on the expected curve.
11    #[error("invalid public key: {0}")]
12    InvalidPublicKey(String),
13
14    /// The provided signature bytes are invalid or malformed.
15    #[error("invalid signature: {0}")]
16    InvalidSignature(String),
17
18    /// The signing operation failed.
19    #[error("signing failed: {0}")]
20    SigningFailed(String),
21
22    /// Signature verification did not pass.
23    #[error("verification failed")]
24    VerificationFailed,
25
26    /// The provided digest/hash has an unexpected length.
27    #[error("invalid hash length: expected {expected}, got {got}")]
28    InvalidHashLength {
29        /// Expected digest length in bytes.
30        expected: usize,
31        /// Actual digest length provided.
32        got: usize,
33    },
34
35    /// Failed to generate random bytes from the OS CSPRNG.
36    #[error("entropy error")]
37    EntropyError,
38
39    /// BLS signature aggregation failed.
40    #[error("aggregation error: {0}")]
41    AggregationError(String),
42
43    /// Encoding or decoding failed (bech32, base58, compact size, hex).
44    #[error("encoding error: {0}")]
45    EncodingError(String),
46
47    /// Parsing failed (descriptors, PSBT, script).
48    #[error("parse error: {0}")]
49    ParseError(String),
50}
51
52#[cfg(test)]
53#[allow(clippy::unwrap_used, clippy::expect_used)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn test_display_invalid_private_key() {
59        let e = SignerError::InvalidPrivateKey("too short".into());
60        assert_eq!(e.to_string(), "invalid private key: too short");
61    }
62
63    #[test]
64    fn test_display_invalid_public_key() {
65        let e = SignerError::InvalidPublicKey("not on curve".into());
66        assert!(e.to_string().contains("not on curve"));
67    }
68
69    #[test]
70    fn test_display_invalid_signature() {
71        let e = SignerError::InvalidSignature("bad DER".into());
72        assert!(e.to_string().contains("bad DER"));
73    }
74
75    #[test]
76    fn test_display_signing_failed() {
77        let e = SignerError::SigningFailed("nonce error".into());
78        assert!(e.to_string().contains("nonce error"));
79    }
80
81    #[test]
82    fn test_display_verification_failed() {
83        let e = SignerError::VerificationFailed;
84        assert_eq!(e.to_string(), "verification failed");
85    }
86
87    #[test]
88    fn test_display_invalid_hash_length() {
89        let e = SignerError::InvalidHashLength {
90            expected: 32,
91            got: 20,
92        };
93        let s = e.to_string();
94        assert!(s.contains("32"));
95        assert!(s.contains("20"));
96    }
97
98    #[test]
99    fn test_display_entropy_error() {
100        assert_eq!(SignerError::EntropyError.to_string(), "entropy error");
101    }
102
103    #[test]
104    fn test_display_aggregation_error() {
105        let e = SignerError::AggregationError("no shares".into());
106        assert!(e.to_string().contains("no shares"));
107    }
108
109    #[test]
110    fn test_display_encoding_error() {
111        let e = SignerError::EncodingError("bad bech32".into());
112        assert!(e.to_string().contains("bad bech32"));
113    }
114
115    #[test]
116    fn test_display_parse_error() {
117        let e = SignerError::ParseError("invalid descriptor".into());
118        assert!(e.to_string().contains("invalid descriptor"));
119    }
120
121    #[test]
122    fn test_error_is_send_sync() {
123        fn assert_send_sync<T: Send + Sync>() {}
124        assert_send_sync::<SignerError>();
125    }
126}