1#![allow(
4 clippy::uninlined_format_args,
5 clippy::must_use_candidate,
6 clippy::too_many_lines
7)]
8
9#[cfg(all(not(feature = "std"), feature = "alloc"))]
16use alloc::string::{
17 String,
18 ToString,
19};
20use core::fmt;
21
22pub type Result<T> = core::result::Result<T, Error>;
24
25#[derive(Debug, Clone, PartialEq)]
30pub enum Error {
31 EntropySourceUnavailable {
33 source: &'static str,
35 context: Option<&'static str>,
37 },
38
39 InsufficientEntropy {
41 required: usize,
43 available: usize,
45 quality: f64,
47 },
48
49 EntropyValidationFailed {
51 reason: &'static str,
53 quality: f64,
55 details: Option<&'static str>,
57 },
58
59 HardwareRngFailed {
61 device: &'static str,
63 status: Option<u32>,
65 details: Option<&'static str>,
67 },
68
69 PlatformRngFailed {
71 platform: &'static str,
73 code: Option<i32>,
75 details: Option<&'static str>,
77 },
78
79 InvalidConfiguration {
81 parameter: &'static str,
83 #[cfg(feature = "alloc")]
85 expected: String,
86 #[cfg(not(feature = "alloc"))]
88 expected: &'static str,
89 #[cfg(feature = "alloc")]
91 actual: String,
92 #[cfg(not(feature = "alloc"))]
94 actual: &'static str,
95 },
96
97 MemoryAllocationFailed {
99 size: usize,
101 context: Option<&'static str>,
103 },
104
105 ThreadSafetyViolation {
107 violation: &'static str,
109 context: Option<&'static str>,
111 },
112
113 CryptographicFailure {
115 operation: &'static str,
117 code: Option<u32>,
119 details: Option<&'static str>,
121 },
122
123 TestVectorValidationFailed {
125 vector_id: &'static str,
127 #[cfg(feature = "alloc")]
129 expected: String,
130 #[cfg(not(feature = "alloc"))]
132 expected: &'static str,
133 #[cfg(feature = "alloc")]
135 actual: String,
136 #[cfg(not(feature = "alloc"))]
138 actual: &'static str,
139 },
140
141 FeatureNotAvailable {
143 feature: &'static str,
145 required_features: &'static [&'static str],
147 },
148
149 InternalError {
151 component: &'static str,
153 message: &'static str,
155 },
156}
157
158impl Error {
159 pub fn entropy_source_unavailable(source: &'static str) -> Self {
161 Self::EntropySourceUnavailable {
162 source,
163 context: None,
164 }
165 }
166
167 pub fn entropy_source_unavailable_with_context(
169 source: &'static str,
170 context: &'static str,
171 ) -> Self {
172 Self::EntropySourceUnavailable {
173 source,
174 context: Some(context),
175 }
176 }
177
178 pub fn insufficient_entropy(required: usize, available: usize, quality: f64) -> Self {
180 Self::InsufficientEntropy {
181 required,
182 available,
183 quality,
184 }
185 }
186
187 pub fn entropy_validation_failed(reason: &'static str, quality: f64) -> Self {
189 Self::EntropyValidationFailed {
190 reason,
191 quality,
192 details: None,
193 }
194 }
195
196 pub fn entropy_validation_failed_with_details(
198 reason: &'static str,
199 quality: f64,
200 details: &'static str,
201 ) -> Self {
202 Self::EntropyValidationFailed {
203 reason,
204 quality,
205 details: Some(details),
206 }
207 }
208
209 pub fn hardware_rng_failed(device: &'static str) -> Self {
211 Self::HardwareRngFailed {
212 device,
213 status: None,
214 details: None,
215 }
216 }
217
218 pub fn hardware_rng_failed_with_status(
220 device: &'static str,
221 status: u32,
222 details: &'static str,
223 ) -> Self {
224 Self::HardwareRngFailed {
225 device,
226 status: Some(status),
227 details: Some(details),
228 }
229 }
230
231 pub fn platform_rng_failed(platform: &'static str) -> Self {
233 Self::PlatformRngFailed {
234 platform,
235 code: None,
236 details: None,
237 }
238 }
239
240 pub fn platform_rng_failed_with_code(
242 platform: &'static str,
243 code: i32,
244 details: &'static str,
245 ) -> Self {
246 Self::PlatformRngFailed {
247 platform,
248 code: Some(code),
249 details: Some(details),
250 }
251 }
252
253 pub fn invalid_configuration(
255 parameter: &'static str,
256 expected: &'static str,
257 actual: &'static str,
258 ) -> Self {
259 Self::InvalidConfiguration {
260 parameter,
261 #[cfg(feature = "alloc")]
262 expected: expected.to_string(),
263 #[cfg(not(feature = "alloc"))]
264 expected,
265 #[cfg(feature = "alloc")]
266 actual: actual.to_string(),
267 #[cfg(not(feature = "alloc"))]
268 actual,
269 }
270 }
271
272 pub fn memory_allocation_failed(size: usize) -> Self {
274 Self::MemoryAllocationFailed {
275 size,
276 context: None,
277 }
278 }
279
280 pub fn memory_allocation_failed_with_context(size: usize, context: &'static str) -> Self {
282 Self::MemoryAllocationFailed {
283 size,
284 context: Some(context),
285 }
286 }
287
288 pub fn thread_safety_violation(violation: &'static str) -> Self {
290 Self::ThreadSafetyViolation {
291 violation,
292 context: None,
293 }
294 }
295
296 pub fn thread_safety_violation_with_context(
298 violation: &'static str,
299 context: &'static str,
300 ) -> Self {
301 Self::ThreadSafetyViolation {
302 violation,
303 context: Some(context),
304 }
305 }
306
307 pub fn cryptographic_failure(operation: &'static str) -> Self {
309 Self::CryptographicFailure {
310 operation,
311 code: None,
312 details: None,
313 }
314 }
315
316 pub fn cryptographic_failure_with_code(
318 operation: &'static str,
319 code: u32,
320 details: &'static str,
321 ) -> Self {
322 Self::CryptographicFailure {
323 operation,
324 code: Some(code),
325 details: Some(details),
326 }
327 }
328
329 pub fn test_vector_validation_failed(
331 vector_id: &'static str,
332 expected: &'static str,
333 actual: &'static str,
334 ) -> Self {
335 Self::TestVectorValidationFailed {
336 vector_id,
337 #[cfg(feature = "alloc")]
338 expected: expected.to_string(),
339 #[cfg(not(feature = "alloc"))]
340 expected,
341 #[cfg(feature = "alloc")]
342 actual: actual.to_string(),
343 #[cfg(not(feature = "alloc"))]
344 actual,
345 }
346 }
347
348 pub fn feature_not_available(
350 feature: &'static str,
351 required_features: &'static [&'static str],
352 ) -> Self {
353 Self::FeatureNotAvailable {
354 feature,
355 required_features,
356 }
357 }
358
359 pub fn internal_error(component: &'static str, message: &'static str) -> Self {
361 Self::InternalError { component, message }
362 }
363
364 pub fn is_recoverable(&self) -> bool {
366 matches!(
367 self,
368 Self::EntropySourceUnavailable { .. } |
369 Self::PlatformRngFailed { .. } |
370 Self::HardwareRngFailed { .. }
371 )
372 }
373
374 pub fn is_entropy_related(&self) -> bool {
376 matches!(
377 self,
378 Self::EntropySourceUnavailable { .. } |
379 Self::InsufficientEntropy { .. } |
380 Self::EntropyValidationFailed { .. }
381 )
382 }
383
384 pub fn description(&self) -> &'static str {
386 match self {
387 Self::EntropySourceUnavailable { .. } => "Entropy source is not available",
388 Self::InsufficientEntropy { .. } => "Insufficient entropy for cryptographic operations",
389 Self::EntropyValidationFailed { .. } => "Entropy validation failed",
390 Self::HardwareRngFailed { .. } => "Hardware random number generator failed",
391 Self::PlatformRngFailed { .. } => "Platform random number generator failed",
392 Self::InvalidConfiguration { .. } => "Invalid configuration or parameters",
393 Self::MemoryAllocationFailed { .. } => "Memory allocation failed",
394 Self::ThreadSafetyViolation { .. } => "Thread safety violation detected",
395 Self::CryptographicFailure { .. } => "Cryptographic operation failed",
396 Self::TestVectorValidationFailed { .. } => "Test vector validation failed",
397 Self::FeatureNotAvailable { .. } => "Required feature is not available",
398 Self::InternalError { .. } => "Internal implementation error",
399 }
400 }
401}
402
403impl fmt::Display for Error {
404 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
405 match self {
406 Self::EntropySourceUnavailable { source, context } => {
407 write!(f, "Entropy source '{}' is not available", source)?;
408 if let Some(ctx) = context {
409 write!(f, ": {}", ctx)?;
410 }
411 Ok(())
412 }
413 Self::InsufficientEntropy {
414 required,
415 available,
416 quality,
417 } => {
418 write!(
419 f,
420 "Insufficient entropy: required {} bits, available {} bits (quality: {:.2})",
421 required, available, quality
422 )
423 }
424 Self::EntropyValidationFailed {
425 reason,
426 quality,
427 details,
428 } => {
429 write!(
430 f,
431 "Entropy validation failed: {} (quality: {:.2})",
432 reason, quality
433 )?;
434 if let Some(details) = details {
435 write!(f, ": {}", details)?;
436 }
437 Ok(())
438 }
439 Self::HardwareRngFailed {
440 device,
441 status,
442 details,
443 } => {
444 write!(f, "Hardware RNG '{}' failed", device)?;
445 if let Some(status) = status {
446 write!(f, " (status: {})", status)?;
447 }
448 if let Some(details) = details {
449 write!(f, ": {}", details)?;
450 }
451 Ok(())
452 }
453 Self::PlatformRngFailed {
454 platform,
455 code,
456 details,
457 } => {
458 write!(f, "Platform RNG '{}' failed", platform)?;
459 if let Some(code) = code {
460 write!(f, " (code: {})", code)?;
461 }
462 if let Some(details) = details {
463 write!(f, ": {}", details)?;
464 }
465 Ok(())
466 }
467 Self::InvalidConfiguration {
468 parameter,
469 expected,
470 actual,
471 } => {
472 write!(
473 f,
474 "Invalid configuration for '{}': expected {}, got {}",
475 parameter, expected, actual
476 )
477 }
478 Self::MemoryAllocationFailed { size, context } => {
479 write!(f, "Memory allocation failed for {} bytes", size)?;
480 if let Some(ctx) = context {
481 write!(f, ": {}", ctx)?;
482 }
483 Ok(())
484 }
485 Self::ThreadSafetyViolation { violation, context } => {
486 write!(f, "Thread safety violation: {}", violation)?;
487 if let Some(ctx) = context {
488 write!(f, ": {}", ctx)?;
489 }
490 Ok(())
491 }
492 Self::CryptographicFailure {
493 operation,
494 code,
495 details,
496 } => {
497 write!(f, "Cryptographic operation '{}' failed", operation)?;
498 if let Some(code) = code {
499 write!(f, " (code: {})", code)?;
500 }
501 if let Some(details) = details {
502 write!(f, ": {}", details)?;
503 }
504 Ok(())
505 }
506 Self::TestVectorValidationFailed {
507 vector_id,
508 expected,
509 actual,
510 } => {
511 write!(
512 f,
513 "Test vector '{}' validation failed: expected {}, got {}",
514 vector_id, expected, actual
515 )
516 }
517 Self::FeatureNotAvailable {
518 feature,
519 required_features,
520 } => {
521 write!(f, "Feature '{}' is not available", feature)?;
522 if !required_features.is_empty() {
523 #[cfg(feature = "alloc")]
524 {
525 write!(f, " (required features: {})", required_features.join(", "))?;
526 }
527 #[cfg(not(feature = "alloc"))]
528 {
529 write!(f, " (required features: {:?})", required_features)?;
530 }
531 }
532 Ok(())
533 }
534 Self::InternalError { component, message } => {
535 write!(f, "Internal error in '{}': {}", component, message)
536 }
537 }
538 }
539}
540
541#[cfg(feature = "std")]
542impl std::error::Error for Error {}
543
544#[cfg(test)]
545mod tests {
546 #[cfg(all(not(feature = "std"), feature = "alloc"))]
547 use alloc::format;
548
549 use super::*;
550
551 #[test]
552 fn test_error_creation() {
553 let err = Error::entropy_source_unavailable("test_source");
554 assert_eq!(err.description(), "Entropy source is not available");
555 assert!(err.is_entropy_related());
556 assert!(err.is_recoverable());
557 }
558
559 #[test]
560 #[cfg(any(feature = "std", feature = "alloc"))]
561 fn test_error_display() {
562 let err = Error::insufficient_entropy(256, 128, 0.5);
563 let display = format!("{}", err);
564 assert!(display.contains("Insufficient entropy"));
565 assert!(display.contains("256"));
566 assert!(display.contains("128"));
567 assert!(display.contains("0.50"));
568 }
569
570 #[test]
571 fn test_error_types() {
572 let entropy_err = Error::entropy_source_unavailable("test");
573 assert!(entropy_err.is_entropy_related());
574
575 let config_err = Error::invalid_configuration("param", "expected", "actual");
576 assert!(!config_err.is_entropy_related());
577 assert!(!config_err.is_recoverable());
578 }
579}