#![allow(
clippy::uninlined_format_args,
clippy::must_use_candidate,
clippy::too_many_lines
)]
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::string::{
String,
ToString,
};
use core::fmt;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug, Clone, PartialEq)]
pub enum Error {
EntropySourceUnavailable {
source: &'static str,
context: Option<&'static str>,
},
InsufficientEntropy {
required: usize,
available: usize,
quality: f64,
},
EntropyValidationFailed {
reason: &'static str,
quality: f64,
details: Option<&'static str>,
},
HardwareRngFailed {
device: &'static str,
status: Option<u32>,
details: Option<&'static str>,
},
PlatformRngFailed {
platform: &'static str,
code: Option<i32>,
details: Option<&'static str>,
},
InvalidConfiguration {
parameter: &'static str,
#[cfg(feature = "alloc")]
expected: String,
#[cfg(not(feature = "alloc"))]
expected: &'static str,
#[cfg(feature = "alloc")]
actual: String,
#[cfg(not(feature = "alloc"))]
actual: &'static str,
},
MemoryAllocationFailed {
size: usize,
context: Option<&'static str>,
},
ThreadSafetyViolation {
violation: &'static str,
context: Option<&'static str>,
},
CryptographicFailure {
operation: &'static str,
code: Option<u32>,
details: Option<&'static str>,
},
TestVectorValidationFailed {
vector_id: &'static str,
#[cfg(feature = "alloc")]
expected: String,
#[cfg(not(feature = "alloc"))]
expected: &'static str,
#[cfg(feature = "alloc")]
actual: String,
#[cfg(not(feature = "alloc"))]
actual: &'static str,
},
FeatureNotAvailable {
feature: &'static str,
required_features: &'static [&'static str],
},
InternalError {
component: &'static str,
message: &'static str,
},
}
impl Error {
pub fn entropy_source_unavailable(source: &'static str) -> Self {
Self::EntropySourceUnavailable {
source,
context: None,
}
}
pub fn entropy_source_unavailable_with_context(
source: &'static str,
context: &'static str,
) -> Self {
Self::EntropySourceUnavailable {
source,
context: Some(context),
}
}
pub fn insufficient_entropy(required: usize, available: usize, quality: f64) -> Self {
Self::InsufficientEntropy {
required,
available,
quality,
}
}
pub fn entropy_validation_failed(reason: &'static str, quality: f64) -> Self {
Self::EntropyValidationFailed {
reason,
quality,
details: None,
}
}
pub fn entropy_validation_failed_with_details(
reason: &'static str,
quality: f64,
details: &'static str,
) -> Self {
Self::EntropyValidationFailed {
reason,
quality,
details: Some(details),
}
}
pub fn hardware_rng_failed(device: &'static str) -> Self {
Self::HardwareRngFailed {
device,
status: None,
details: None,
}
}
pub fn hardware_rng_failed_with_status(
device: &'static str,
status: u32,
details: &'static str,
) -> Self {
Self::HardwareRngFailed {
device,
status: Some(status),
details: Some(details),
}
}
pub fn platform_rng_failed(platform: &'static str) -> Self {
Self::PlatformRngFailed {
platform,
code: None,
details: None,
}
}
pub fn platform_rng_failed_with_code(
platform: &'static str,
code: i32,
details: &'static str,
) -> Self {
Self::PlatformRngFailed {
platform,
code: Some(code),
details: Some(details),
}
}
pub fn invalid_configuration(
parameter: &'static str,
expected: &'static str,
actual: &'static str,
) -> Self {
Self::InvalidConfiguration {
parameter,
#[cfg(feature = "alloc")]
expected: expected.to_string(),
#[cfg(not(feature = "alloc"))]
expected,
#[cfg(feature = "alloc")]
actual: actual.to_string(),
#[cfg(not(feature = "alloc"))]
actual,
}
}
pub fn memory_allocation_failed(size: usize) -> Self {
Self::MemoryAllocationFailed {
size,
context: None,
}
}
pub fn memory_allocation_failed_with_context(size: usize, context: &'static str) -> Self {
Self::MemoryAllocationFailed {
size,
context: Some(context),
}
}
pub fn thread_safety_violation(violation: &'static str) -> Self {
Self::ThreadSafetyViolation {
violation,
context: None,
}
}
pub fn thread_safety_violation_with_context(
violation: &'static str,
context: &'static str,
) -> Self {
Self::ThreadSafetyViolation {
violation,
context: Some(context),
}
}
pub fn cryptographic_failure(operation: &'static str) -> Self {
Self::CryptographicFailure {
operation,
code: None,
details: None,
}
}
pub fn cryptographic_failure_with_code(
operation: &'static str,
code: u32,
details: &'static str,
) -> Self {
Self::CryptographicFailure {
operation,
code: Some(code),
details: Some(details),
}
}
pub fn test_vector_validation_failed(
vector_id: &'static str,
expected: &'static str,
actual: &'static str,
) -> Self {
Self::TestVectorValidationFailed {
vector_id,
#[cfg(feature = "alloc")]
expected: expected.to_string(),
#[cfg(not(feature = "alloc"))]
expected,
#[cfg(feature = "alloc")]
actual: actual.to_string(),
#[cfg(not(feature = "alloc"))]
actual,
}
}
pub fn feature_not_available(
feature: &'static str,
required_features: &'static [&'static str],
) -> Self {
Self::FeatureNotAvailable {
feature,
required_features,
}
}
pub fn internal_error(component: &'static str, message: &'static str) -> Self {
Self::InternalError { component, message }
}
pub fn is_recoverable(&self) -> bool {
matches!(
self,
Self::EntropySourceUnavailable { .. } |
Self::PlatformRngFailed { .. } |
Self::HardwareRngFailed { .. }
)
}
pub fn is_entropy_related(&self) -> bool {
matches!(
self,
Self::EntropySourceUnavailable { .. } |
Self::InsufficientEntropy { .. } |
Self::EntropyValidationFailed { .. }
)
}
pub fn description(&self) -> &'static str {
match self {
Self::EntropySourceUnavailable { .. } => "Entropy source is not available",
Self::InsufficientEntropy { .. } => "Insufficient entropy for cryptographic operations",
Self::EntropyValidationFailed { .. } => "Entropy validation failed",
Self::HardwareRngFailed { .. } => "Hardware random number generator failed",
Self::PlatformRngFailed { .. } => "Platform random number generator failed",
Self::InvalidConfiguration { .. } => "Invalid configuration or parameters",
Self::MemoryAllocationFailed { .. } => "Memory allocation failed",
Self::ThreadSafetyViolation { .. } => "Thread safety violation detected",
Self::CryptographicFailure { .. } => "Cryptographic operation failed",
Self::TestVectorValidationFailed { .. } => "Test vector validation failed",
Self::FeatureNotAvailable { .. } => "Required feature is not available",
Self::InternalError { .. } => "Internal implementation error",
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::EntropySourceUnavailable { source, context } => {
write!(f, "Entropy source '{}' is not available", source)?;
if let Some(ctx) = context {
write!(f, ": {}", ctx)?;
}
Ok(())
}
Self::InsufficientEntropy {
required,
available,
quality,
} => {
write!(
f,
"Insufficient entropy: required {} bits, available {} bits (quality: {:.2})",
required, available, quality
)
}
Self::EntropyValidationFailed {
reason,
quality,
details,
} => {
write!(
f,
"Entropy validation failed: {} (quality: {:.2})",
reason, quality
)?;
if let Some(details) = details {
write!(f, ": {}", details)?;
}
Ok(())
}
Self::HardwareRngFailed {
device,
status,
details,
} => {
write!(f, "Hardware RNG '{}' failed", device)?;
if let Some(status) = status {
write!(f, " (status: {})", status)?;
}
if let Some(details) = details {
write!(f, ": {}", details)?;
}
Ok(())
}
Self::PlatformRngFailed {
platform,
code,
details,
} => {
write!(f, "Platform RNG '{}' failed", platform)?;
if let Some(code) = code {
write!(f, " (code: {})", code)?;
}
if let Some(details) = details {
write!(f, ": {}", details)?;
}
Ok(())
}
Self::InvalidConfiguration {
parameter,
expected,
actual,
} => {
write!(
f,
"Invalid configuration for '{}': expected {}, got {}",
parameter, expected, actual
)
}
Self::MemoryAllocationFailed { size, context } => {
write!(f, "Memory allocation failed for {} bytes", size)?;
if let Some(ctx) = context {
write!(f, ": {}", ctx)?;
}
Ok(())
}
Self::ThreadSafetyViolation { violation, context } => {
write!(f, "Thread safety violation: {}", violation)?;
if let Some(ctx) = context {
write!(f, ": {}", ctx)?;
}
Ok(())
}
Self::CryptographicFailure {
operation,
code,
details,
} => {
write!(f, "Cryptographic operation '{}' failed", operation)?;
if let Some(code) = code {
write!(f, " (code: {})", code)?;
}
if let Some(details) = details {
write!(f, ": {}", details)?;
}
Ok(())
}
Self::TestVectorValidationFailed {
vector_id,
expected,
actual,
} => {
write!(
f,
"Test vector '{}' validation failed: expected {}, got {}",
vector_id, expected, actual
)
}
Self::FeatureNotAvailable {
feature,
required_features,
} => {
write!(f, "Feature '{}' is not available", feature)?;
if !required_features.is_empty() {
#[cfg(feature = "alloc")]
{
write!(f, " (required features: {})", required_features.join(", "))?;
}
#[cfg(not(feature = "alloc"))]
{
write!(f, " (required features: {:?})", required_features)?;
}
}
Ok(())
}
Self::InternalError { component, message } => {
write!(f, "Internal error in '{}': {}", component, message)
}
}
}
}
impl core::error::Error for Error {}
#[cfg(test)]
mod tests {
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::format;
use super::*;
#[test]
fn test_error_creation() {
let err = Error::entropy_source_unavailable("test_source");
assert_eq!(err.description(), "Entropy source is not available");
assert!(err.is_entropy_related());
assert!(err.is_recoverable());
}
#[test]
#[cfg(any(feature = "std", feature = "alloc"))]
fn test_error_display() {
let err = Error::insufficient_entropy(256, 128, 0.5);
let display = format!("{}", err);
assert!(display.contains("Insufficient entropy"));
assert!(display.contains("256"));
assert!(display.contains("128"));
assert!(display.contains("0.50"));
}
#[test]
fn test_error_types() {
let entropy_err = Error::entropy_source_unavailable("test");
assert!(entropy_err.is_entropy_related());
let config_err = Error::invalid_configuration("param", "expected", "actual");
assert!(!config_err.is_entropy_related());
assert!(!config_err.is_recoverable());
}
}