#[cfg(feature = "std")]
use std::boxed::Box;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
extern crate alloc as rust_alloc;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use rust_alloc::boxed::Box;
pub trait SecureCompare: Sized {
fn secure_eq(&self, other: &Self) -> bool;
fn secure_cmp(&self, other: &Self) -> dcrypt_internal::constant_time::Choice;
}
impl<const N: usize> SecureCompare for [u8; N] {
fn secure_eq(&self, other: &Self) -> bool {
use dcrypt_internal::constant_time::ConstantTimeEq;
bool::from(self.ct_eq(other))
}
fn secure_cmp(&self, other: &Self) -> dcrypt_internal::constant_time::Choice {
use dcrypt_internal::constant_time::ConstantTimeEq;
self.ct_eq(other)
}
}
impl SecureCompare for &[u8] {
fn secure_eq(&self, other: &Self) -> bool {
use dcrypt_internal::constant_time::ConstantTimeEq;
bool::from(self.ct_eq(other))
}
fn secure_cmp(&self, other: &Self) -> dcrypt_internal::constant_time::Choice {
use dcrypt_internal::constant_time::ConstantTimeEq;
self.ct_eq(other)
}
}
pub mod barrier {
use core::sync::atomic::{compiler_fence, fence, Ordering};
#[inline(always)]
pub fn compiler_fence_seq_cst() {
compiler_fence(Ordering::SeqCst);
}
#[inline(always)]
pub fn memory_fence_seq_cst() {
fence(Ordering::SeqCst);
}
#[inline(always)]
pub fn with_barriers<T, F: FnOnce() -> T>(f: F) -> T {
compiler_fence_seq_cst();
let result = f();
compiler_fence_seq_cst();
result
}
}
#[cfg(feature = "alloc")]
pub mod alloc {
use super::*;
use dcrypt_internal::zeroing::Zeroize;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use super::rust_alloc::vec;
pub fn zeroizing_box<T: Default + Zeroize + Clone>(size: usize) -> Box<[T]> {
vec![T::default(); size].into_boxed_slice()
}
pub fn clear_box<T: Zeroize>(mut data: Box<[T]>) {
data.zeroize();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_secure_compare() {
let a = [1u8, 2, 3, 4];
let b = [1u8, 2, 3, 4];
let c = [1u8, 2, 3, 5];
assert!(a.secure_eq(&b));
assert!(!a.secure_eq(&c));
}
#[test]
fn test_memory_barriers() {
use barrier::*;
let result = with_barriers(|| {
let mut x = 42;
x += 1;
x
});
assert_eq!(result, 43);
}
#[test]
#[cfg(feature = "alloc")]
fn exact_size_sensitive_storage_helpers_round_trip() {
let mut data = alloc::zeroizing_box::<u8>(17);
assert_eq!(data.len(), 17);
data.fill(0x5a);
alloc::clear_box(data);
}
}