1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//! Explicit memory erasure with volatile writes and opt-in scope guards.
//!
//! The crate has no dependencies. Its single `alloc` feature is off by default
//! and adds support for `Vec<T>` and `Box<T>`, including boxed slices.
//! [`Zeroize`] supports all primitive integers, `bool`, `char`, arrays, slices,
//! `Option<T>`, and [`core::mem::MaybeUninit<T>`]. [`Zeroizing`] clears a local
//! value when its guard is dropped.
//!
//! # Capability and policy
//!
//! [`Zeroize`] is a capability: a caller can explicitly erase a value. Storage
//! types do not know whether their contents are secret, so implementing this
//! trait should not by itself impose automatic erasure. For example, a big
//! integer used for public arithmetic need not be cleared on drop.
//!
//! [`ZeroizeOnDrop`] expresses a policy chosen by types that know they hold
//! secrets, such as private-key containers. The marker does not generate drop
//! behavior: implementors must provide their own `Drop` implementation and call
//! [`Zeroize::zeroize`]. Use [`Zeroizing`] to opt into this policy for a local value.
//!
//! # Usage
//!
//! ```
//! use tc_zeroize::{Zeroize, Zeroizing};
//!
//! let mut scratch = [1_u8, 2, 3, 4];
//! scratch.zeroize();
//! assert_eq!(scratch, [0; 4]);
//!
//! let mut optional = Some([7_u32, 9]);
//! optional.zeroize();
//! assert_eq!(optional, None);
//!
//! {
//! let mut secret = Zeroizing::new([42_u8; 32]);
//! secret[0] = 7;
//! assert_eq!(secret[0], 7);
//! } // The guard clears its current array before dropping it.
//! ```
//!
//! # Mechanism and limits
//!
//! Primitive implementations overwrite their current storage with volatile
//! writes, followed by a `SeqCst` compiler fence. Volatile stores prevent the
//! compiler from deleting the wipe; the final fence constrains compiler
//! reordering across the wipe. Neither operation flushes caches or supplies a
//! hardware memory barrier. Functional tests check results, not generated code.
//!
//! Arrays and slices visit every element and retain their length; slice lengths
//! are public. `Option<T>` clears a present value before dropping it and becoming
//! `None`. Composite implementations inherit the erasure behavior of their
//! elements. This is not a constant-time API: an option's presence and custom
//! implementations may affect control flow. Padding bytes are not covered.
//! `MaybeUninit<T>` receives a typed volatile zero store and remains logically
//! uninitialized; this does not promise to overwrite padding in `T`. Padding-free
//! storage such as bytes and integer limbs has no such gap.
//!
//! Erasure applies only to the storage reached through the current mutable
//! borrow. It cannot recover copies left elsewhere by the compiler or operating
//! system, including registers, stack spills, swap, and core dumps.
//!
//! A `Copy` value can be implicitly copied on by-value use. Clearing one binding
//! cannot clear other copies; this matters for a `Copy` fixed-width integer type.
//! Such types cannot implement `Drop` and therefore cannot clear themselves
//! automatically at scope exit. Even ordinary moves may leave old bytes behind.
//! A [`Zeroizing`] guard clears its current value, not copies made before or
//! during its lifetime. It cannot prevent copies through [`core::ops::Deref`].
//!
//! With `alloc`, `Vec<T>` clears its live elements before dropping them, then
//! clears the whole current allocation through its spare capacity. Its length
//! becomes zero and capacity is retained. The padding limitation above still
//! applies. `Box<T>` delegates to its contents without releasing the allocation.
//! Collection reallocations can leave data in inaccessible old buffers: erasure
//! cannot reach earlier allocations left by growth, `shrink_to_fit`, or
//! `into_boxed_slice`. Reserve sufficient capacity up front or use `Box<[T]>`
//! for fixed-size secret storage to avoid reallocations while holding secrets.
//! `String` is not supported.
//!
//! Drop-based erasure also requires that the destructor runs: forgetting a guard,
//! leaking it, or aborting the process bypasses its cleanup. If a custom `zeroize`
//! implementation panics, composite erasure can remain incomplete.
// no std
pub use ;
pub use Zeroizing;
// alloc
extern crate alloc;