use aead::{
KeySizeUser, TagPosition,
array::{Array, typenum::Unsigned},
consts::{U1, U6, U8, U12, U16, U40, U64, U128},
inout::{InOut, InOutBuf},
};
use ascon_core::State;
use crate::{AbsorbingState, AeadCore, AeadInOut, Isap, Key, KeyInit, Nonce, Result, Tag};
#[derive(Debug, Default)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
pub(crate) struct AsconState {
state: State,
#[cfg_attr(feature = "zeroize", zeroize(skip))]
idx: usize,
}
impl AbsorbingState for AsconState {
const RATE: usize = 8;
type StateSize = U40;
fn absorb_byte<R: Unsigned>(&mut self, byte: u8) {
self.state[0] ^= (byte as u64) << ((7 - self.idx) * 8);
self.idx += 1;
if self.idx == Self::RATE {
self.permute_n::<R>();
}
}
fn absorb_bytes<R: Unsigned>(&mut self, mut bytes: &[u8]) {
while self.idx != 0 && !bytes.is_empty() {
self.absorb_byte::<R>(bytes[0]);
bytes = &bytes[1..];
}
let chunks = bytes.chunks_exact(Self::RATE);
let reminder = chunks.remainder();
for chunk in chunks {
self.state[0] ^= u64::from_be_bytes(chunk.try_into().unwrap());
self.permute_n::<R>();
}
if !reminder.is_empty() {
let mut tmp = [0u8; 8];
tmp[0..reminder.len()].copy_from_slice(reminder);
self.state[0] ^= u64::from_be_bytes(tmp);
self.idx = reminder.len();
}
}
fn permute_n<R: Unsigned>(&mut self) {
match R::USIZE {
12 => self.state.permute_12(),
8 => self.state.permute_8(),
6 => self.state.permute_6(),
1 => self.state.permute_1(),
_ => unreachable!(),
}
self.idx = 0;
}
fn permute_n_if<R: Unsigned>(&mut self) {
if self.idx != 0 {
self.permute_n::<R>();
}
}
fn seperate_domains(&mut self) {
self.state[4] ^= 0x1;
}
fn extract_bytes<const LEN: usize>(&self) -> [u8; LEN] {
debug_assert!(LEN % 8 == 0 && LEN <= 40);
let mut ret = [0u8; LEN];
for (idx, chunk) in ret.chunks_exact_mut(8).enumerate() {
chunk.copy_from_slice(&u64::to_be_bytes(self.state[idx]));
}
ret
}
fn overwrite_bytes<const LEN: usize, O: Unsigned>(&mut self, bytes: &[u8; LEN]) {
debug_assert!(LEN % 8 == 0);
debug_assert!(O::USIZE % 8 == 0);
debug_assert!(LEN + O::USIZE <= 40);
for (idx, chunk) in bytes.chunks_exact(8).enumerate() {
self.state[idx + O::USIZE / 8] = u64::from_be_bytes(chunk.try_into().unwrap());
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
pub struct IsapAscon128 {
k: [u8; 16],
}
impl Isap for IsapAscon128 {
type KeySizeBits = U128;
type RateBits = U64;
type RateBytes = U8;
type RateSessionKeyBits = U1;
type RoundsKey = U12;
type RoundsBit = U12;
type RoundsEncryption = U12;
type RoundsMAC = U12;
type State = AsconState;
fn isap_enc_process_block(
state: &Self::State,
mut buffer: InOut<'_, '_, Array<u8, Self::RateBytes>>,
) {
let t = u64::from_ne_bytes(state.extract_bytes())
^ u64::from_ne_bytes(buffer.get_in()[..8].try_into().unwrap());
buffer.get_out()[..8].copy_from_slice(&u64::to_ne_bytes(t));
}
fn isap_enc_process_bytes(state: Self::State, mut buffer: InOutBuf<'_, '_, u8>) {
let mut tmp = [0u8; 8];
let buf_len = buffer.len();
tmp[0..buf_len].copy_from_slice(buffer.get_in());
buffer.get_out().copy_from_slice(
&u64::to_ne_bytes(u64::from_ne_bytes(state.extract_bytes()) ^ u64::from_ne_bytes(tmp))
[0..buf_len],
);
}
}
impl AeadCore for IsapAscon128 {
type NonceSize = U16;
type TagSize = U16;
const TAG_POSITION: TagPosition = TagPosition::Postfix;
}
impl KeySizeUser for IsapAscon128 {
type KeySize = U16;
}
impl KeyInit for IsapAscon128 {
fn new(key: &Key<Self>) -> Self {
Self { k: (*key).into() }
}
}
impl AeadInOut for IsapAscon128 {
fn encrypt_inout_detached(
&self,
nonce: &Nonce<Self>,
associated_data: &[u8],
buffer: InOutBuf<'_, '_, u8>,
) -> Result<Tag<Self>> {
Self::encrypt_impl(&self.k, nonce, associated_data, buffer).map(Into::into)
}
fn decrypt_inout_detached(
&self,
nonce: &Nonce<Self>,
associated_data: &[u8],
buffer: InOutBuf<'_, '_, u8>,
tag: &Tag<Self>,
) -> Result<()> {
Self::decrypt_impl(&self.k, nonce, associated_data, buffer, tag)
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
pub struct IsapAscon128A {
k: [u8; 16],
}
impl Isap for IsapAscon128A {
type KeySizeBits = U128;
type RateBits = U64;
type RateBytes = U8;
type RateSessionKeyBits = U1;
type RoundsKey = U12;
type RoundsBit = U1;
type RoundsEncryption = U6;
type RoundsMAC = U12;
type State = AsconState;
fn isap_enc_process_block(
state: &Self::State,
mut buffer: InOut<'_, '_, Array<u8, Self::RateBytes>>,
) {
let t = u64::from_ne_bytes(state.extract_bytes())
^ u64::from_ne_bytes(buffer.get_in()[..8].try_into().unwrap());
buffer.get_out()[..8].copy_from_slice(&u64::to_ne_bytes(t));
}
fn isap_enc_process_bytes(state: Self::State, mut buffer: InOutBuf<'_, '_, u8>) {
let mut tmp = [0u8; 8];
let buf_len = buffer.len();
tmp[0..buf_len].copy_from_slice(buffer.get_in());
buffer.get_out().copy_from_slice(
&u64::to_ne_bytes(u64::from_ne_bytes(state.extract_bytes()) ^ u64::from_ne_bytes(tmp))
[0..buf_len],
);
}
}
impl AeadCore for IsapAscon128A {
type NonceSize = U16;
type TagSize = U16;
const TAG_POSITION: TagPosition = TagPosition::Postfix;
}
impl KeySizeUser for IsapAscon128A {
type KeySize = U16;
}
impl KeyInit for IsapAscon128A {
fn new(key: &Key<Self>) -> Self {
Self { k: (*key).into() }
}
}
impl AeadInOut for IsapAscon128A {
fn encrypt_inout_detached(
&self,
nonce: &Nonce<Self>,
associated_data: &[u8],
buffer: InOutBuf<'_, '_, u8>,
) -> Result<Tag<Self>> {
Self::encrypt_impl(&self.k, nonce, associated_data, buffer).map(Into::into)
}
fn decrypt_inout_detached(
&self,
nonce: &Nonce<Self>,
associated_data: &[u8],
buffer: InOutBuf<'_, '_, u8>,
tag: &Tag<Self>,
) -> Result<()> {
Self::decrypt_impl(&self.k, nonce, associated_data, buffer, tag)
}
}