use crate::ct;
use crate::zeroize::Zeroize;
use core::fmt;
pub struct Secret<T: Zeroize> {
value: T,
}
impl<T: Zeroize> Secret<T> {
pub fn new(value: T) -> Self {
Secret { value }
}
pub fn expose_secret(&self) -> &T {
&self.value
}
pub fn expose_secret_mut(&mut self) -> &mut T {
&mut self.value
}
pub fn clone_secret(&self) -> Self
where
T: Clone,
{
Secret { value: self.value.clone() }
}
}
impl<T: Zeroize> Drop for Secret<T> {
fn drop(&mut self) {
self.value.zeroize();
}
}
impl<T: Zeroize> fmt::Debug for Secret<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Secret([REDACTED])")
}
}
impl<T: Zeroize> From<T> for Secret<T> {
fn from(value: T) -> Self {
Secret::new(value)
}
}
impl<const N: usize> PartialEq for Secret<[u8; N]> {
fn eq(&self, other: &Self) -> bool {
ct::eq(&self.value, &other.value)
}
}
impl<const N: usize> Eq for Secret<[u8; N]> {}
impl PartialEq for Secret<Vec<u8>> {
fn eq(&self, other: &Self) -> bool {
ct::eq(&self.value, &other.value)
}
}
impl Eq for Secret<Vec<u8>> {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn secret_behaviour() {
let mut s = Secret::new(vec![1u8, 2, 3]);
assert_eq!(s.expose_secret(), &vec![1, 2, 3]);
s.expose_secret_mut().push(4);
let copy = s.clone_secret();
assert!(copy == s);
assert!(Secret::new(vec![1u8]) != Secret::new(vec![2u8]));
assert!(Secret::new(vec![1u8]) != Secret::new(vec![1u8, 1]));
assert_eq!(format!("{:?}", s), "Secret([REDACTED])");
}
}