#![allow(unsafe_op_in_unsafe_fn)]
use core::{arch::aarch64::*, mem, slice};
pub(super) type RoundKeys<const RK: usize> = [uint8x16_t; RK];
const BLOCK_WORDS: usize = 4;
const WORD_SIZE: usize = 4;
const ROUND_CONSTS: [u32; 10] = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
#[inline]
#[target_feature(enable = "aes")]
pub unsafe fn expand_key<const N: usize, const RK: usize>(key: &[u8; N]) -> [uint8x16_t; RK] {
const { assert!(matches!((N, RK), (16, 11) | (24, 13) | (32, 15))) }
let mut expanded_keys: [uint8x16_t; RK] = mem::zeroed();
const _: () = assert!(mem::align_of::<uint8x16_t>() >= mem::align_of::<u32>());
let keys_ptr: *mut u32 = expanded_keys.as_mut_ptr().cast();
let columns = slice::from_raw_parts_mut(keys_ptr, RK * BLOCK_WORDS);
for (i, chunk) in key.chunks_exact(WORD_SIZE).enumerate() {
columns[i] = u32::from_ne_bytes(chunk.try_into().unwrap());
}
let nk = N / WORD_SIZE;
for i in nk..(RK * BLOCK_WORDS) {
let mut word = columns[i - 1];
if i % nk == 0 {
word = sub_word(word).rotate_right(8) ^ ROUND_CONSTS[i / nk - 1];
} else if nk > 6 && i % nk == 4 {
word = sub_word(word);
}
columns[i] = columns[i - nk] ^ word;
}
expanded_keys
}
#[inline]
#[target_feature(enable = "aes")]
pub(super) unsafe fn inv_expanded_keys<const RK: usize>(
keys: &[uint8x16_t; RK],
) -> [uint8x16_t; RK] {
const { assert!(matches!(RK, 11 | 13 | 15)) }
let mut inv_keys: [uint8x16_t; RK] = core::mem::zeroed();
inv_keys[0] = keys[RK - 1];
for i in 1..RK - 1 {
inv_keys[i] = vaesimcq_u8(keys[RK - 1 - i]);
}
inv_keys[RK - 1] = keys[0];
inv_keys
}
#[inline]
#[target_feature(enable = "aes")]
unsafe fn sub_word(input: u32) -> u32 {
let input = vreinterpretq_u8_u32(vdupq_n_u32(input));
let sub_input = vaeseq_u8(input, vdupq_n_u8(0));
vgetq_lane_u32(vreinterpretq_u32_u8(sub_input), 0)
}