use alloc::string::String;
use alloc::vec::Vec;
use core::sync::atomic::{Ordering, compiler_fence};
use super::traits::{FastZeroizable, ZeroizationProbe, ZeroizeMetadata};
#[inline(always)]
pub fn to_fast_zeroizable_dyn_mut<'a, T: FastZeroizable>(
x: &'a mut T,
) -> &'a mut (dyn FastZeroizable + 'a) {
x
}
#[inline(always)]
pub fn to_zeroization_probe_dyn_ref<'a, T: ZeroizationProbe>(
x: &'a T,
) -> &'a (dyn ZeroizationProbe + 'a) {
x
}
pub fn zeroize_collection(collection_iter: &mut dyn Iterator<Item = &mut dyn FastZeroizable>) {
for z in collection_iter {
z.fast_zeroize();
compiler_fence(Ordering::SeqCst);
}
}
pub fn collection_zeroed(collection_iter: &mut dyn Iterator<Item = &dyn ZeroizationProbe>) -> bool {
for z in collection_iter {
if !z.is_zeroized() {
return false;
}
}
true
}
#[inline(always)]
pub(crate) fn slice_fast_zeroize<T: FastZeroizable + ZeroizeMetadata>(slice: &mut [T], fast: bool) {
if fast {
redoubt_util::fast_zeroize_slice(slice);
compiler_fence(Ordering::SeqCst);
} else {
for elem in slice.iter_mut() {
elem.fast_zeroize();
compiler_fence(Ordering::SeqCst);
}
}
}
impl<T> ZeroizeMetadata for [T]
where
T: FastZeroizable + ZeroizeMetadata,
{
const CAN_BE_BULK_ZEROIZED: bool = T::CAN_BE_BULK_ZEROIZED;
}
impl<T> FastZeroizable for [T]
where
T: FastZeroizable + ZeroizeMetadata,
{
fn fast_zeroize(&mut self) {
slice_fast_zeroize(self, T::CAN_BE_BULK_ZEROIZED);
}
}
impl<T> ZeroizationProbe for [T]
where
T: ZeroizeMetadata + FastZeroizable + ZeroizationProbe,
{
fn is_zeroized(&self) -> bool {
collection_zeroed(&mut self.iter().map(to_zeroization_probe_dyn_ref))
}
}
impl<T: ZeroizeMetadata, const N: usize> ZeroizeMetadata for [T; N] {
const CAN_BE_BULK_ZEROIZED: bool = T::CAN_BE_BULK_ZEROIZED;
}
impl<T: ZeroizeMetadata + FastZeroizable, const N: usize> FastZeroizable for [T; N] {
#[inline(always)]
fn fast_zeroize(&mut self) {
slice_fast_zeroize(self, T::CAN_BE_BULK_ZEROIZED);
}
}
impl<T, const N: usize> ZeroizationProbe for [T; N]
where
T: ZeroizationProbe,
{
fn is_zeroized(&self) -> bool {
collection_zeroed(&mut self.iter().map(to_zeroization_probe_dyn_ref))
}
}
#[inline(always)]
pub(crate) fn vec_fast_zeroize<T: FastZeroizable + ZeroizeMetadata>(vec: &mut Vec<T>, fast: bool) {
if fast {
redoubt_util::fast_zeroize_vec(vec);
compiler_fence(Ordering::SeqCst);
} else {
for elem in vec.iter_mut() {
elem.fast_zeroize();
compiler_fence(Ordering::SeqCst);
}
redoubt_util::zeroize_spare_capacity(vec);
compiler_fence(Ordering::SeqCst);
}
}
impl<T: ZeroizeMetadata> ZeroizeMetadata for Vec<T> {
const CAN_BE_BULK_ZEROIZED: bool = false;
}
impl<T: ZeroizeMetadata + FastZeroizable> FastZeroizable for Vec<T> {
#[inline(always)]
fn fast_zeroize(&mut self) {
vec_fast_zeroize(self, T::CAN_BE_BULK_ZEROIZED);
}
}
impl<T> ZeroizationProbe for Vec<T>
where
T: ZeroizationProbe,
{
fn is_zeroized(&self) -> bool {
collection_zeroed(&mut self.iter().map(to_zeroization_probe_dyn_ref))
&& redoubt_util::is_spare_capacity_zeroized(self)
}
}
impl ZeroizeMetadata for String {
const CAN_BE_BULK_ZEROIZED: bool = false;
}
impl FastZeroizable for String {
#[inline(always)]
fn fast_zeroize(&mut self) {
unsafe {
let vec_bytes = self.as_mut_vec();
redoubt_util::fast_zeroize_vec(vec_bytes);
}
}
}
impl ZeroizationProbe for String {
fn is_zeroized(&self) -> bool {
redoubt_util::is_slice_zeroized(self.as_bytes())
}
}
impl<T: ZeroizeMetadata + FastZeroizable> ZeroizeMetadata for alloc::boxed::Box<T> {
const CAN_BE_BULK_ZEROIZED: bool = T::CAN_BE_BULK_ZEROIZED;
}
impl<T: FastZeroizable> FastZeroizable for alloc::boxed::Box<T> {
#[inline(always)]
fn fast_zeroize(&mut self) {
(**self).fast_zeroize();
}
}
impl<T: ZeroizationProbe> ZeroizationProbe for alloc::boxed::Box<T> {
fn is_zeroized(&self) -> bool {
(**self).is_zeroized()
}
}
impl<T: ZeroizeMetadata + FastZeroizable> ZeroizeMetadata for Option<T> {
const CAN_BE_BULK_ZEROIZED: bool = false;
}
impl<T: FastZeroizable> FastZeroizable for Option<T> {
#[inline(always)]
fn fast_zeroize(&mut self) {
if let Some(val) = self {
val.fast_zeroize();
}
*self = None;
}
}
impl<T: ZeroizationProbe> ZeroizationProbe for Option<T> {
fn is_zeroized(&self) -> bool {
match self {
Some(val) => val.is_zeroized(),
None => true, }
}
}