1use std::sync::LazyLock;
6
7use aes::{
8 Aes128,
9 cipher::{BlockCipherEncrypt, Key, KeyInit},
10};
11use bytemuck::Pod;
12
13use crate::{AES_PAR_BLOCKS, Block, utils::xor_inplace};
14
15pub struct AesHash {
17 aes: Aes128,
18}
19
20impl AesHash {
21 pub fn new(key: &Key<Aes128>) -> Self {
23 Self {
24 aes: Aes128::new(key),
25 }
26 }
27
28 pub fn cr_hash_block(&self, x: Block) -> Block {
33 let mut x_enc = x.into();
34 self.aes.encrypt_block(&mut x_enc);
35 x ^ x_enc.into()
36 }
37
38 pub fn cr_hash_blocks<const N: usize>(&self, x: &[Block; N]) -> [Block; N]
43 where
44 [Block; N]: Pod,
45 [aes::Block; N]: Pod,
46 {
47 let mut blocks: [aes::Block; N] = bytemuck::cast(*x);
48 self.aes.encrypt_blocks(&mut blocks);
49 let mut blocks: [Block; N] = bytemuck::cast(blocks);
50 xor_inplace(&mut blocks, x);
51 blocks
52 }
53
54 pub fn cr_hash_blocks_b2b<const N: usize>(&self, inp: &[Block; N], out: &mut [Block])
62 where
63 [Block; N]: Pod,
64 [aes::Block; N]: Pod,
65 {
66 assert_eq!(N, out.len());
67 let inp_aes: &[aes::Block; N] = bytemuck::cast_ref(inp);
68 let out_aes: &mut [aes::Block] = bytemuck::cast_slice_mut(out);
69 self.aes
70 .encrypt_blocks_b2b(inp_aes, out_aes)
71 .expect("buffer have equal size");
72 xor_inplace(out, inp);
73 }
74
75 pub fn cr_hash_slice_mut(&self, x: &mut [Block]) {
83 let mut tmp = [aes::Block::default(); AES_PAR_BLOCKS];
84
85 for chunk in x.chunks_mut(AES_PAR_BLOCKS) {
86 self.aes
87 .encrypt_blocks_b2b(bytemuck::cast_slice(chunk), &mut tmp[..chunk.len()])
88 .expect("in and out always have same length");
89 chunk
90 .iter_mut()
91 .zip(tmp)
92 .for_each(|(x, x_enc)| *x ^= x_enc.into());
93 }
94 }
95
96 pub fn tccr_hash_slice_mut(&self, x: &mut [Block], mut tweak_fn: impl FnMut(usize) -> Block) {
100 let mut tmp = [aes::Block::default(); AES_PAR_BLOCKS];
101 for (chunk_idx, chunk) in x.chunks_mut(AES_PAR_BLOCKS).enumerate() {
102 self.aes
103 .encrypt_blocks_b2b(bytemuck::cast_slice(chunk), &mut tmp[..chunk.len()])
104 .expect("in and out always have same length");
105 chunk
106 .iter_mut()
107 .zip(&mut tmp)
108 .enumerate()
109 .for_each(|(idx, (dest, x_enc))| {
110 *dest = Block::from(*x_enc) ^ tweak_fn(chunk_idx * AES_PAR_BLOCKS + idx);
111 });
112 self.aes.encrypt_blocks(bytemuck::cast_slice_mut(chunk));
113 chunk
114 .iter_mut()
115 .zip(tmp)
116 .for_each(|(x, x_enc)| *x ^= x_enc.into());
117 }
118 }
119}
120
121pub static FIXED_KEY_HASH: LazyLock<AesHash> = LazyLock::new(|| {
123 let key = 193502124791825095790518994062991136444_u128
124 .to_le_bytes()
125 .into();
126 AesHash::new(&key)
127});