#![no_std]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
use core::ops::Sub;
pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, Nonce, Result, Tag};
use aead::{
array::{Array, ArraySize, typenum::Unsigned},
consts::{U0, U16},
inout::{InOut, InOutBuf},
};
use subtle::ConstantTimeEq;
#[cfg(feature = "ascon")]
mod ascon_impl;
#[cfg(feature = "keccak")]
mod keccak_impl;
#[cfg(feature = "ascon")]
pub use ascon_impl::{IsapAscon128, IsapAscon128A};
#[cfg(feature = "keccak")]
pub use keccak_impl::{IsapKeccak128, IsapKeccak128A};
trait U16Subtractable: Sub<U16> {
type Output: Unsigned;
}
impl<T> U16Subtractable for T
where
T: Unsigned + Sub<U16>,
<T as Sub<U16>>::Output: Unsigned,
{
type Output = <T as Sub<U16>>::Output;
}
trait AbsorbingState: Default {
const RATE: usize;
type StateSize: Unsigned + U16Subtractable;
fn absorb_byte<R: Unsigned>(&mut self, byte: u8);
fn absorb_bytes<R: Unsigned>(&mut self, bytes: &[u8]);
fn absorb_bytes_pad_permute<R: Unsigned>(&mut self, data: &[u8]) {
self.absorb_bytes::<R>(data);
self.absorb_byte::<R>(0x80);
self.permute_n_if::<R>();
}
fn permute_n<R: Unsigned>(&mut self);
fn permute_n_if<R: Unsigned>(&mut self);
fn seperate_domains(&mut self);
fn extract_bytes<const LEN: usize>(&self) -> [u8; LEN];
fn overwrite_bytes<const LEN: usize, O: Unsigned>(&mut self, bytes: &[u8; LEN]);
}
trait Isap {
type State: AbsorbingState;
type KeySizeBits: Unsigned; type RateBits: Unsigned;
type RateBytes: ArraySize;
type RateSessionKeyBits: Unsigned; type RoundsKey: Unsigned;
type RoundsBit: Unsigned;
type RoundsEncryption: Unsigned;
type RoundsMAC: Unsigned;
const ISAP_IV_A: [u8; 8] = [
0x01,
Self::KeySizeBits::U8,
Self::RateBits::U8,
Self::RateSessionKeyBits::U8,
Self::RoundsMAC::U8,
Self::RoundsBit::U8,
Self::RoundsEncryption::U8,
Self::RoundsKey::U8,
];
const ISAP_IV_KA: [u8; 8] = [
0x02,
Self::KeySizeBits::U8,
Self::RateBits::U8,
Self::RateSessionKeyBits::U8,
Self::RoundsMAC::U8,
Self::RoundsBit::U8,
Self::RoundsEncryption::U8,
Self::RoundsKey::U8,
];
const ISAP_IV_KE: [u8; 8] = [
0x03,
Self::KeySizeBits::U8,
Self::RateBits::U8,
Self::RateSessionKeyBits::U8,
Self::RoundsMAC::U8,
Self::RoundsBit::U8,
Self::RoundsEncryption::U8,
Self::RoundsKey::U8,
];
fn isap_enc_process_block(
state: &Self::State,
buffer: InOut<'_, '_, Array<u8, Self::RateBytes>>,
);
fn isap_enc_process_bytes(state: Self::State, buffer: InOutBuf<'_, '_, u8>);
fn isap_enc(key: &[u8; 16], nonce: &[u8; 16], buffer: InOutBuf<'_, '_, u8>) {
let mut state =
isap_rk::<Self::State, Self::RoundsKey, Self::RoundsBit>(key, Self::ISAP_IV_KE, nonce);
state.overwrite_bytes::<16, <<Self::State as AbsorbingState>::StateSize as U16Subtractable>::Output>(nonce);
let (chunks, remainder) = buffer.into_chunks::<Self::RateBytes>();
for chunk in chunks {
state.permute_n::<Self::RoundsEncryption>();
Self::isap_enc_process_block(&state, chunk);
}
if !remainder.is_empty() {
state.permute_n::<Self::RoundsEncryption>();
Self::isap_enc_process_bytes(state, remainder);
}
}
fn isap_mac(
k: &[u8; 16],
nonce: &[u8; 16],
associated_data: &[u8],
ciphertext: &[u8],
) -> [u8; 16] {
let mut state = Self::State::default();
state.overwrite_bytes::<16, U0>(nonce);
state.overwrite_bytes::<8, U16>(&Self::ISAP_IV_A);
state.permute_n::<Self::RoundsMAC>();
state.absorb_bytes_pad_permute::<Self::RoundsMAC>(associated_data);
state.seperate_domains();
state.absorb_bytes_pad_permute::<Self::RoundsMAC>(ciphertext);
let y: [u8; 16] = state.extract_bytes();
let state2 =
isap_rk::<Self::State, Self::RoundsKey, Self::RoundsBit>(k, Self::ISAP_IV_KA, &y);
state.overwrite_bytes::<16, U0>(&state2.extract_bytes());
state.permute_n::<Self::RoundsMAC>();
state.extract_bytes()
}
fn encrypt_impl(
key: &[u8; 16],
nonce: &Array<u8, U16>,
associated_data: &[u8],
mut buffer: InOutBuf<'_, '_, u8>,
) -> Result<[u8; 16]> {
if !buffer.is_empty() {
Self::isap_enc(key, nonce.as_ref(), buffer.reborrow());
}
Ok(Self::isap_mac(
key,
nonce.as_ref(),
associated_data,
buffer.into_out(),
))
}
fn decrypt_impl(
key: &[u8; 16],
nonce: &Array<u8, U16>,
associated_data: &[u8],
buffer: InOutBuf<'_, '_, u8>,
tag: &[u8],
) -> Result<()> {
if bool::from(
Self::isap_mac(key, nonce.as_ref(), associated_data, buffer.get_in()).ct_eq(tag),
) {
if !buffer.is_empty() {
Self::isap_enc(key, nonce.as_ref(), buffer);
}
Ok(())
} else {
Err(Error)
}
}
}
fn isap_rk<State: AbsorbingState, RoundsKey: Unsigned, RoundsBit: Unsigned>(
k: &[u8; 16],
iv: [u8; 8],
input: &[u8],
) -> State {
let mut state = State::default();
state.overwrite_bytes::<16, U0>(k);
state.overwrite_bytes::<8, U16>(&iv);
state.permute_n::<RoundsKey>();
for byte in &input[..input.len() - 1] {
for bit_index in 0..8 {
state.absorb_byte::<RoundsBit>((byte << bit_index) & 0x80);
state.permute_n::<RoundsBit>();
}
}
let byte = input[input.len() - 1];
for bit_index in 0..7 {
state.absorb_byte::<RoundsBit>((byte << bit_index) & 0x80);
state.permute_n::<RoundsBit>();
}
state.absorb_byte::<RoundsKey>((byte << 7) & 0x80);
state.permute_n::<RoundsKey>();
state
}