1use core::sync::atomic::{compiler_fence, Ordering};
8
9pub trait Zeroize {
11 fn zeroize(&mut self);
13}
14
15impl Zeroize for [u8] {
16 fn zeroize(&mut self) {
17 for byte in self.iter_mut() {
18 unsafe { core::ptr::write_volatile(byte, 0) };
20 }
21 compiler_fence(Ordering::SeqCst);
22 }
23}
24
25impl Zeroize for [u32] {
26 fn zeroize(&mut self) {
27 for w in self.iter_mut() {
28 unsafe { core::ptr::write_volatile(w, 0) };
30 }
31 compiler_fence(Ordering::SeqCst);
32 }
33}
34
35impl Zeroize for [u64] {
36 fn zeroize(&mut self) {
37 for w in self.iter_mut() {
38 unsafe { core::ptr::write_volatile(w, 0) };
40 }
41 compiler_fence(Ordering::SeqCst);
42 }
43}
44
45impl<const N: usize> Zeroize for [u8; N] {
46 fn zeroize(&mut self) {
47 self.as_mut_slice().zeroize();
48 }
49}
50
51impl<const N: usize> Zeroize for [u32; N] {
52 fn zeroize(&mut self) {
53 self.as_mut_slice().zeroize();
54 }
55}
56
57impl<const N: usize> Zeroize for [u64; N] {
58 fn zeroize(&mut self) {
59 self.as_mut_slice().zeroize();
60 }
61}
62
63#[derive(Debug, Clone, PartialEq, Eq)]
73pub struct Zeroizing<T: Zeroize>(T);
74
75impl<T: Zeroize> Zeroizing<T> {
76 pub const fn new(value: T) -> Self {
78 Self(value)
79 }
80
81 pub fn get(&self) -> &T {
83 &self.0
84 }
85
86 pub fn get_mut(&mut self) -> &mut T {
88 &mut self.0
89 }
90}
91
92impl<T: Zeroize> core::ops::Deref for Zeroizing<T> {
93 type Target = T;
94 fn deref(&self) -> &T {
95 &self.0
96 }
97}
98
99impl<T: Zeroize> core::ops::DerefMut for Zeroizing<T> {
100 fn deref_mut(&mut self) -> &mut T {
101 &mut self.0
102 }
103}
104
105impl<T: Zeroize> Drop for Zeroizing<T> {
106 fn drop(&mut self) {
107 self.0.zeroize();
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn slices_are_wiped() {
117 let mut buf = [1u8, 2, 3, 4];
118 buf.zeroize();
119 assert_eq!(buf, [0, 0, 0, 0]);
120 }
121
122 #[test]
123 fn zeroizing_derefs() {
124 let mut z = Zeroizing::new([7u8; 8]);
125 assert_eq!(z[0], 7);
126 z[0] = 9;
127 assert_eq!(z.get()[0], 9);
128 }
129
130 #[test]
131 fn word_slices_are_wiped() {
132 let mut w = [0xDEAD_BEEFu32; 4];
133 w.zeroize();
134 assert_eq!(w, [0u32; 4]);
135 let mut q = [0xDEAD_BEEF_CAFE_F00Du64; 2];
136 q.zeroize();
137 assert_eq!(q, [0u64; 2]);
138 }
139}