mod reference;
use aes::Aes256;
use cipher::KeyInit;
use eme2::Eme2;
fn hex(s: &str) -> Vec<u8> {
assert!(s.len().is_multiple_of(2));
(0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("valid hex"))
.collect()
}
type Vector = (&'static str, &'static str, &'static str, &'static str);
const KAT_VECTORS: &[Vector] = &[
(
"11c67b30e59a4f04b96e23d88d42f7ac6116cb8035ea9f5409be7328dd9247fcb1661bd0853aefa4590ec3782de2974c01b66b20d58a3ff4a95e13c87d32e79c",
"",
"01203f5e7d9cbbdaf91837567594b3d2",
"e7f53b919115f47159f9b1f91b32b39f",
),
(
"11c67b30e59a4f04b96e23d88d42f7ac6116cb8035ea9f5409be7328dd9247fcb1661bd0853aefa4590ec3782de2974c01b66b20d58a3ff4a95e13c87d32e79c",
"",
"0221405f7e9dbcdbfa1938577695b4d3f211304f6e8daccbea0928476685a4c3e201203f5e7d9cbbdaf91837567594b3d2f1102f4e6d8cabcae90827466584a3",
"1b97a3ad7ba143409f6a33a62df712cd460221286168ed9eb50644c861d93d77541002d266d5a96aef0201a7f91282900262c4da7716e5d115be291737241590",
),
(
"11c67b30e59a4f04b96e23d88d42f7ac6116cb8035ea9f5409be7328dd9247fcb1661bd0853aefa4590ec3782de2974c01b66b20d58a3ff4a95e13c87d32e79c",
"",
"032241607f9ebddcfb1a39587796b5d4f31231506f8eadcceb0a29486786a5c4e3",
"624db62cd4815ec00d34e2669f01861412194271051777920516c93ad93edd0797",
),
(
"11c67b30e59a4f04b96e23d88d42f7ac6116cb8035ea9f5409be7328dd9247fcb1661bd0853aefa4590ec3782de2974c01b66b20d58a3ff4a95e13c87d32e79c",
"68656c6c6f",
"0524436281a0bfdefd1c3b5a7998b7d6f51433527190afceed0c2b4a6988a7c6e504234261809fbeddfc1b3a597897b6",
"ef73f5d262949233b1037f5c5df648d3e7dd64102c2ef64e69eda627a574cdb48473784704b86f13204ca5aee8b21f60",
),
(
"11c67b30e59a4f04b96e23d88d42f7ac6116cb8035ea9f5409be7328dd9247fcb1661bd0853aefa4590ec3782de2974c01b66b20d58a3ff4a95e13c87d32e79c",
"0928476685a4c3e201203f5e7d9cbbda",
"0625446382a1c0dffe1d3c5b7a99b8d7f61534537291b0cfee0d2c4b6a89a8c7e60524436281a0bfdefd1c3b5a7998b7",
"28d9ab33a1ab7bf1234da4f673b8a48cb6b446bb95c84ce634f6b23e4ab672f47055efb3234a52c456554b5a248e9bf2",
),
(
"11c67b30e59a4f04b96e23d88d42f7ac6116cb8035ea9f5409be7328dd9247fcb1661bd0853aefa4590ec3782de2974c01b66b20d58a3ff4a95e13c87d32e79c",
"0827466584a3c2e1001f3e5d7c9bbad9f81736557493b2d1f00f2e4d6c8baac9e807264564",
"0726456483a2c1e0ff1e3d5c7b9ab9d8f71635547392b1d0ef0e2d4c6b8aa9c8e70625446382a1c0dffe1d3c5b7a99b8d7f61534537291b0cfee0d2c4b6a89a8c7e60524436281a0bfdefd1c3b5a7998",
"3925ed4e340c662503f2f4679329daef3575397484f6b667a8f3215d675cbec93604dddbd903e1fff99f680b8cc855ef35f038b7c52114b3bd65ae5e9be45769f0212699af46a014160e629205d15f60",
),
];
#[test]
fn known_answer_vectors() {
for (i, (key, ad, pt, expected)) in KAT_VECTORS.iter().enumerate() {
let key_bytes = hex(key);
let ad_bytes = hex(ad);
let pt_bytes = hex(pt);
let expected_bytes = hex(expected);
let key_arr: cipher::Key<Eme2<Aes256>> = key_bytes.as_slice().try_into().unwrap();
let cipher = <Eme2<Aes256> as KeyInit>::new(&key_arr);
let mut buf = pt_bytes.clone();
cipher
.encrypt_with_ad(&ad_bytes, &mut buf)
.unwrap_or_else(|e| panic!("vector {i}: encryption failed: {e}"));
assert_eq!(buf, expected_bytes, "vector {i}: ciphertext mismatch");
cipher
.decrypt_with_ad(&ad_bytes, &mut buf)
.unwrap_or_else(|e| panic!("vector {i}: decryption failed: {e}"));
assert_eq!(buf, pt_bytes, "vector {i}: roundtrip mismatch");
}
}
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 cross_check_against_reference_transcription() {
let mut key = [0u8; 64];
fill(&mut key, 0x00C0_FFEE);
let mut key1 = [0u8; 32];
key1.copy_from_slice(&key[..32]);
let mut key2 = [0u8; 16];
key2.copy_from_slice(&key[32..48]);
let mut key3 = [0u8; 16];
key3.copy_from_slice(&key[48..64]);
let raw = reference::raw_cipher(&key1);
let mut lens: Vec<usize> = (16..=200).collect();
lens.extend([
2030, 2046, 2047, 2048, 2049, 2050, 2064, 2065, 4094, 4096, 4098,
]);
let ad_lens = [0usize, 1, 15, 16, 17, 31, 32, 33, 64, 100];
let crate_cipher = <Eme2<Aes256> as KeyInit>::new(&key.into());
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 expected = reference::eme2_encrypt(&raw, &key2, &key3, &ad, &pt);
let mut got = pt.clone();
crate_cipher.encrypt_with_ad(&ad, &mut got).unwrap();
assert_eq!(
got, expected,
"encrypt mismatch vs reference: len={len}, ad_len={al}"
);
let mut got_pt = expected.clone();
crate_cipher.decrypt_with_ad(&ad, &mut got_pt).unwrap();
assert_eq!(
got_pt, pt,
"decrypt mismatch vs reference: len={len}, ad_len={al}"
);
let ref_back = reference::eme2_decrypt(&raw, &key2, &key3, &ad, &expected);
assert_eq!(
ref_back, pt,
"reference self-roundtrip failed: len={len}, ad_len={al}"
);
}
}
}
#[test]
fn default_tweak_matches_empty_associated_data() {
let key = [0x42u8; 64];
let cipher = <Eme2<Aes256> as KeyInit>::new(&key.into());
let pt = vec![0xABu8; 64];
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);
assert_eq!(*cipher.t_star(), cipher.hash_ad(&[]));
}