use core::{convert::TryFrom, fmt::Debug};
use crate::{
reexport::rand_core::CryptoRngCore, CBytes, CryptoCoreError, FixedSizeCBytes,
RandomFixedSizeCBytes,
};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Nonce<const LENGTH: usize>(pub [u8; LENGTH]);
impl<const LENGTH: usize> CBytes for Nonce<LENGTH> {}
impl<const LENGTH: usize> FixedSizeCBytes<LENGTH> for Nonce<LENGTH> {
fn to_bytes(&self) -> [u8; LENGTH] {
self.0
}
fn try_from_bytes(bytes: [u8; LENGTH]) -> Result<Self, CryptoCoreError> {
Ok(Self(bytes))
}
}
impl<const LENGTH: usize> RandomFixedSizeCBytes<LENGTH> for Nonce<LENGTH> {
fn new<R: CryptoRngCore>(rng: &mut R) -> Self {
let mut bytes = [0; LENGTH];
rng.fill_bytes(&mut bytes);
Self(bytes)
}
fn as_bytes(&self) -> &[u8] {
self.0.as_ref()
}
}
impl<const LENGTH: usize> Nonce<LENGTH> {
#[must_use]
pub fn xor(&self, b2: &[u8]) -> Self {
let mut n = self.0;
for (ni, bi) in n.iter_mut().zip(b2) {
*ni ^= bi;
}
Self(n)
}
}
impl<'a, const LENGTH: usize> TryFrom<&'a [u8]> for Nonce<LENGTH> {
type Error = CryptoCoreError;
fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
Self::try_from_slice(bytes)
}
}
impl<const LENGTH: usize> From<[u8; LENGTH]> for Nonce<LENGTH> {
fn from(b: [u8; LENGTH]) -> Self {
Self(b)
}
}
#[cfg(test)]
mod tests {
use crate::{
reexport::rand_core::SeedableRng, symmetric_crypto::nonce::Nonce, CsRng,
RandomFixedSizeCBytes,
};
const NONCE_LENGTH: usize = 12;
#[test]
fn test_nonce() {
let mut cs_rng = CsRng::from_entropy();
let nonce_1 = Nonce::<NONCE_LENGTH>::new(&mut cs_rng);
assert_eq!(NONCE_LENGTH, nonce_1.as_bytes().len());
let nonce_2 = Nonce::<NONCE_LENGTH>::new(&mut cs_rng);
assert_eq!(NONCE_LENGTH, nonce_2.as_bytes().len());
assert_ne!(nonce_1, nonce_2);
}
}