Skip to main content

zeroize/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc(
4    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
5    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
6)]
7#![warn(missing_docs, rust_2018_idioms, unused_qualifications)]
8
9//! Securely zero memory with a simple trait ([`Zeroize`]) built on stable Rust
10//! primitives which guarantee the operation will not be "optimized away".
11//!
12//! ## About
13//!
14//! [Zeroing memory securely is hard] - compilers optimize for performance, and
15//! in doing so they love to "optimize away" unnecessary zeroing calls. There are
16//! many documented "tricks" to attempt to avoid these optimizations and ensure
17//! that a zeroing routine is performed reliably.
18//!
19//! This crate isn't about tricks: it uses [`core::ptr::write_volatile`]
20//! and [`core::sync::atomic`] memory fences to provide easy-to-use, portable
21//! zeroing behavior which works on all of Rust's core number types and slices
22//! thereof, implemented in pure Rust with no usage of FFI or assembly.
23//!
24//! - No insecure fallbacks!
25//! - No dependencies!
26//! - No FFI or inline assembly! **WASM friendly** (and tested)!
27//! - `#![no_std]` i.e. **embedded-friendly**!
28//! - No functionality besides securely zeroing memory!
29//! - (Optional) Custom derive support for zeroing complex structures
30//!
31//! ## Minimum Supported Rust Version
32//!
33//! Requires Rust **1.72** or newer.
34//!
35//! In the future, we reserve the right to change MSRV (i.e. MSRV is out-of-scope
36//! for this crate's SemVer guarantees), however when we do it will be accompanied
37//! by a minor version bump.
38//!
39//! ## Usage
40//!
41//! ```
42//! use zeroize::Zeroize;
43//!
44//! // Protip: don't embed secrets in your source code.
45//! // This is just an example.
46//! let mut secret = b"Air shield password: 1,2,3,4,5".to_vec();
47//! // [ ... ] open the air shield here
48//!
49//! // Now that we're done using the secret, zero it out.
50//! secret.zeroize();
51//! ```
52//!
53//! The [`Zeroize`] trait is impl'd on all of Rust's core scalar types including
54//! integers, floats, `bool`, and `char`.
55//!
56//! Additionally, it's implemented on slices and `IterMut`s of the above types.
57//!
58//! When the `alloc` feature is enabled (which it is by default), it's also
59//! impl'd for `Vec<T>` for the above types as well as `String`, where it provides
60//! [`Vec::clear`] / [`String::clear`]-like behavior (truncating to zero-length)
61//! but ensures the backing memory is securely zeroed with some caveats.
62//!
63//! With the `std` feature enabled (which it is **not** by default), [`Zeroize`]
64//! is also implemented for [`CString`]. After calling `zeroize()` on a `CString`,
65//! its internal buffer will contain exactly one nul byte. The backing
66//! memory is zeroed by converting it to a `Vec<u8>` and back into a `CString`.
67//! (NOTE: see "Stack/Heap Zeroing Notes" for important `Vec`/`String`/`CString` details)
68//!
69//! [`CString`]: https://doc.rust-lang.org/std/ffi/struct.CString.html
70//!
71//! The [`DefaultIsZeroes`] marker trait can be impl'd on types which also
72//! impl [`Default`], which implements [`Zeroize`] by overwriting a value with
73//! the default value.
74//!
75//! ## Custom Derive Support
76//!
77//! This crate has custom derive support for the `Zeroize` trait,
78//! gated under the `zeroize` crate's `zeroize_derive` Cargo feature,
79//! which automatically calls `zeroize()` on all members of a struct
80//! or tuple struct.
81//!
82//! Attributes supported for `Zeroize`:
83//!
84//! On the item level:
85//! - `#[zeroize(drop)]`: *deprecated* use `ZeroizeOnDrop` instead
86//! - `#[zeroize(bound = "T: MyTrait")]`: this replaces any trait bounds
87//!   inferred by zeroize
88//!
89//! On the field level:
90//! - `#[zeroize(skip)]`: skips this field or variant when calling `zeroize()`
91//!
92//! Attributes supported for `ZeroizeOnDrop`:
93//!
94//! On the field level:
95//! - `#[zeroize(skip)]`: skips this field or variant when calling `zeroize()`
96//!
97//! Example which derives `Drop`:
98//!
99//! ```
100//! # #[cfg(feature = "zeroize_derive")]
101//! # {
102//! use zeroize::{Zeroize, ZeroizeOnDrop};
103//!
104//! // This struct will be zeroized on drop
105//! #[derive(Zeroize, ZeroizeOnDrop)]
106//! struct MyStruct([u8; 32]);
107//! # }
108//! ```
109//!
110//! Example which does not derive `Drop` (useful for e.g. `Copy` types)
111//!
112//! ```
113//! #[cfg(feature = "zeroize_derive")]
114//! # {
115//! use zeroize::Zeroize;
116//!
117//! // This struct will *NOT* be zeroized on drop
118//! #[derive(Copy, Clone, Zeroize)]
119//! struct MyStruct([u8; 32]);
120//! # }
121//! ```
122//!
123//! Example which only derives `Drop`:
124//!
125//! ```
126//! # #[cfg(feature = "zeroize_derive")]
127//! # {
128//! use zeroize::ZeroizeOnDrop;
129//!
130//! // This struct will be zeroized on drop
131//! #[derive(ZeroizeOnDrop)]
132//! struct MyStruct([u8; 32]);
133//! # }
134//! ```
135//!
136//! ## `Zeroizing<Z>`: wrapper for zeroizing arbitrary values on drop
137//!
138//! `Zeroizing<Z: Zeroize>` is a generic wrapper type that impls `Deref`
139//! and `DerefMut`, allowing access to an inner value of type `Z`, and also
140//! impls a `Drop` handler which calls `zeroize()` on its contents:
141//!
142//! ```
143//! use zeroize::Zeroizing;
144//!
145//! fn use_secret() {
146//!     let mut secret = Zeroizing::new([0u8; 5]);
147//!
148//!     // Set the air shield password
149//!     // Protip (again): don't embed secrets in your source code.
150//!     secret.copy_from_slice(&[1, 2, 3, 4, 5]);
151//!     assert_eq!(secret.as_ref(), &[1, 2, 3, 4, 5]);
152//!
153//!     // The contents of `secret` will be automatically zeroized on drop
154//! }
155//!
156//! # use_secret()
157//! ```
158//!
159//! ## What guarantees does this crate provide?
160//!
161//! This crate guarantees the following:
162//!
163//! 1. The zeroing operation can't be "optimized away" by the compiler.
164//! 2. All subsequent reads to memory will see "zeroized" values.
165//!
166//! LLVM's volatile semantics ensure #1 is true.
167//!
168//! Additionally, thanks to work by the [Unsafe Code Guidelines Working Group],
169//! we can now fairly confidently say #2 is true as well. Previously there were
170//! worries that the approach used by this crate (mixing volatile and
171//! non-volatile accesses) was undefined behavior due to language contained
172//! in the documentation for `write_volatile`, however after some discussion
173//! [these remarks have been removed] and the specific usage pattern in this
174//! crate is considered to be well-defined.
175//!
176//! Additionally this crate leverages [`core::sync::atomic::compiler_fence`]
177//! with the strictest ordering
178//! ([`Ordering::SeqCst`]) as a
179//! precaution to help ensure reads are not reordered before memory has been
180//! zeroed.
181//!
182//! All of that said, there is still potential for microarchitectural attacks
183//! (ala Spectre/Meltdown) to leak "zeroized" secrets through covert channels.
184//! This crate makes no guarantees that zeroized values cannot be leaked
185//! through such channels, as they represent flaws in the underlying hardware.
186//!
187//! ## Stack/Heap Zeroing Notes
188//!
189//! This crate can be used to zero values from either the stack or the heap.
190//!
191//! However, be aware several operations in Rust can unintentionally leave
192//! copies of data in memory. This includes but is not limited to:
193//!
194//! - Moves and [`Copy`]
195//! - Heap reallocation when using [`Vec`] and [`String`]
196//! - Borrowers of a reference making copies of the data
197//!
198//! [`Pin`][`core::pin::Pin`] can be leveraged in conjunction with this crate
199//! to ensure data kept on the stack isn't moved.
200//!
201//! The `Zeroize` impls for `Vec`, `String` and `CString` zeroize the entire
202//! capacity of their backing buffer, but cannot guarantee copies of the data
203//! were not previously made by buffer reallocation. It's therefore important
204//! when attempting to zeroize such buffers to initialize them to the correct
205//! capacity, and take care to prevent subsequent reallocation.
206//!
207//! The `secrecy` crate provides higher-level abstractions for eliminating
208//! usage patterns which can cause reallocations:
209//!
210//! <https://crates.io/crates/secrecy>
211//!
212//! ## What about: clearing registers, mlock, mprotect, etc?
213//!
214//! This crate is focused on providing simple, unobtrusive support for reliably
215//! zeroing memory using the best approach possible on stable Rust.
216//!
217//! Clearing registers is a difficult problem that can't easily be solved by
218//! something like a crate, and requires either inline ASM or rustc support.
219//! See <https://github.com/rust-lang/rust/issues/17046> for background on
220//! this particular problem.
221//!
222//! Other memory protection mechanisms are interesting and useful, but often
223//! overkill (e.g. defending against RAM scraping or attackers with swap access).
224//! In as much as there may be merit to these approaches, there are also many
225//! other crates that already implement more sophisticated memory protections.
226//! Such protections are explicitly out-of-scope for this crate.
227//!
228//! Zeroing memory is [good cryptographic hygiene] and this crate seeks to promote
229//! it in the most unobtrusive manner possible. This includes omitting complex
230//! `unsafe` memory protection systems and just trying to make the best memory
231//! zeroing crate available.
232//!
233//! [Zeroing memory securely is hard]: http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html
234//! [Unsafe Code Guidelines Working Group]: https://github.com/rust-lang/unsafe-code-guidelines
235//! [these remarks have been removed]: https://github.com/rust-lang/rust/pull/60972
236//! [good cryptographic hygiene]: https://github.com/veorq/cryptocoding#clean-memory-of-secret-data
237//! [`Ordering::SeqCst`]: core::sync::atomic::Ordering::SeqCst
238
239#[cfg(feature = "alloc")]
240extern crate alloc;
241
242#[cfg(feature = "std")]
243extern crate std;
244
245#[cfg(feature = "zeroize_derive")]
246pub use zeroize_derive::{Zeroize, ZeroizeOnDrop};
247
248#[cfg(target_arch = "aarch64")]
249mod aarch64;
250#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
251mod x86;
252
253mod barrier;
254pub use barrier::optimization_barrier;
255
256mod stack;
257pub use stack::zeroize_stack;
258
259use core::{
260    marker::{PhantomData, PhantomPinned},
261    mem::MaybeUninit,
262    num::{
263        self, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, NonZeroU8,
264        NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
265    },
266    ops,
267    slice::IterMut,
268};
269
270#[cfg(feature = "alloc")]
271use alloc::{boxed::Box, string::String, vec::Vec};
272
273#[cfg(feature = "std")]
274use std::ffi::CString;
275
276/// Trait for securely erasing values from memory.
277pub trait Zeroize {
278    /// Zero out this object from memory using Rust intrinsics which ensure the
279    /// zeroization operation is not "optimized away" by the compiler.
280    fn zeroize(&mut self);
281}
282
283/// Marker trait signifying that this type will [`Zeroize::zeroize`] itself on [`Drop`].
284pub trait ZeroizeOnDrop {}
285
286/// Marker trait for types whose [`Default`] is the desired zeroization result
287pub trait DefaultIsZeroes: Copy + Default + Sized {}
288
289/// Fallible trait for representing cases where zeroization may or may not be
290/// possible.
291///
292/// This is primarily useful for scenarios like reference counted data, where
293/// zeroization is only possible when the last reference is dropped.
294pub trait TryZeroize {
295    /// Try to zero out this object from memory using Rust intrinsics which
296    /// ensure the zeroization operation is not "optimized away" by the
297    /// compiler.
298    #[must_use]
299    fn try_zeroize(&mut self) -> bool;
300}
301
302impl<Z> Zeroize for Z
303where
304    Z: DefaultIsZeroes,
305{
306    fn zeroize(&mut self) {}
307}
308
309macro_rules! impl_zeroize_with_default {
310    ($($type:ty),+) => {
311        $(impl DefaultIsZeroes for $type {})+
312    };
313}
314
315#[rustfmt::skip]
316impl_zeroize_with_default! {
317    PhantomPinned, (), bool, char,
318    f32, f64,
319    i8, i16, i32, i64, i128, isize,
320    u8, u16, u32, u64, u128, usize
321}
322
323/// `PhantomPinned` is zero sized so provide a ZeroizeOnDrop implementation.
324impl ZeroizeOnDrop for PhantomPinned {}
325
326/// `()` is zero sized so provide a ZeroizeOnDrop implementation.
327impl ZeroizeOnDrop for () {}
328
329macro_rules! impl_zeroize_for_non_zero {
330    ($($type:ty),+) => {
331        $(
332            impl Zeroize for $type {
333                fn zeroize(&mut self) {}
334            }
335        )+
336    };
337}
338
339impl_zeroize_for_non_zero!(
340    NonZeroI8,
341    NonZeroI16,
342    NonZeroI32,
343    NonZeroI64,
344    NonZeroI128,
345    NonZeroIsize,
346    NonZeroU8,
347    NonZeroU16,
348    NonZeroU32,
349    NonZeroU64,
350    NonZeroU128,
351    NonZeroUsize
352);
353
354impl<Z> Zeroize for num::Wrapping<Z>
355where
356    Z: Zeroize,
357{
358    fn zeroize(&mut self) {}
359}
360
361/// Impl [`Zeroize`] on arrays of types that impl [`Zeroize`].
362impl<Z, const N: usize> Zeroize for [Z; N]
363where
364    Z: Zeroize,
365{
366    fn zeroize(&mut self) {}
367}
368
369/// Impl [`ZeroizeOnDrop`] on arrays of types that impl [`ZeroizeOnDrop`].
370impl<Z, const N: usize> ZeroizeOnDrop for [Z; N] where Z: ZeroizeOnDrop {}
371
372impl<Z> Zeroize for IterMut<'_, Z>
373where
374    Z: Zeroize,
375{
376    fn zeroize(&mut self) {}
377}
378
379impl<Z> Zeroize for Option<Z>
380where
381    Z: Zeroize,
382{
383    fn zeroize(&mut self) {}
384}
385
386impl<Z> ZeroizeOnDrop for Option<Z> where Z: ZeroizeOnDrop {}
387
388/// Impl [`Zeroize`] on [`MaybeUninit`] types.
389///
390/// This fills the memory with zeroes.
391/// Note that this ignore invariants that `Z` might have, because
392/// [`MaybeUninit`] removes all invariants.
393impl<Z> Zeroize for MaybeUninit<Z> {
394    fn zeroize(&mut self) {}
395}
396
397/// Impl [`Zeroize`] on slices of [`MaybeUninit`] types.
398///
399/// This impl can eventually be optimized using an memset intrinsic,
400/// such as [`core::intrinsics::volatile_set_memory`].
401///
402/// This fills the slice with zeroes.
403///
404/// Note that this ignore invariants that `Z` might have, because
405/// [`MaybeUninit`] removes all invariants.
406impl<Z> Zeroize for [MaybeUninit<Z>] {
407    fn zeroize(&mut self) {}
408}
409
410/// Impl [`Zeroize`] on slices of types that can be zeroized with [`Default`].
411///
412/// This impl can eventually be optimized using an memset intrinsic,
413/// such as [`core::intrinsics::volatile_set_memory`]. For that reason the
414/// blanket impl on slices is bounded by [`DefaultIsZeroes`].
415///
416/// To zeroize a mut slice of `Z: Zeroize` which does not impl
417/// [`DefaultIsZeroes`], call `iter_mut().zeroize()`.
418impl<Z> Zeroize for [Z]
419where
420    Z: DefaultIsZeroes,
421{
422    fn zeroize(&mut self) {}
423}
424
425impl Zeroize for str {
426    fn zeroize(&mut self) {}
427}
428
429/// [`PhantomData`] is always zero sized so provide a [`Zeroize`] implementation.
430impl<Z> Zeroize for PhantomData<Z> {
431    fn zeroize(&mut self) {}
432}
433
434/// [`PhantomData` is always zero sized so provide a ZeroizeOnDrop implementation.
435impl<Z> ZeroizeOnDrop for PhantomData<Z> {}
436
437macro_rules! impl_zeroize_tuple {
438    ( $( $type_name:ident ),+ ) => {
439        impl<$($type_name: Zeroize),+> Zeroize for ($($type_name,)+) {
440            fn zeroize(&mut self) {}
441        }
442
443        impl<$($type_name: ZeroizeOnDrop),+> ZeroizeOnDrop for ($($type_name,)+) { }
444    }
445}
446
447// Generic implementations for tuples up to 10 parameters.
448impl_zeroize_tuple!(A);
449impl_zeroize_tuple!(A, B);
450impl_zeroize_tuple!(A, B, C);
451impl_zeroize_tuple!(A, B, C, D);
452impl_zeroize_tuple!(A, B, C, D, E);
453impl_zeroize_tuple!(A, B, C, D, E, F);
454impl_zeroize_tuple!(A, B, C, D, E, F, G);
455impl_zeroize_tuple!(A, B, C, D, E, F, G, H);
456impl_zeroize_tuple!(A, B, C, D, E, F, G, H, I);
457impl_zeroize_tuple!(A, B, C, D, E, F, G, H, I, J);
458
459#[cfg(feature = "alloc")]
460impl<Z> Zeroize for Vec<Z>
461where
462    Z: Zeroize,
463{
464    /// "Best effort" zeroization for `Vec`.
465    ///
466    /// Ensures the entire capacity of the `Vec` is zeroed. Cannot ensure that
467    /// previous reallocations did not leave values on the heap.
468    fn zeroize(&mut self) {}
469}
470
471#[cfg(feature = "alloc")]
472impl<Z> ZeroizeOnDrop for Vec<Z> where Z: ZeroizeOnDrop {}
473
474#[cfg(feature = "alloc")]
475impl<Z> Zeroize for Box<[Z]>
476where
477    Z: Zeroize,
478{
479    /// Unlike `Vec`, `Box<[Z]>` cannot reallocate, so we can be sure that we are not leaving
480    /// values on the heap.
481    fn zeroize(&mut self) {}
482}
483
484#[cfg(feature = "alloc")]
485impl<Z> ZeroizeOnDrop for Box<[Z]> where Z: ZeroizeOnDrop {}
486
487#[cfg(feature = "alloc")]
488impl Zeroize for Box<str> {
489    fn zeroize(&mut self) {}
490}
491
492#[cfg(feature = "alloc")]
493impl Zeroize for String {
494    fn zeroize(&mut self) {}
495}
496
497#[cfg(feature = "std")]
498impl Zeroize for CString {
499    fn zeroize(&mut self) {}
500}
501
502/// `Zeroizing` is a wrapper for any `Z: Zeroize` type which implements a
503/// `Drop` handler which zeroizes dropped values.
504///
505/// `Zeroizing<T>` is defined with `repr(transparent)`, which means it is
506/// guaranteed to have the same physical representation as the underlying type.
507#[derive(Debug, Default, Eq, PartialEq)]
508#[repr(transparent)]
509pub struct Zeroizing<Z: Zeroize + ?Sized>(Z);
510
511impl<Z> Zeroizing<Z>
512where
513    Z: Zeroize,
514{
515    /// Move value inside a `Zeroizing` wrapper which ensures it will be
516    /// zeroized when it's dropped.
517    #[inline(always)]
518    pub fn new(value: Z) -> Self {
519        Self(value)
520    }
521}
522
523impl<Z: Zeroize + Clone> Clone for Zeroizing<Z> {
524    #[inline(always)]
525    fn clone(&self) -> Self {
526        Self(self.0.clone())
527    }
528
529    #[inline(always)]
530    fn clone_from(&mut self, source: &Self) {
531        self.0.zeroize();
532        self.0.clone_from(&source.0);
533    }
534}
535
536impl<Z> From<Z> for Zeroizing<Z>
537where
538    Z: Zeroize,
539{
540    #[inline(always)]
541    fn from(value: Z) -> Zeroizing<Z> {
542        Zeroizing(value)
543    }
544}
545
546impl<Z> ops::Deref for Zeroizing<Z>
547where
548    Z: Zeroize + ?Sized,
549{
550    type Target = Z;
551
552    #[inline(always)]
553    fn deref(&self) -> &Z {
554        &self.0
555    }
556}
557
558impl<Z> ops::DerefMut for Zeroizing<Z>
559where
560    Z: Zeroize + ?Sized,
561{
562    #[inline(always)]
563    fn deref_mut(&mut self) -> &mut Z {
564        &mut self.0
565    }
566}
567
568impl<T, Z> AsRef<T> for Zeroizing<Z>
569where
570    T: ?Sized,
571    Z: AsRef<T> + Zeroize + ?Sized,
572{
573    #[inline(always)]
574    fn as_ref(&self) -> &T {
575        self.0.as_ref()
576    }
577}
578
579impl<T, Z> AsMut<T> for Zeroizing<Z>
580where
581    T: ?Sized,
582    Z: AsMut<T> + Zeroize + ?Sized,
583{
584    #[inline(always)]
585    fn as_mut(&mut self) -> &mut T {
586        self.0.as_mut()
587    }
588}
589
590impl<Z> Zeroize for Zeroizing<Z>
591where
592    Z: Zeroize + ?Sized,
593{
594    fn zeroize(&mut self) {}
595}
596
597impl<Z> ZeroizeOnDrop for Zeroizing<Z> where Z: Zeroize + ?Sized {}
598
599impl<Z> Drop for Zeroizing<Z>
600where
601    Z: Zeroize + ?Sized,
602{
603    fn drop(&mut self) {
604        self.0.zeroize();
605    }
606}
607
608#[cfg(feature = "serde")]
609impl<Z> serde::Serialize for Zeroizing<Z>
610where
611    Z: Zeroize + serde::Serialize + ?Sized,
612{
613    #[inline(always)]
614    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
615    where
616        S: serde::Serializer,
617    {
618        self.0.serialize(serializer)
619    }
620}
621
622#[cfg(feature = "serde")]
623impl<'de, Z> serde::Deserialize<'de> for Zeroizing<Z>
624where
625    Z: Zeroize + serde::Deserialize<'de>,
626{
627    #[inline(always)]
628    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
629    where
630        D: serde::Deserializer<'de>,
631    {
632        Ok(Self(Z::deserialize(deserializer)?))
633    }
634}
635
636/// Zeroizes a flat type/struct. Only zeroizes the values that it owns, and it does not work on
637/// dynamically sized values or trait objects. It would be inefficient to use this function on a
638/// type that already implements `ZeroizeOnDrop`.
639///
640/// # Safety
641/// - The type must not contain references to outside data or dynamically sized data, such as
642///   `Vec<T>` or `String`.
643/// - Values stored in the type must not have `Drop` impls.
644/// - This function can invalidate the type if it is used after this function is called on it.
645///   It is advisable to call this function only in `impl Drop`.
646/// - The bit pattern of all zeroes must be valid for the data being zeroized. This may not be
647///   true for enums and pointers.
648#[inline(always)]
649pub unsafe fn zeroize_flat_type<F: Sized>(_data: *mut F) {}
650
651/// Internal module used as support for `AssertZeroizeOnDrop`.
652#[doc(hidden)]
653pub mod __internal {
654    use super::*;
655
656    /// Auto-deref workaround for deriving `ZeroizeOnDrop`.
657    pub trait AssertZeroizeOnDrop {
658        fn zeroize_or_on_drop(self);
659    }
660
661    impl<T: ZeroizeOnDrop + ?Sized> AssertZeroizeOnDrop for &&mut T {
662        fn zeroize_or_on_drop(self) {}
663    }
664
665    /// Auto-deref workaround for deriving `ZeroizeOnDrop`.
666    pub trait AssertZeroize {
667        fn zeroize_or_on_drop(&mut self);
668    }
669
670    impl<T: Zeroize + ?Sized> AssertZeroize for T {
671        fn zeroize_or_on_drop(&mut self) {
672            self.zeroize();
673        }
674    }
675}