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
61impl<const N: usize> Zeroize for [u8; N] {
62 fn zeroize(&mut self) {
63 self.as_mut_slice().zeroize();
64 }
65}
66
67impl<const N: usize> Zeroize for [u32; N] {
68 fn zeroize(&mut self) {
69 self.as_mut_slice().zeroize();
70 }
71}
72
73impl<const N: usize> Zeroize for [u64; N] {
74 fn zeroize(&mut self) {
75 self.as_mut_slice().zeroize();
76 }
77}
78
79#[derive(Debug, Clone, PartialEq, Eq)]
89pub struct Zeroizing<T: Zeroize>(T);
90
91impl<T: Zeroize> Zeroizing<T> {
92 pub const fn new(value: T) -> Self {
94 Self(value)
95 }
96
97 pub fn get(&self) -> &T {
99 &self.0
100 }
101
102 pub fn get_mut(&mut self) -> &mut T {
104 &mut self.0
105 }
106}
107
108impl<T: Zeroize> core::ops::Deref for Zeroizing<T> {
109 type Target = T;
110 fn deref(&self) -> &T {
111 &self.0
112 }
113}
114
115impl<T: Zeroize> core::ops::DerefMut for Zeroizing<T> {
116 fn deref_mut(&mut self) -> &mut T {
117 &mut self.0
118 }
119}
120
121impl<T: Zeroize> Drop for Zeroizing<T> {
122 fn drop(&mut self) {
123 self.0.zeroize();
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn slices_are_wiped() {
133 let mut buf = [1u8, 2, 3, 4];
134 buf.zeroize();
135 assert_eq!(buf, [0, 0, 0, 0]);
136 }
137
138 #[test]
139 fn zeroizing_derefs() {
140 let mut z = Zeroizing::new([7u8; 8]);
141 assert_eq!(z[0], 7);
142 z[0] = 9;
143 assert_eq!(z.get()[0], 9);
144 }
145
146 #[test]
147 fn eight_byte_chunks_and_the_tail_are_wiped_and_nothing_else() {
148 let mut buf = [0xa5u8; 32];
152 buf[5..24].zeroize();
153 assert_eq!(&buf[..5], &[0xa5; 5]);
154 assert_eq!(&buf[5..24], &[0u8; 19]);
155 assert_eq!(&buf[24..], &[0xa5; 8]);
156 for len in 0..=17 {
157 let mut v = [0xffu8; 17];
158 v[..len].zeroize();
159 assert!(v[..len].iter().all(|&b| b == 0), "length {len}");
160 assert!(v[len..].iter().all(|&b| b == 0xff), "length {len}");
161 }
162 }
163
164 #[test]
165 fn word_slices_are_wiped() {
166 let mut w = [0xDEAD_BEEFu32; 4];
167 w.zeroize();
168 assert_eq!(w, [0u32; 4]);
169 let mut q = [0xDEAD_BEEF_CAFE_F00Du64; 2];
170 q.zeroize();
171 assert_eq!(q, [0u64; 2]);
172 }
173}