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) {
27 let mut chunks = self.chunks_exact_mut(8);
28 for chunk in &mut chunks {
29 unsafe { core::ptr::write_volatile(chunk.as_mut_ptr() as *mut [u8; 8], [0u8; 8]) };
32 }
33 for byte in chunks.into_remainder() {
34 unsafe { core::ptr::write_volatile(byte, 0) };
36 }
37 compiler_fence(Ordering::SeqCst);
38 }
39}
40
41impl Zeroize for [u32] {
42 fn zeroize(&mut self) {
43 for w in self.iter_mut() {
44 unsafe { core::ptr::write_volatile(w, 0) };
46 }
47 compiler_fence(Ordering::SeqCst);
48 }
49}
50
51impl Zeroize for [u64] {
52 fn zeroize(&mut self) {
53 for w in self.iter_mut() {
54 unsafe { core::ptr::write_volatile(w, 0) };
56 }
57 compiler_fence(Ordering::SeqCst);
58 }
59}
60
61#[cfg(feature = "std")]
62impl Zeroize for std::vec::Vec<u8> {
63 fn zeroize(&mut self) {
66 self.as_mut_slice().zeroize();
67 }
68}
69
70impl<const N: usize> Zeroize for [u8; N] {
71 fn zeroize(&mut self) {
72 self.as_mut_slice().zeroize();
73 }
74}
75
76impl<const N: usize> Zeroize for [u32; N] {
77 fn zeroize(&mut self) {
78 self.as_mut_slice().zeroize();
79 }
80}
81
82impl<const N: usize> Zeroize for [u64; N] {
83 fn zeroize(&mut self) {
84 self.as_mut_slice().zeroize();
85 }
86}
87
88#[derive(Debug, Clone, PartialEq, Eq)]
98pub struct Zeroizing<T: Zeroize>(T);
99
100impl<T: Zeroize> Zeroizing<T> {
101 pub const fn new(value: T) -> Self {
103 Self(value)
104 }
105
106 pub fn get(&self) -> &T {
108 &self.0
109 }
110
111 pub fn get_mut(&mut self) -> &mut T {
113 &mut self.0
114 }
115}
116
117impl<T: Zeroize> core::ops::Deref for Zeroizing<T> {
118 type Target = T;
119 fn deref(&self) -> &T {
120 &self.0
121 }
122}
123
124impl<T: Zeroize> core::ops::DerefMut for Zeroizing<T> {
125 fn deref_mut(&mut self) -> &mut T {
126 &mut self.0
127 }
128}
129
130impl<T: Zeroize> Drop for Zeroizing<T> {
131 fn drop(&mut self) {
132 self.0.zeroize();
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn slices_are_wiped() {
142 let mut buf = [1u8, 2, 3, 4];
143 buf.zeroize();
144 assert_eq!(buf, [0, 0, 0, 0]);
145 }
146
147 #[test]
148 fn zeroizing_derefs() {
149 let mut z = Zeroizing::new([7u8; 8]);
150 assert_eq!(z[0], 7);
151 z[0] = 9;
152 assert_eq!(z.get()[0], 9);
153 }
154
155 #[test]
156 fn eight_byte_chunks_and_the_tail_are_wiped_and_nothing_else() {
157 let mut buf = [0xa5u8; 32];
161 buf[5..24].zeroize();
162 assert_eq!(&buf[..5], &[0xa5; 5]);
163 assert_eq!(&buf[5..24], &[0u8; 19]);
164 assert_eq!(&buf[24..], &[0xa5; 8]);
165 for len in 0..=17 {
166 let mut v = [0xffu8; 17];
167 v[..len].zeroize();
168 assert!(v[..len].iter().all(|&b| b == 0), "length {len}");
169 assert!(v[len..].iter().all(|&b| b == 0xff), "length {len}");
170 }
171 }
172
173 #[test]
174 fn word_slices_are_wiped() {
175 let mut w = [0xDEAD_BEEFu32; 4];
176 w.zeroize();
177 assert_eq!(w, [0u32; 4]);
178 let mut q = [0xDEAD_BEEF_CAFE_F00Du64; 2];
179 q.zeroize();
180 assert_eq!(q, [0u64; 2]);
181 }
182}