dcrypt 2.0.0

Rust APIs for classical, post-quantum, and hybrid cryptographic primitives
Documentation
# API Error Handling (`api/error`)

This module establishes the core error handling infrastructure for the dcrypt library. It defines the primary `Error` enum, a unified `Result` type, extension traits for easier error manipulation, and a compatibility registry for deferred diagnostics.

## Core Components

1.  **`Error` Enum (`types.rs`)**:
    The central error type used across the dcrypt API. It covers a range of common cryptographic error scenarios:
    *   `InvalidKey`: Issues with cryptographic keys (e.g., wrong size, invalid format).
    *   `InvalidSignature`: Signature verification failures or malformed signatures.
    *   `DecryptionFailed`: General failure during decryption (often implies failed authentication in AEAD).
    *   `InvalidCiphertext`: Ciphertext is malformed or has an invalid structure.
    *   `InvalidLength`: Data provided has an incorrect length for the operation.
    *   `InvalidParameter`: A general parameter provided to a function is invalid.
    *   `SerializationError`: Failure during serialization or deserialization of cryptographic objects.
    *   `RandomGenerationError`: Failure during the generation of random numbers or cryptographic material.
    *   `NotImplemented`: A requested feature or algorithm is not implemented.
    *   `AuthenticationFailed`: Explicit failure of an authentication check (e.g., MAC or AEAD tag mismatch).
    *   `Other`: A catch-all for other types of errors, often wrapping errors from underlying libraries or system calls.

    Each variant includes a `context` field (`&'static str`) and, when the `std` feature is enabled, an optional `message` field (`String`) for more detailed error information. The `Error` enum implements `Debug`, `Clone`, `PartialEq`, `Eq`, `Display`, and `std::error::Error` (if `std` is enabled).

2.  **`Result<T>` Type Alias (`types.rs`)**:
    A standard alias for `core::result::Result<T, api::Error>`, used throughout the dcrypt ecosystem for fallible operations.

3.  **`ErrorRegistry` (`registry.rs`)**:
    *   `pub static ERROR_REGISTRY: ErrorRegistry`: A globally accessible static instance of the error registry.
    *   **Purpose**: Retained for compatibility with code that records a diagnostic before returning fallback data. A global last-error slot is inherently vulnerable to unrelated operations overwriting it, so returning errors directly is preferred.
    *   Methods: `new()`, `store(error)`, `clear()`, `has_error()`, `get_error()` (std-only, for retrieving a clone of the stored error).
    *   **Memory Management**: In `std` mode, a mutex owns an optional `Box<dyn Any + Send>` plus a mutation generation. Retrieval temporarily takes ownership, performs a checked downcast and clone without holding the mutex, and restores the value only if no newer store/clear operation occurred. A mismatched requested type returns `None`; reentrant user-defined `Clone` implementations cannot deadlock the registry. In `no_std` mode, it can only indicate the presence of an error, not store the error itself.

4.  **Error Handling Traits (`traits.rs`)**:
    *   **`ResultExt<T, E>`**: An extension trait for `core::result::Result<T, E>`.
        *   `wrap_err()`: Maps an `Err` to a new error type.
        *   `with_context(context: &'static str)`: Adds static context to an error that can be converted into `api::Error`.
        *   `with_message(message: impl Into<String>)` (std-only): Adds a dynamic message to an error.
    *   **`ErrorRegistryExt<T, E>`**:
        *   `unwrap_or_record_with(default: T, on_error: F) -> T`: On `Err`, stores the error generated by `on_error` and returns `default`. This method uses ordinary branching and is only appropriate when the result variant is public.
    *   **`SecureErrorHandling<T, E>`** (compatibility API with a deprecated method):
        *   `secure_unwrap(default: T, on_error: F) -> T`: Has the same branching behavior as `unwrap_or_record_with`; despite its historical name, it is not constant-time.
    *   **`ConstantTimeResult<T, E>`** (compatibility API with deprecated methods):
        *   Its `ct_is_ok()`, `ct_is_err()`, and `ct_map()` names are historical. They branch on the enum discriminant and `ct_map()` invokes only the selected closure. Use ordinary `Result` methods, and do not use a secret result variant as control flow.

5.  **Validation Utilities (`validate.rs`)**:
    A collection of helper functions for validating inputs and conditions, returning `api::Result<()>` or `api::Result<T>` on success, or an appropriate `api::Error` variant on failure.
    *   `parameter()` / `check_parameter()`: General condition check.
    *   `length()`, `min_length()`, `max_length()`, `range_length()`: For validating data lengths.
    *   `authentication()`: For authentication results.
    *   `key()`, `signature()`, `ciphertext()`: For validating formats of specific cryptographic types.
    *   `not_implemented()`: Convenience for returning `Error::NotImplemented`.

## Error Propagation and Conversion

-   Errors from lower-level crates (like `algorithms::Error`) typically implement `From<LowerLevelError> for api::Error` or are wrapped.
-   The `ResultExt` trait helps in adding context as errors propagate up the call stack.
-   The `Error` enum itself provides `with_context()` and `with_message()` methods for further enrichment.

## Example of Deferred Error Recording

```rust
use dcrypt_api::error::{Error, ErrorRegistryExt, Result, ERROR_REGISTRY};

// This is ordinary branching control flow; `succeed` must not be secret.
fn fallible_operation(succeed: bool) -> Result<u32> {
    if succeed {
        Ok(42)
    } else {
        Err(Error::Other { context: "dummy failure", #[cfg(feature="std")] message: "".into() })
    }
}

fn example_deferred_error() {
    ERROR_REGISTRY.clear(); // Clear any previous errors

    let result_value = fallible_operation(false)
        .unwrap_or_record_with(0, || Error::DecryptionFailed {
            context: "deferred_error_example",
            #[cfg(feature="std")]
            message: "Operation failed".into(),
        });

    // At this point, result_value is 0 (the default)
    // The actual error is stored in ERROR_REGISTRY
    if ERROR_REGISTRY.has_error() {
        println!("Operation failed, default value {} used.", result_value);
        // Optionally, retrieve and log the error if in `std` mode
        #[cfg(feature="std")]
        if let Some(err) = ERROR_REGISTRY.get_error::<Error>() {
            println!("Stored error: {}", err);
        }
        ERROR_REGISTRY.clear();
    } else {
        println!("Operation succeeded with value: {}", result_value);
    }
}
```

This error module provides consistent error propagation and a memory-safe compatibility registry. It does not make `Result` branching constant-time.