use core::fmt;
use core::ops::{Deref, DerefMut};
use rand::{CryptoRng, RngCore};
use subtle::ConstantTimeEq;
use zeroize::Zeroize;
use crate::error::{validate, Result};
use crate::types::sealed::Sealed;
use crate::types::{
ByteSerializable, ConstantTimeEq as LocalConstantEq, FixedSize, RandomGeneration,
SecureZeroingType,
};
#[derive(Clone, Zeroize)]
pub struct Nonce<const N: usize> {
data: [u8; N],
}
impl<const N: usize> Sealed for Nonce<N> {}
impl<const N: usize> Nonce<N> {
pub fn new(data: [u8; N]) -> Self {
Self { data }
}
pub fn zeroed() -> Self {
Self { data: [0u8; N] }
}
pub fn from_slice(slice: &[u8]) -> Result<Self> {
validate::length("Nonce", slice.len(), N)?;
let mut data = [0u8; N];
data.copy_from_slice(slice);
Ok(Self { data })
}
pub fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let mut data = [0u8; N];
rng.fill_bytes(&mut data);
Self { data }
}
pub fn size() -> usize {
N
}
}
impl<const N: usize> AsRef<[u8]> for Nonce<N> {
fn as_ref(&self) -> &[u8] {
&self.data
}
}
impl<const N: usize> AsMut<[u8]> for Nonce<N> {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.data
}
}
impl<const N: usize> Deref for Nonce<N> {
type Target = [u8; N];
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<const N: usize> DerefMut for Nonce<N> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<const N: usize> PartialEq for Nonce<N> {
fn eq(&self, other: &Self) -> bool {
self.data.ct_eq(&other.data).into()
}
}
impl<const N: usize> Eq for Nonce<N> {}
impl<const N: usize> fmt::Debug for Nonce<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Nonce<{}>({:?})", N, &self.data[..])
}
}
impl<const N: usize> LocalConstantEq for Nonce<N> {
fn ct_eq(&self, other: &Self) -> bool {
self.data.ct_eq(&other.data).into()
}
}
impl<const N: usize> RandomGeneration for Nonce<N> {
fn random<R: RngCore + CryptoRng>(rng: &mut R) -> crate::error::Result<Self> {
Ok(Self::random(rng))
}
}
impl<const N: usize> SecureZeroingType for Nonce<N> {
fn zeroed() -> Self {
Self::zeroed()
}
}
impl<const N: usize> FixedSize for Nonce<N> {
fn size() -> usize {
N
}
}
impl<const N: usize> ByteSerializable for Nonce<N> {
fn to_bytes(&self) -> Vec<u8> {
self.data.to_vec()
}
fn from_bytes(bytes: &[u8]) -> crate::error::Result<Self> {
Self::from_slice(bytes)
}
}
pub trait ChaCha20Compatible: Sealed {}
impl ChaCha20Compatible for Nonce<12> {}
pub trait XChaCha20Compatible: Sealed {}
impl XChaCha20Compatible for Nonce<24> {}
pub trait AesGcmCompatible: Sealed {}
impl AesGcmCompatible for Nonce<12> {}
impl AesGcmCompatible for Nonce<15> {} impl AesGcmCompatible for Nonce<16> {}
pub trait AesCtrCompatible: Sealed {}
impl<const N: usize> AesCtrCompatible for Nonce<N> {}