use std::fmt;
#[derive(Debug)]
pub enum CryptoError {
InvalidKeyLength {
algorithm: &'static str,
expected: usize,
got: usize,
},
InvalidKey(String),
InvalidNonceLength {
algorithm: &'static str,
expected: usize,
got: usize,
},
AuthenticationFailed,
Encryption(String),
Decryption(String),
Kdf(String),
Pqc(String),
ReedSolomon(String),
InvalidParameter(String),
Serialization(String),
Compression(String),
Io(std::io::Error),
}
impl fmt::Display for CryptoError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CryptoError::InvalidKeyLength {
algorithm,
expected,
got,
} => write!(
f,
"Invalid key length for {algorithm}: expected {expected} bytes, got {got}"
),
CryptoError::InvalidKey(msg) => write!(f, "Invalid key: {msg}"),
CryptoError::InvalidNonceLength {
algorithm,
expected,
got,
} => write!(
f,
"Invalid nonce length for {algorithm}: expected {expected} bytes, got {got}"
),
CryptoError::AuthenticationFailed => write!(
f,
"Authentication failed (wrong key, tampered data, or invalid signature)"
),
CryptoError::Encryption(msg) => write!(f, "Encryption failed: {msg}"),
CryptoError::Decryption(msg) => write!(f, "Decryption failed: {msg}"),
CryptoError::Kdf(msg) => write!(f, "KDF error: {msg}"),
CryptoError::Pqc(msg) => write!(f, "PQC error: {msg}"),
CryptoError::ReedSolomon(msg) => write!(f, "Reed-Solomon error: {msg}"),
CryptoError::InvalidParameter(msg) => write!(f, "Invalid parameter: {msg}"),
CryptoError::Serialization(msg) => write!(f, "Serialization error: {msg}"),
CryptoError::Compression(msg) => write!(f, "Compression error: {msg}"),
CryptoError::Io(err) => write!(f, "I/O error: {err}"),
}
}
}
impl std::error::Error for CryptoError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
CryptoError::Io(err) => Some(err),
_ => None,
}
}
}
impl From<std::io::Error> for CryptoError {
fn from(err: std::io::Error) -> Self {
CryptoError::Io(err)
}
}
impl Clone for CryptoError {
fn clone(&self) -> Self {
match self {
CryptoError::InvalidKeyLength {
algorithm,
expected,
got,
} => CryptoError::InvalidKeyLength {
algorithm,
expected: *expected,
got: *got,
},
CryptoError::InvalidKey(msg) => CryptoError::InvalidKey(msg.clone()),
CryptoError::InvalidNonceLength {
algorithm,
expected,
got,
} => CryptoError::InvalidNonceLength {
algorithm,
expected: *expected,
got: *got,
},
CryptoError::AuthenticationFailed => CryptoError::AuthenticationFailed,
CryptoError::Encryption(msg) => CryptoError::Encryption(msg.clone()),
CryptoError::Decryption(msg) => CryptoError::Decryption(msg.clone()),
CryptoError::Kdf(msg) => CryptoError::Kdf(msg.clone()),
CryptoError::Pqc(msg) => CryptoError::Pqc(msg.clone()),
CryptoError::ReedSolomon(msg) => CryptoError::ReedSolomon(msg.clone()),
CryptoError::InvalidParameter(msg) => CryptoError::InvalidParameter(msg.clone()),
CryptoError::Serialization(msg) => CryptoError::Serialization(msg.clone()),
CryptoError::Compression(msg) => CryptoError::Compression(msg.clone()),
CryptoError::Io(err) => CryptoError::Io(std::io::Error::new(
err.kind(),
err.to_string(),
)),
}
}
}
pub type Result<T> = std::result::Result<T, CryptoError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_invalid_key_length_display() {
let err = CryptoError::InvalidKeyLength {
algorithm: "Falcon-1024",
expected: 32,
got: 16,
};
let msg = err.to_string();
assert!(msg.contains("Falcon-1024"));
assert!(msg.contains("expected 32"));
assert!(msg.contains("got 16"));
}
#[test]
fn test_auth_failed_display() {
let err = CryptoError::AuthenticationFailed;
assert!(err.to_string().contains("Authentication failed"));
}
#[test]
fn test_clone_roundtrip() {
let err = CryptoError::InvalidKeyLength {
algorithm: "Ed25519",
expected: 32,
got: 31,
};
let cloned = err.clone();
assert_eq!(err.to_string(), cloned.to_string());
}
#[test]
fn test_io_from() {
let io_err = std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "truncated");
let crypto_err: CryptoError = io_err.into();
assert!(matches!(crypto_err, CryptoError::Io(_)));
assert!(crypto_err.to_string().contains("truncated"));
}
}