#![deny(unsafe_code)]
#![deny(missing_docs)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::panic)]
use thiserror::Error;
pub use crate::types::error::TypeError;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum CoreError {
#[error("Invalid input: {0}")]
InvalidInput(String),
#[error("Invalid key length: expected {expected}, got {actual}")]
InvalidKeyLength {
expected: usize,
actual: usize,
},
#[error("Encryption failed: {0}")]
EncryptionFailed(String),
#[error("Decryption failed: {0}")]
DecryptionFailed(String),
#[error("Signature verification failed")]
VerificationFailed,
#[error("Key derivation failed: {0}")]
KeyDerivationFailed(String),
#[error("Invalid nonce: {0}")]
InvalidNonce(String),
#[error("Hardware error: {0}")]
HardwareError(String),
#[error("Configuration error: {0}")]
ConfigurationError(String),
#[error("Scheme selection failed: {0}")]
SchemeSelectionFailed(String),
#[error("Authentication failed: {0}")]
AuthenticationFailed(String),
#[error("Zero-trust verification failed: {0}")]
ZeroTrustVerificationFailed(String),
#[error("Authentication required: {0}")]
AuthenticationRequired(String),
#[error("Session expired")]
SessionExpired,
#[error("Unsupported operation: {0}")]
UnsupportedOperation(String),
#[error("Memory allocation failed: {0}")]
MemoryError(String),
#[error("IO error: {0}")]
IoError(#[from] std::io::Error),
#[error("ML-KEM error: {0}")]
MlKemError(#[from] crate::primitives::kem::ml_kem::MlKemError),
#[error("ML-DSA error: {0}")]
MlDsaError(#[from] crate::primitives::sig::ml_dsa::MlDsaError),
#[error("SLH-DSA error: {0}")]
SlhDsaError(#[from] crate::primitives::sig::slh_dsa::SlhDsaError),
#[error("Serialization error: {0}")]
SerializationError(String),
#[error("Recoverable error: {message}. Suggestion: {suggestion}")]
Recoverable {
message: String,
suggestion: String,
},
#[error("Hardware acceleration unavailable: {reason}. Fallback: {fallback}")]
HardwareUnavailable {
reason: String,
fallback: String,
},
#[error("Entropy source depleted: {message}. Action: {action}")]
EntropyDepleted {
message: String,
action: String,
},
#[error("Key generation failed: {reason}. Recovery: {recovery}")]
KeyGenerationFailed {
reason: String,
recovery: String,
},
#[error("Self-test failed: {component}. Status: {status}")]
SelfTestFailed {
component: String,
status: String,
},
#[error("Feature not available: {0}")]
FeatureNotAvailable(String),
#[error("Invalid signature: {0}")]
InvalidSignature(String),
#[error("Invalid key: {0}")]
InvalidKey(String),
#[error("Not implemented: {0}")]
NotImplemented(String),
#[error("Signature failed: {0}")]
SignatureFailed(String),
#[error("HSM error: {0}")]
HsmError(String),
#[error("Resource limit exceeded: {0}")]
ResourceExceeded(String),
#[error("Invalid key state transition: {from:?} -> {to:?}")]
InvalidStateTransition {
from: crate::unified_api::KeyLifecycleState,
to: crate::unified_api::KeyLifecycleState,
},
#[error("Audit error: {0}")]
AuditError(String),
#[error("Compliance violation: {0}")]
ComplianceViolation(String),
}
impl From<TypeError> for CoreError {
fn from(err: TypeError) -> Self {
match err {
TypeError::InvalidStateTransition { from, to } => {
CoreError::InvalidStateTransition { from, to }
}
TypeError::ConfigurationError(msg) => CoreError::ConfigurationError(msg),
TypeError::UnknownScheme(scheme) => {
CoreError::DecryptionFailed(format!("Unknown encryption scheme: {scheme}"))
}
}
}
}
pub type Result<T> = std::result::Result<T, CoreError>;
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
#[test]
fn test_core_error_display_invalid_input_has_correct_format() {
let err = CoreError::InvalidInput("bad data".to_string());
assert_eq!(format!("{err}"), "Invalid input: bad data");
}
#[test]
fn test_core_error_display_invalid_key_length_has_correct_format() {
let err = CoreError::InvalidKeyLength { expected: 32, actual: 16 };
assert_eq!(format!("{err}"), "Invalid key length: expected 32, got 16");
}
#[test]
fn test_core_error_display_encryption_failed_has_correct_format() {
let err = CoreError::EncryptionFailed("buffer too small".to_string());
assert_eq!(format!("{err}"), "Encryption failed: buffer too small");
}
#[test]
fn test_core_error_display_decryption_failed_has_correct_format() {
let err = CoreError::DecryptionFailed("auth tag mismatch".to_string());
assert_eq!(format!("{err}"), "Decryption failed: auth tag mismatch");
}
#[test]
fn test_core_error_display_verification_failed_has_correct_format() {
let err = CoreError::VerificationFailed;
assert_eq!(format!("{err}"), "Signature verification failed");
}
#[test]
fn test_core_error_display_session_expired_has_correct_format() {
let err = CoreError::SessionExpired;
assert_eq!(format!("{err}"), "Session expired");
}
#[test]
fn test_core_error_display_recoverable_includes_message_and_suggestion_fails() {
let err = CoreError::Recoverable {
message: "temporary failure".to_string(),
suggestion: "retry after 5s".to_string(),
};
let msg = format!("{err}");
assert!(msg.contains("temporary failure"));
assert!(msg.contains("retry after 5s"));
}
#[test]
fn test_core_error_display_hardware_unavailable_includes_reason_and_fallback_fails() {
let err = CoreError::HardwareUnavailable {
reason: "no AES-NI".to_string(),
fallback: "software AES".to_string(),
};
let msg = format!("{err}");
assert!(msg.contains("no AES-NI"));
assert!(msg.contains("software AES"));
}
#[test]
fn test_core_error_display_entropy_depleted_includes_message_and_action_fails() {
let err = CoreError::EntropyDepleted {
message: "pool empty".to_string(),
action: "wait and retry".to_string(),
};
let msg = format!("{err}");
assert!(msg.contains("pool empty"));
assert!(msg.contains("wait and retry"));
}
#[test]
fn test_core_error_display_key_generation_failed_includes_reason_and_recovery_fails() {
let err = CoreError::KeyGenerationFailed {
reason: "insufficient entropy".to_string(),
recovery: "seed from HSM".to_string(),
};
let msg = format!("{err}");
assert!(msg.contains("insufficient entropy"));
assert!(msg.contains("seed from HSM"));
}
#[test]
fn test_core_error_display_self_test_failed_includes_component_and_status_fails() {
let err = CoreError::SelfTestFailed {
component: "AES-GCM".to_string(),
status: "KAT mismatch".to_string(),
};
let msg = format!("{err}");
assert!(msg.contains("AES-GCM"));
assert!(msg.contains("KAT mismatch"));
}
#[test]
fn test_core_error_display_serialization_has_correct_format() {
let err = CoreError::SerializationError("invalid JSON".to_string());
assert_eq!(format!("{err}"), "Serialization error: invalid JSON");
}
#[test]
fn test_core_error_display_feature_not_available_fails() {
let err = CoreError::FeatureNotAvailable("HSM support".to_string());
assert_eq!(format!("{err}"), "Feature not available: HSM support");
}
#[test]
fn test_core_error_display_not_implemented_has_correct_format() {
let err = CoreError::NotImplemented("FN-DSA Level 5".to_string());
assert_eq!(format!("{err}"), "Not implemented: FN-DSA Level 5");
}
#[test]
fn test_core_error_display_hsm_error_has_correct_format() {
let err = CoreError::HsmError("connection lost".to_string());
assert_eq!(format!("{err}"), "HSM error: connection lost");
}
#[test]
fn test_core_error_display_resource_exceeded_has_correct_format() {
let err = CoreError::ResourceExceeded("max connections".to_string());
assert_eq!(format!("{err}"), "Resource limit exceeded: max connections");
}
#[test]
fn test_core_error_display_audit_error_has_correct_format() {
let err = CoreError::AuditError("write failed".to_string());
assert_eq!(format!("{err}"), "Audit error: write failed");
}
#[test]
fn test_core_error_from_io_error_converts_correctly_fails() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
let err: CoreError = io_err.into();
let msg = format!("{err}");
assert!(msg.contains("file missing"));
}
#[test]
fn test_core_error_debug_contains_variant_name_fails() {
let err = CoreError::InvalidInput("test".to_string());
let debug = format!("{:?}", err);
assert!(debug.contains("InvalidInput"));
}
#[test]
fn test_core_error_all_simple_variants_have_correct_format_fails() {
let cases: Vec<(CoreError, &str)> = vec![
(CoreError::KeyDerivationFailed("kdf".to_string()), "Key derivation failed: kdf"),
(CoreError::InvalidNonce("nonce".to_string()), "Invalid nonce: nonce"),
(CoreError::HardwareError("hw".to_string()), "Hardware error: hw"),
(CoreError::ConfigurationError("cfg".to_string()), "Configuration error: cfg"),
(CoreError::SchemeSelectionFailed("sel".to_string()), "Scheme selection failed: sel"),
(CoreError::AuthenticationFailed("auth".to_string()), "Authentication failed: auth"),
(
CoreError::ZeroTrustVerificationFailed("zt".to_string()),
"Zero-trust verification failed: zt",
),
(CoreError::AuthenticationRequired("req".to_string()), "Authentication required: req"),
(CoreError::UnsupportedOperation("op".to_string()), "Unsupported operation: op"),
(CoreError::MemoryError("mem".to_string()), "Memory allocation failed: mem"),
(CoreError::InvalidSignature("sig".to_string()), "Invalid signature: sig"),
(CoreError::InvalidKey("key".to_string()), "Invalid key: key"),
(CoreError::SignatureFailed("sf".to_string()), "Signature failed: sf"),
(
CoreError::ComplianceViolation("FIPS rejects chacha".to_string()),
"Compliance violation: FIPS rejects chacha",
),
];
for (error, expected_msg) in cases {
assert_eq!(format!("{error}"), expected_msg);
}
}
}