use aes::{Aes128, Aes256};
use cipher::KeyInit;
use eme2::Eme2 as BaseEme2;
use eme2::extended::Eme2 as ExtEme2;
fn fill(buf: &mut [u8], seed: u64) {
let mut s = seed.wrapping_mul(6_364_136_223_846_793_005).wrapping_add(1);
for b in buf.iter_mut() {
s = s
.wrapping_mul(6_364_136_223_846_793_005)
.wrapping_add(1_442_695_040_888_963_407);
*b = (s >> 33) as u8;
}
}
#[test]
fn extended_matches_base_for_aes256() {
let key = [0x42u8; 64];
let base = <BaseEme2<Aes256> as KeyInit>::new(&key.into());
let ext = <ExtEme2<Aes256> as KeyInit>::new(&key.into());
let mut lens: Vec<usize> = (16..=200).collect();
lens.extend([2030, 2048, 2049, 2064]);
let ad_lens = [0usize, 1, 15, 16, 17, 31, 32, 33];
for &len in &lens {
for &al in &ad_lens {
let mut pt = vec![0u8; len];
fill(&mut pt, (len * 131 + al) as u64);
let mut ad = vec![0u8; al];
fill(&mut ad, (al * 7919 + len) as u64);
let mut buf_base = pt.clone();
base.encrypt_with_ad(&ad, &mut buf_base).unwrap();
let mut buf_ext = pt.clone();
ext.encrypt_with_ad(&ad, &mut buf_ext).unwrap();
assert_eq!(
buf_base, buf_ext,
"extended::Eme2 diverged from base Eme2: len={len}, ad_len={al}"
);
ext.decrypt_with_ad(&ad, &mut buf_ext).unwrap();
assert_eq!(
buf_ext, pt,
"extended::Eme2 roundtrip failed: len={len}, ad_len={al}"
);
}
}
}
#[test]
fn extended_matches_base_for_aes128() {
let key = [0x24u8; 48];
let base = <BaseEme2<Aes128> as KeyInit>::new(&key.into());
let ext = <ExtEme2<Aes128> as KeyInit>::new(&key.into());
for len in [16, 17, 32, 48, 63, 128] {
let mut pt = vec![0u8; len];
fill(&mut pt, len as u64);
let mut buf_base = pt.clone();
base.encrypt(&mut buf_base).unwrap();
let mut buf_ext = pt.clone();
ext.encrypt(&mut buf_ext).unwrap();
assert_eq!(buf_base, buf_ext, "mismatch at len={len}");
}
}
#[test]
fn extended_default_tweak_matches_empty_ad() {
let key = [0x11u8; 64];
let cipher = <ExtEme2<Aes256> as KeyInit>::new(&key.into());
let pt = vec![0xCDu8; 48];
let mut via_default = pt.clone();
cipher.encrypt(&mut via_default).unwrap();
let mut via_empty_ad = pt;
cipher.encrypt_with_ad(&[], &mut via_empty_ad).unwrap();
assert_eq!(via_default, via_empty_ad);
}
#[cfg(test)]
mod threefish {
use super::fill;
use cipher::KeyInit;
use eme2::extended::Eme2;
use threefish::{Threefish256, Threefish512, Threefish1024};
fn roundtrip<C>(cipher: &Eme2<C>, len: usize, ad: &[u8], seed: u64)
where
C: cipher::BlockCipherEncrypt
+ cipher::BlockCipherDecrypt
+ cipher::BlockSizeUser
+ cipher::KeySizeUser,
C::BlockSize: eme2::extended::EmePoly + core::ops::Add<C::BlockSize>,
cipher::typenum::Sum<C::BlockSize, C::BlockSize>: hybrid_array::ArraySize,
{
let mut pt = vec![0u8; len];
fill(&mut pt, seed);
let mut buf = pt.clone();
cipher
.encrypt_with_ad(ad, &mut buf)
.expect("encryption succeeded");
assert_ne!(
buf, pt,
"ciphertext should differ from plaintext (len={len})"
);
cipher
.decrypt_with_ad(ad, &mut buf)
.expect("decryption succeeded");
assert_eq!(buf, pt, "roundtrip failed (len={len})");
}
#[test]
fn threefish256_roundtrip() {
let key = [0x33u8; 96]; let cipher = <Eme2<Threefish256> as KeyInit>::new(&key.into());
for len in [32, 33, 64, 96, 100] {
roundtrip(&cipher, len, b"associated data", len as u64);
}
}
#[test]
fn threefish512_roundtrip() {
let key = [0x55u8; 192]; let cipher = <Eme2<Threefish512> as KeyInit>::new(&key.into());
for len in [64, 65, 128, 200] {
roundtrip(&cipher, len, b"", len as u64);
}
}
#[test]
fn threefish1024_roundtrip() {
let key = [0x77u8; 384]; let cipher = <Eme2<Threefish1024> as KeyInit>::new(&key.into());
for len in [128, 129, 256, 400] {
roundtrip(&cipher, len, b"tweak-like AD", len as u64);
}
}
}