redoubt_zero_core/
traits.rs

1// Copyright (c) 2025-2026 Federico Hoerth <memparanoid@gmail.com>
2// SPDX-License-Identifier: GPL-3.0-only
3// See LICENSE in the repository root for full license text.
4
5//! Core traits for systematic zeroization.
6
7use super::zeroize_on_drop_sentinel::ZeroizeOnDropSentinel;
8
9/// Trait for verifying that a value has been zeroized.
10///
11/// This trait allows runtime checks to verify that zeroization actually happened.
12/// Used in tests and assertions to ensure no sensitive data remains in memory.
13///
14/// # Example
15///
16/// ```rust
17/// use redoubt_zero_core::{ZeroizationProbe, FastZeroizable};
18///
19/// let mut value: u32 = 42;
20///
21/// assert!(!value.is_zeroized());
22///
23/// value.fast_zeroize();
24/// assert!(value.is_zeroized());
25/// assert_eq!(value, 0);
26/// ```
27pub trait ZeroizationProbe {
28    /// Returns `true` if the value is zeroized (all bytes are 0).
29    ///
30    /// This method should perform a runtime check to verify that the value
31    /// has been properly zeroized.
32    fn is_zeroized(&self) -> bool;
33}
34
35/// Trait for types that verify zeroization happened before drop.
36///
37/// Types implementing this trait contain a [`ZeroizeOnDropSentinel`] and provide
38/// methods to verify that `.zeroize()` was called before the value is dropped.
39///
40/// This trait is typically derived using `#[derive(RedoubtZero)]` from the `RedoubtZero` crate.
41pub trait AssertZeroizeOnDrop {
42    /// Clones the internal [`ZeroizeOnDropSentinel`] for verification.
43    ///
44    /// This is used by [`assert_zeroize_on_drop`](AssertZeroizeOnDrop::assert_zeroize_on_drop)
45    /// to verify zeroization after the value is dropped.
46    fn clone_sentinel(&self) -> ZeroizeOnDropSentinel;
47
48    /// Asserts that zeroization happens when this value is dropped.
49    ///
50    /// # Panics
51    ///
52    /// Panics if `.zeroize()` was not called before drop.
53    ///
54    /// This is typically used in tests to verify drop behavior for types
55    /// that implement this trait.
56    fn assert_zeroize_on_drop(self);
57}
58
59/// Trait for mutable guards that auto-zeroize on drop.
60///
61/// Types implementing this trait wrap a mutable reference `&mut T` and
62/// provide controlled access while ensuring zeroization on drop.
63///
64/// # Example
65///
66/// ```rust,ignore
67/// use redoubt_zero_core::{MutGuarded, ZeroizingMutGuard};
68///
69/// fn process_guarded<'a, T: MutGuarded<'a, SomeType>>(guard: &mut T) {
70///     let value = guard.expose_mut();
71///     // ... use value
72/// } // guard zeroizes on drop
73/// ```
74pub trait MutGuarded<'a, T>: FastZeroize + ZeroizationProbe + AssertZeroizeOnDrop
75where
76    T: FastZeroize + ZeroizationProbe,
77{
78    /// Exposes an immutable reference to the guarded value.
79    fn expose(&self) -> &T;
80
81    /// Exposes a mutable reference to the guarded value.
82    fn expose_mut(&mut self) -> &mut T;
83}
84
85/// Metadata about zeroization strategy for a type.
86///
87/// This trait provides compile-time information about whether a type can be
88/// bulk-zeroized with memset or requires element-by-element zeroization.
89///
90/// **Note:** This trait is NOT dyn-compatible (has associated constants).
91/// Use [`FastZeroizable`] for trait objects.
92pub trait ZeroizeMetadata {
93    /// Whether this type can be bulk-zeroized with memset.
94    ///
95    /// - `true`: All-zeros is a valid bit pattern (primitives)
96    /// - `false`: Requires element-by-element recursive zeroization (complex types)
97    const CAN_BE_BULK_ZEROIZED: bool;
98}
99
100/// Trait for types that can be zeroized at runtime.
101///
102/// This trait is dyn-compatible, allowing it to be used in trait objects
103/// like `&mut dyn FastZeroizable`.
104///
105/// Use this trait when you need dynamic dispatch for zeroization operations.
106pub trait FastZeroizable {
107    /// Zeroizes the value in place.
108    ///
109    /// After calling this method, all sensitive data should be overwritten with zeros.
110    fn fast_zeroize(&mut self);
111}
112
113/// Combined trait for types with both zeroization metadata and runtime zeroization.
114///
115/// This is the main trait users should implement. It combines:
116/// - [`ZeroizeMetadata`]: Compile-time optimization hints
117/// - [`FastZeroizable`]: Runtime zeroization method (dyn-compatible)
118///
119/// # Usage
120///
121/// Most types should use `#[derive(RedoubtZero)]` which implements this automatically.
122/// Manual implementation is only needed for custom types with special zeroization requirements.
123///
124/// # `CAN_BE_BULK_ZEROIZED` Constant
125///
126/// ## `CAN_BE_BULK_ZEROIZED = true` (Fast Path)
127///
128/// All-zeros is a valid bit pattern. Enables:
129/// - Fast vectorized memset operations (`ptr::write_bytes`)
130/// - ~20x performance improvement over byte-by-byte writes
131/// - Safe for: primitives (u8-u128, i8-i128, bool, char, floats)
132///
133/// ## `CAN_BE_BULK_ZEROIZED = false` (Slow Path)
134///
135/// Requires element-by-element zeroization because:
136/// - Type contains pointers, references, or heap allocations
137/// - All-zeros may not be a valid representation
138/// - Needs recursive calls on each field
139///
140/// # Example
141///
142/// ```rust,ignore
143/// use redoubt_zero_core::FastZeroize;
144///
145/// // Primitive: bulk zeroization
146/// impl FastZeroize for u32 {
147///     const CAN_BE_BULK_ZEROIZED: bool = true;
148///
149///     fn fast_zeroize(&mut self) {
150///         redoubt_util::zeroize_primitive(self);
151///     }
152/// }
153///
154/// // Complex type: element-by-element
155/// struct ApiKey {
156///     secret: Vec<u8>,
157/// }
158///
159/// impl FastZeroize for ApiKey {
160///     const CAN_BE_BULK_ZEROIZED: bool = false;
161///
162///     fn fast_zeroize(&mut self) {
163///         self.secret.fast_zeroize();
164///     }
165/// }
166/// ```
167pub trait FastZeroize: ZeroizeMetadata + FastZeroizable {}
168
169// Blanket impl: any type implementing both sub-traits automatically gets FastZeroize
170impl<T: ZeroizeMetadata + FastZeroizable> FastZeroize for T {}
171
172/// Trait for static zeroization of global CipherBox instances.
173///
174/// Used by `#[cipherbox(..., global = true)]` to expose `fast_zeroize()` on
175/// the generated module. Requires trait import for consistency with
176/// [`FastZeroizable`].
177///
178/// # Example
179///
180/// ```rust,ignore
181/// use redoubt::codec::RedoubtCodec;
182/// use redoubt::vault::cipherbox;
183/// use redoubt::zero::{RedoubtZero, StaticFastZeroizable};
184///
185/// #[cipherbox(SensitiveDataBox, global = true)]
186/// #[derive(Default, RedoubtCodec, RedoubtZero)]
187/// struct SensitiveData {
188///     // ...
189/// }
190///
191/// SENSITIVE_DATA_BOX::fast_zeroize();
192/// ```
193pub trait StaticFastZeroizable {
194    /// Zeroizes the global instance.
195    fn fast_zeroize();
196}