crypto_async_rs/
aes_gcm.rs

1//https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
2use crate::aes;
3use crate::aes::BLOCK_SIZE;
4use std::convert::TryInto;
5
6const R: u128 = 0xe1000000000000000000000000000000;
7pub const TABLE_R: [u16; 256] = calculate_table_r();
8const P: u128 = 2u128.reverse_bits();
9const ONE_REVERSED: u128 = 1u128.reverse_bits();
10
11pub type GcmBlockMulFn = dyn Fn(u128) -> u128;
12
13///Block multiplication enhancement variants used for GHASH calculation.
14/// Which in turn used for calculation of authentication tag.
15/// https://luca-giuzzi.unibs.it/corsi/Support/papers-cryptography/gcm-spec.pdf
16/// `None` - regular multiplication. Requires just 16B (aes cipher key) per session, i.e. cca 67M sessions per 1GB of memory
17///     worst throughput
18/// `M0TableAndRTable` - cca 3.7 times faster then regular multiplication.
19///     Needs 4096Bytes per key, i.e. cca 262K key per 1GB of memory.
20/// `M4BitTables` - cca 6.9 times faster then regular multiplication.
21///     Needs 8192Bytes per key, i.e. cca 131K keys per 1GB of memory.
22/// `MTables` - cca 9 times faster then regular multiplication.
23///     Needs 65535Bytes per key, i.e. cca 16,4K keys per 1GB of memory.
24pub enum GcmBlockMulEnhancement {
25    None,
26    M0TableAndRTable,
27    M4BitTables,
28    MTables,
29}
30
31impl GcmBlockMulEnhancement {
32    /// Converts `BlockMulEnhancement` to a `Box<BlockMulFn>` function which represents block multiplication
33    /// and needs to be passed to `encrypt` and `decrypt` functions within a session.
34    ///  * `block_mul_enhancement` BlockMulEnhancement base on time-memory tradeoffs
35    ///  * `cipher_key` cipher key of underlying block cipher protocol i.e. AES
36    pub fn to_mul_fn(&self, cipher_key: &[u8]) -> Box<GcmBlockMulFn> {
37        let h = u128::from_be_bytes(aes::encrypt(&[0u8; BLOCK_SIZE], cipher_key));
38        match self {
39            GcmBlockMulEnhancement::None => Box::new(move |x| block_mul(x, h)),
40            GcmBlockMulEnhancement::M0TableAndRTable => {
41                let m0 = calculate_table_m(h, 0);
42                Box::new(move |x| block_mul_with_m0_r(&m0, x))
43            }
44            GcmBlockMulEnhancement::M4BitTables => {
45                let mut m = [[0u128; 16]; BLOCK_SIZE << 1];
46                for i in 0..m.len() {
47                    m[i] = calculate_4bit_table_m(h, i);
48                }
49                Box::new(move |x| block_mul_with_4bit_tables(&m, x))
50            }
51            GcmBlockMulEnhancement::MTables => {
52                let mut m = [[0u128; 256]; BLOCK_SIZE];
53                for i in 0..BLOCK_SIZE {
54                    m[i] = calculate_table_m(h, i);
55                }
56                Box::new(move |x| block_mul_with_tables(&m, x))
57            }
58        }
59    }
60}
61
62/// Encrypts `plain_text` to cipher text by XOR'ing with AES-encrypted "Counter block".
63/// "Counter block" is initialized by "Initialization Vector" and incremented for each input block
64/// i.e. each 16 bytes of plain text.
65/// Cipher text then gets concatenated with "additional authenticated data" to produce GHASH which in turn XOR'ed
66/// with first AES-encrypted counter block to produce "Authentication tag"
67///
68/// * `cipher_key` cipher key of underlying block cipher protocol i.e. AES
69/// * `iv` Initialization Vector. To initialize counter block.
70/// * `plain_text` plain text to encrypt and authenticate.
71/// * `aad` additional authenticated data.
72/// * `mul_fn` block multiplication function. The output of `block_mul_to_block_mul_fn` which
73///     should be provided within same session/`key` .
74/// * `(Vec<u8>, [u8; 16])`  (cipher_text, tag) output
75///
76/// # Examples
77///
78///```
79/// use crypto_async_rs::aes_gcm::{GcmBlockMulEnhancement, gcm_aes_encrypt};
80///
81/// let cipher_key = [0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08];
82/// let iv = [0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad];
83/// let p = [0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59];
84/// let aad = [0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe];
85/// let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
86/// let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
87///```
88pub fn gcm_aes_encrypt(
89    key: &[u8],
90    iv: &[u8],
91    plain_text: &[u8],
92    aad: &[u8],
93    mul_fn: &GcmBlockMulFn,
94) -> (Vec<u8>, [u8; 16]) {
95    let mut counter_block = iv2pre_counter_block(&iv, mul_fn);
96    let encrypted_block = aes::encrypt(&counter_block, key);
97    increment_32_least_bits(&mut counter_block);
98    let cipher_text = gctr(&mut counter_block, plain_text, key);
99    let s = define_block_s(&cipher_text, aad, mul_fn);
100    let tag = xor_full_blocks(&s, &encrypted_block);
101    (cipher_text, tag)
102}
103
104/// Decrypts `cipher_text` to plain text by XOR'ing with AES-encrypted "Counter block".
105/// "Counter block" is initialized by "Initialization Vector" and incremented for each input block
106/// i.e. each 16 bytes of plain text.
107/// Cipher text then gets concatenated with "additional authenticated data" to produce GHASH which in turn XOR'ed
108/// with first AES-encrypted counter block to produce "Authentication tag"
109///
110/// * `cipher_key` cipher key of underlying block cipher protocol i.e. AES
111/// * `iv` Initialization Vector. To initialize counter block.
112/// * `cipher_text` cipher text to decrypt and authenticate.
113/// * `aad` additional authenticated data.
114/// * `mul_fn` block multiplication function. The output of `block_mul_to_block_mul_fn` which
115///     should be provided within same session/`key` .
116/// * `(Vec<u8>, [u8; 16])`  (plain_text, tag) output
117///
118///  Tag should be compared with the one received with `cipher_text`.
119///  If not equal, then authentication failed (message is forged or corrupted).
120///
121/// # Examples
122///
123///```
124/// use crypto_async_rs::aes_gcm::{GcmBlockMulEnhancement, gcm_aes_decrypt};
125///
126/// let cipher_key = [0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08];
127/// let iv = [0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88];
128/// let cipher_text = [0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85];
129/// let aad = [];
130/// let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
131/// let (p, tag) = gcm_aes_decrypt(&cipher_key, &iv, &cipher_text, &aad, &mul_fn);
132///```
133pub fn gcm_aes_decrypt(
134    key: &[u8],
135    iv: &[u8],
136    cipher_text: &[u8],
137    aad: &[u8],
138    mul_fn: &GcmBlockMulFn,
139) -> (Vec<u8>, [u8; 16]) {
140    let mut counter_block = iv2pre_counter_block(&iv, mul_fn);
141    let encrypted_block = aes::encrypt(&counter_block, key);
142    increment_32_least_bits(&mut counter_block);
143    let plain_text = gctr(&mut counter_block, cipher_text, key);
144    let s = define_block_s(&cipher_text, aad, mul_fn);
145    let tag = xor_full_blocks(&s, &encrypted_block);
146    (plain_text, tag)
147}
148
149fn to_multiple_128_minus_itself_bits(value: usize) -> usize {
150    const ZERO_7: usize = !0x7fusize;
151    if value & 0x7f > 0 {
152        (value & ZERO_7) + 0x80 - value
153    } else {
154        0
155    }
156}
157
158pub const fn block_mul(x: u128, y: u128) -> u128 {
159    let mut z = 0u128;
160    let mut v = x;
161    let mut y_bit = ONE_REVERSED;
162    let mut i = 0usize;
163    while i < 128 {
164        if y & y_bit > 0 {
165            z ^= v;
166        }
167        v = if v & 1 > 0 { (v >> 1) ^ R } else { v >> 1 };
168        y_bit >>= 1;
169        i += 1;
170    }
171    z
172}
173
174fn ghash(bytes: &[u8], mul_fn: &GcmBlockMulFn) -> [u8; BLOCK_SIZE] {
175    let mut y = 0u128;
176    let mut start = 0usize;
177    let mut end = start + BLOCK_SIZE;
178    while start < bytes.len() {
179        y ^= u128::from_be_bytes(bytes[start..end].try_into().unwrap());
180        y = mul_fn(y);
181        start = end;
182        end = start + BLOCK_SIZE;
183    }
184    y.to_be_bytes()
185}
186
187pub fn iv2pre_counter_block(iv: &[u8], mul_fn: &GcmBlockMulFn) -> [u8; BLOCK_SIZE] {
188    if iv.len() == 12 {
189        let mut result = [0u8; BLOCK_SIZE];
190        result[..12].copy_from_slice(iv);
191        result[12..].copy_from_slice(&[0, 0, 0, 1]);
192        result
193    } else {
194        let iv_len_bit_len = iv.len() << 3;
195        let s = to_multiple_128_minus_itself_bits(iv_len_bit_len);
196        let len = iv.len() + ((s + 64) >> 3) + 8;
197        let mut bytes = vec![0u8; len];
198        bytes[..iv.len()].copy_from_slice(iv);
199        bytes[len - 8..].copy_from_slice(&(iv_len_bit_len as u64).to_be_bytes());
200        ghash(&bytes, mul_fn)
201    }
202}
203
204pub fn increment_32_least_bits(value: &mut [u8; BLOCK_SIZE]) {
205    let least_4_bytes: [u8; 4] = value[12..].try_into().unwrap();
206    value[12..].copy_from_slice(
207        &u32::from_be_bytes(least_4_bytes)
208            .wrapping_add(1)
209            .to_be_bytes(),
210    );
211}
212
213pub fn gctr(counter_block: &mut [u8; BLOCK_SIZE], bytes: &[u8], key: &[u8]) -> Vec<u8> {
214    if bytes.len() == 0 {
215        return vec![];
216    }
217    let full_blocks_len = bytes.len() & !0x0f;
218    let mut result = Vec::with_capacity(bytes.len());
219    let mut start = 0usize;
220    while start < full_blocks_len {
221        let encrypted_block = aes::encrypt(counter_block, key);
222        result.extend_from_slice(&xor_full_blocks(
223            &bytes[start..start + BLOCK_SIZE],
224            &encrypted_block,
225        ));
226        start += BLOCK_SIZE;
227        increment_32_least_bits(counter_block);
228    }
229
230    let partial_block_len = bytes.len() - full_blocks_len;
231    if partial_block_len > 0 {
232        let encrypted_block = aes::encrypt(counter_block, key);
233        result.extend_from_slice(&xor_partial_blocks(
234            &bytes[start..start + partial_block_len],
235            &encrypted_block[..partial_block_len],
236        ));
237    }
238
239    result
240}
241
242fn xor_partial_blocks(a: &[u8], b: &[u8]) -> Vec<u8> {
243    let mut result = Vec::with_capacity(a.len());
244    for i in 0..a.len() {
245        result.push(a[i] ^ b[i]);
246    }
247    result
248}
249
250/// a and b should be 16 bytes long
251pub fn xor_full_blocks(a: &[u8], b: &[u8]) -> [u8; 16] {
252    let a = u128::from_be_bytes(a.try_into().unwrap());
253    let b = u128::from_be_bytes(b.try_into().unwrap());
254    (a ^ b).to_be_bytes()
255}
256
257pub fn define_block_s(cipher_text: &[u8], aad: &[u8], mul_fn: &GcmBlockMulFn) -> [u8; BLOCK_SIZE] {
258    let aad_len_bit_len = aad.len() << 3;
259    let cipher_text_bit_len = cipher_text.len() << 3;
260    let u = to_multiple_128_minus_itself_bits(cipher_text_bit_len) >> 3;
261    let v = to_multiple_128_minus_itself_bits(aad_len_bit_len) >> 3;
262    let len = aad.len() + cipher_text.len() + u + v + 16;
263    let mut bytes = vec![0u8; len];
264    bytes[..aad.len()].copy_from_slice(aad);
265    let mut start = aad.len() + v;
266    bytes[start..start + cipher_text.len()].copy_from_slice(cipher_text);
267    start = len - 16;
268    bytes[start..start + 8].copy_from_slice(&(aad_len_bit_len as u64).to_be_bytes());
269    start += 8;
270    bytes[start..].copy_from_slice(&(cipher_text_bit_len as u64).to_be_bytes());
271    ghash(&bytes, mul_fn)
272}
273
274///
275/// h - hash sub-key. u128::from_be_bytes((h as &[u8]).try_into().unwrap())
276pub const fn calculate_table_m(h: u128, byte_index: usize) -> [u128; 256] {
277    let mut m = [0u128; 256];
278    let mut i = 64usize;
279    m[128] = block_mul(h, ONE_REVERSED >> (byte_index << 3));
280    while i > 0 {
281        m[i] = block_mul(m[i << 1], P);
282        i >>= 1;
283    }
284    i = 2;
285    while i < 256 {
286        let mut j = 1;
287        while j < i {
288            m[i + j] = m[i] ^ m[j];
289            j += 1;
290        }
291        i <<= 1;
292    }
293    m
294}
295
296pub const fn calculate_4bit_table_m(h: u128, four_bit_index: usize) -> [u128; 16] {
297    let mut m = [0u128; 16];
298    let mut i = 4usize;
299    m[8] = block_mul(h, ONE_REVERSED >> (four_bit_index << 2));
300    while i > 0 {
301        m[i] = block_mul(m[i << 1], P);
302        i >>= 1;
303    }
304    i = 2;
305    while i < 16 {
306        let mut j = 1;
307        while j < i {
308            m[i + j] = m[i] ^ m[j];
309            j += 1;
310        }
311        i <<= 1;
312    }
313    m
314}
315
316pub fn block_mul_with_tables(m: &[[u128; 256]; BLOCK_SIZE], x: u128) -> u128 {
317    let mut result = 0u128;
318    const MASK: u128 = 0xffu128.reverse_bits();
319    let mut mask = MASK;
320    for i in 0..BLOCK_SIZE {
321        let index = (x & mask) >> ((15 - i) << 3);
322        result ^= m[i][index as usize];
323        mask >>= 8;
324    }
325    result
326}
327
328pub fn block_mul_with_4bit_tables(m: &[[u128; 16]; BLOCK_SIZE << 1], x: u128) -> u128 {
329    let mut result = 0u128;
330    const MASK: u128 = 0x0fu128.reverse_bits();
331    let mut mask = MASK;
332    for i in 0..BLOCK_SIZE << 1 {
333        let index = (x & mask) >> ((31 - i) << 2);
334        result ^= m[i][index as usize];
335        mask >>= 4;
336    }
337    result
338}
339
340///
341/// calculates R-table for faster multiplication using M0 and R
342/// https://luca-giuzzi.unibs.it/corsi/Support/papers-cryptography/gcm-spec.pdf
343pub const fn calculate_table_r() -> [u16; 256] {
344    let mut m = [0u128; 256];
345    let mut i = 64usize;
346    m[128] = R;
347    while i > 0 {
348        m[i] = block_mul(m[i << 1], P);
349        i >>= 1;
350    }
351    i = 2;
352    while i < 256 {
353        let mut j = 1;
354        while j < i {
355            m[i + j] = m[i] ^ m[j];
356            j += 1;
357        }
358        i <<= 1;
359    }
360    let mut result = [0u16; 256];
361    i = 0;
362    while i < 256 {
363        result[i] = (m[i] >> 112) as u16;
364        i += 1;
365    }
366    result
367}
368
369pub fn block_mul_with_m0_r(m0: &[u128; 256], x: u128) -> u128 {
370    let mut z = 0u128;
371    let mut i = 15;
372    let mut a;
373    while i > 0 {
374        let index = (x >> ((15 - i) << 3)) as u8;
375        z = z ^ m0[index as usize];
376        a = z as u8;
377        z >>= 8;
378        z ^= (TABLE_R[a as usize] as u128) << 112;
379        i -= 1;
380    }
381    let index = (x >> 120) as u8;
382    z ^ m0[index as usize]
383}
384
385#[cfg(test)]
386mod tests {
387    use super::*;
388
389    #[test]
390    fn test_gcm_to_multiple_128_minus_itself() {
391        assert_eq!(to_multiple_128_minus_itself_bits(128), 0);
392        assert_eq!(to_multiple_128_minus_itself_bits(148), 108);
393        assert_eq!(to_multiple_128_minus_itself_bits(129), 127);
394        assert_eq!(to_multiple_128_minus_itself_bits(888888), 72);
395    }
396
397    #[test]
398    fn test_gcm_increment_32_least_bits_a() {
399        let mut bytes = [
400            0x10u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
401            0x00, 0x00,
402        ];
403        increment_32_least_bits(&mut bytes);
404        assert_eq!(
405            bytes,
406            [
407                0x10u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
408                0x00, 0x00, 0x01
409            ]
410        );
411        let mut bytes = [
412            0x10u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
413            0xff, 0xff,
414        ];
415        increment_32_least_bits(&mut bytes);
416        assert_eq!(
417            bytes,
418            [
419                0x10u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
420                0x00, 0x00, 0x00
421            ]
422        );
423    }
424
425    #[test]
426    fn test_gcm_aes_128_encrypt() {
427        //https://luca-giuzzi.unibs.it/corsi/Support/papers-cryptography/gcm-spec.pdf
428        //Test  Case  1
429        let cipher_key = [
430            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
431            0x00, 0x00,
432        ];
433        let iv = [
434            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
435        ];
436        let p = "".as_bytes();
437        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
438        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &"".as_bytes(), &mul_fn);
439        assert_eq!(&cipher_text, &[]);
440        assert_eq!(
441            &tag,
442            &[
443                0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61, 0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7,
444                0x45, 0x5a
445            ]
446        );
447
448        //Test  Case  2
449        let p = [
450            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
451            0x00, 0x00,
452        ];
453        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
454        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &"".as_bytes(), &mul_fn);
455        assert_eq!(
456            &cipher_text,
457            &[
458                0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2,
459                0xfe, 0x78
460            ]
461        );
462        assert_eq!(
463            &tag,
464            &[
465                0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd, 0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57,
466                0xbd, 0xdf
467            ]
468        );
469
470        let cipher_key = [
471            0xAD, 0x7A, 0x2B, 0xD0, 0x3E, 0xAC, 0x83, 0x5A, 0x6F, 0x62, 0x0F, 0xDC, 0xB5, 0x06,
472            0xB3, 0x45,
473        ];
474        let iv = [
475            0x12, 0x15, 0x35, 0x24, 0xC0, 0x89, 0x5E, 0x81, 0xB2, 0xC2, 0x84, 0x65,
476        ];
477        let p = [
478            0x08, 0x00, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
479            0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
480            0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
481            0x37, 0x38, 0x39, 0x3A, 0x00, 0x02,
482        ];
483        let aad = [
484            0xD6, 0x09, 0xB1, 0xF0, 0x56, 0x63, 0x7A, 0x0D, 0x46, 0xDF, 0x99, 0x8D, 0x88, 0xE5,
485            0x2E, 0x00, 0xB2, 0xC2, 0x84, 0x65, 0x12, 0x15, 0x35, 0x24, 0xC0, 0x89, 0x5E, 0x81,
486        ];
487        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
488        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
489        assert_eq!(
490            &cipher_text,
491            &[
492                0x70, 0x1A, 0xFA, 0x1C, 0xC0, 0x39, 0xC0, 0xD7, 0x65, 0x12, 0x8A, 0x66, 0x5D, 0xAB,
493                0x69, 0x24, 0x38, 0x99, 0xBF, 0x73, 0x18, 0xCC, 0xDC, 0x81, 0xC9, 0x93, 0x1D, 0xA1,
494                0x7F, 0xBE, 0x8E, 0xDD, 0x7D, 0x17, 0xCB, 0x8B, 0x4C, 0x26, 0xFC, 0x81, 0xE3, 0x28,
495                0x4F, 0x2B, 0x7F, 0xBA, 0x71, 0x3D
496            ]
497        );
498        assert_eq!(
499            &tag,
500            &[
501                0x4F, 0x8D, 0x55, 0xE7, 0xD3, 0xF0, 0x6F, 0xD5, 0xA1, 0x3C, 0x0C, 0x29, 0xB9, 0xD5,
502                0xB8, 0x80
503            ]
504        );
505
506        //Test  Case  3
507        let cipher_key = [
508            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
509            0x83, 0x08,
510        ];
511        let iv = [
512            0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
513        ];
514        let p = [
515            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
516            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
517            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
518            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
519            0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55,
520        ];
521        let aad = [];
522        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
523        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
524        assert_eq!(
525            &cipher_text,
526            &[
527                0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0,
528                0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23,
529                0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f,
530                0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
531                0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85
532            ]
533        );
534        assert_eq!(
535            &tag,
536            &[
537                0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6,
538                0xfa, 0xb4
539            ]
540        );
541
542        //Test  Case  4
543        let cipher_key = [
544            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
545            0x83, 0x08,
546        ];
547        let iv = [
548            0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
549        ];
550        let p = [
551            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
552            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
553            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
554            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
555            0xba, 0x63, 0x7b, 0x39,
556        ];
557        let aad = [
558            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
559            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
560        ];
561        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
562        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
563        assert_eq!(
564            &cipher_text,
565            &[
566                0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0,
567                0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23,
568                0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f,
569                0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
570                0x3d, 0x58, 0xe0, 0x91
571            ]
572        );
573        assert_eq!(
574            &tag,
575            &[
576                0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb, 0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12,
577                0x1a, 0x47
578            ]
579        );
580
581        //Test  Case  5
582        let cipher_key = [
583            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
584            0x83, 0x08,
585        ];
586        let iv = [0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad];
587        let p = [
588            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
589            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
590            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
591            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
592            0xba, 0x63, 0x7b, 0x39,
593        ];
594        let aad = [
595            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
596            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
597        ];
598        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
599        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
600        assert_eq!(
601            &cipher_text,
602            &[
603                0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a, 0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a,
604                0x47, 0x55, 0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8, 0x37, 0x66, 0xe5, 0xf9,
605                0x7b, 0x6c, 0x74, 0x23, 0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2, 0x2b, 0x09,
606                0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42, 0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07,
607                0xc2, 0x3f, 0x45, 0x98
608            ]
609        );
610        assert_eq!(
611            &tag,
612            &[
613                0x36, 0x12, 0xd2, 0xe7, 0x9e, 0x3b, 0x07, 0x85, 0x56, 0x1b, 0xe1, 0x4a, 0xac, 0xa2,
614                0xfc, 0xcb
615            ]
616        );
617
618        //Test  Case  6
619        let cipher_key = [
620            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
621            0x83, 0x08,
622        ];
623        let iv = [
624            0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5, 0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52,
625            0x69, 0xaa, 0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1, 0xe4, 0xc3, 0x03, 0xd2,
626            0xa3, 0x18, 0xa7, 0x28, 0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39, 0xfc, 0xf0,
627            0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54, 0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57,
628            0xa6, 0x37, 0xb3, 0x9b,
629        ];
630        let p = [
631            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
632            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
633            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
634            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
635            0xba, 0x63, 0x7b, 0x39,
636        ];
637        let aad = [
638            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
639            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
640        ];
641        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
642        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
643        assert_eq!(
644            &cipher_text,
645            &[
646                0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6, 0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f,
647                0xb8, 0x94, 0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8, 0xba, 0x26, 0x2a, 0x3c,
648                0xca, 0x7e, 0x2c, 0xa7, 0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90, 0xcc, 0xdc,
649                0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f, 0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03,
650                0x4c, 0x34, 0xae, 0xe5
651            ]
652        );
653        assert_eq!(
654            &tag,
655            &[
656                0x61, 0x9c, 0xc5, 0xae, 0xff, 0xfe, 0x0b, 0xfa, 0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99,
657                0xd0, 0x50
658            ]
659        );
660    }
661
662    #[test]
663    fn test_gcm_aes_192_encrypt() {
664        //https://luca-giuzzi.unibs.it/corsi/Support/papers-cryptography/gcm-spec.pdf
665        //Test  Case  7
666        let cipher_key = [
667            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
668            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
669        ];
670        let iv = [
671            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
672        ];
673        let p = [];
674        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
675        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &"".as_bytes(), &mul_fn);
676        assert_eq!(&cipher_text, &[]);
677        assert_eq!(
678            &tag,
679            &[
680                0xcd, 0x33, 0xb2, 0x8a, 0xc7, 0x73, 0xf7, 0x4b, 0xa0, 0x0e, 0xd1, 0xf3, 0x12, 0x57,
681                0x24, 0x35
682            ]
683        );
684
685        //Test  Case  8
686        let cipher_key = [
687            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
688            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
689        ];
690        let iv = [
691            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
692        ];
693        let p = [
694            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
695            0x00, 0x00,
696        ];
697        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
698        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &"".as_bytes(), &mul_fn);
699        assert_eq!(
700            &cipher_text,
701            &[
702                0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41, 0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0,
703                0xf6, 0x00
704            ]
705        );
706        assert_eq!(
707            &tag,
708            &[
709                0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab, 0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14,
710                0xf0, 0xfb
711            ]
712        );
713
714        //Test  Case  9
715        let cipher_key = [
716            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
717            0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
718        ];
719        let iv = [
720            0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
721        ];
722        let p = [
723            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
724            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
725            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
726            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
727            0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55,
728        ];
729        let aad = [];
730        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
731        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
732        assert_eq!(
733            &cipher_text,
734            &[
735                0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a,
736                0x27, 0x57, 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, 0x62, 0x85, 0x93, 0xb4,
737                0x0c, 0xa1, 0xe1, 0x9c, 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, 0xac, 0x61,
738                0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
739                0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56
740            ]
741        );
742        assert_eq!(
743            &tag,
744            &[
745                0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf, 0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67,
746                0x4a, 0x14
747            ]
748        );
749
750        //Test  Case  10
751        let cipher_key = [
752            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
753            0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
754        ];
755        let iv = [
756            0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
757        ];
758        let p = [
759            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
760            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
761            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
762            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
763            0xba, 0x63, 0x7b, 0x39,
764        ];
765        let aad = [
766            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
767            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
768        ];
769        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
770        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
771        assert_eq!(
772            &cipher_text,
773            &[
774                0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a,
775                0x27, 0x57, 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, 0x62, 0x85, 0x93, 0xb4,
776                0x0c, 0xa1, 0xe1, 0x9c, 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, 0xac, 0x61,
777                0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
778                0xcc, 0xda, 0x27, 0x10
779            ]
780        );
781        assert_eq!(
782            &tag,
783            &[
784                0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f, 0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27,
785                0x61, 0x8c
786            ]
787        );
788
789        //Test  Case  11
790        let cipher_key = [
791            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
792            0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
793        ];
794        let iv = [0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad];
795        let p = [
796            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
797            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
798            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
799            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
800            0xba, 0x63, 0x7b, 0x39,
801        ];
802        let aad = [
803            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
804            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
805        ];
806        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
807        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
808        assert_eq!(
809            &cipher_text,
810            &[
811                0x0f, 0x10, 0xf5, 0x99, 0xae, 0x14, 0xa1, 0x54, 0xed, 0x24, 0xb3, 0x6e, 0x25, 0x32,
812                0x4d, 0xb8, 0xc5, 0x66, 0x63, 0x2e, 0xf2, 0xbb, 0xb3, 0x4f, 0x83, 0x47, 0x28, 0x0f,
813                0xc4, 0x50, 0x70, 0x57, 0xfd, 0xdc, 0x29, 0xdf, 0x9a, 0x47, 0x1f, 0x75, 0xc6, 0x65,
814                0x41, 0xd4, 0xd4, 0xda, 0xd1, 0xc9, 0xe9, 0x3a, 0x19, 0xa5, 0x8e, 0x8b, 0x47, 0x3f,
815                0xa0, 0xf0, 0x62, 0xf7
816            ]
817        );
818        assert_eq!(
819            &tag,
820            &[
821                0x65, 0xdc, 0xc5, 0x7f, 0xcf, 0x62, 0x3a, 0x24, 0x09, 0x4f, 0xcc, 0xa4, 0x0d, 0x35,
822                0x33, 0xf8
823            ]
824        );
825
826        //Test  Case  12
827        let cipher_key = [
828            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
829            0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
830        ];
831        let iv = [
832            0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5, 0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52,
833            0x69, 0xaa, 0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1, 0xe4, 0xc3, 0x03, 0xd2,
834            0xa3, 0x18, 0xa7, 0x28, 0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39, 0xfc, 0xf0,
835            0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54, 0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57,
836            0xa6, 0x37, 0xb3, 0x9b,
837        ];
838        let p = [
839            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
840            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
841            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
842            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
843            0xba, 0x63, 0x7b, 0x39,
844        ];
845        let aad = [
846            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
847            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
848        ];
849        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
850        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
851        assert_eq!(
852            &cipher_text,
853            &[
854                0xd2, 0x7e, 0x88, 0x68, 0x1c, 0xe3, 0x24, 0x3c, 0x48, 0x30, 0x16, 0x5a, 0x8f, 0xdc,
855                0xf9, 0xff, 0x1d, 0xe9, 0xa1, 0xd8, 0xe6, 0xb4, 0x47, 0xef, 0x6e, 0xf7, 0xb7, 0x98,
856                0x28, 0x66, 0x6e, 0x45, 0x81, 0xe7, 0x90, 0x12, 0xaf, 0x34, 0xdd, 0xd9, 0xe2, 0xf0,
857                0x37, 0x58, 0x9b, 0x29, 0x2d, 0xb3, 0xe6, 0x7c, 0x03, 0x67, 0x45, 0xfa, 0x22, 0xe7,
858                0xe9, 0xb7, 0x37, 0x3b
859            ]
860        );
861        assert_eq!(
862            &tag,
863            &[
864                0xdc, 0xf5, 0x66, 0xff, 0x29, 0x1c, 0x25, 0xbb, 0xb8, 0x56, 0x8f, 0xc3, 0xd3, 0x76,
865                0xa6, 0xd9
866            ]
867        );
868    }
869
870    #[test]
871    fn test_gcm_aes_256_encrypt() {
872        //https://luca-giuzzi.unibs.it/corsi/Support/papers-cryptography/gcm-spec.pdf
873        //Test  Case  13
874        let cipher_key = [
875            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
876            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
877            0x00, 0x00, 0x00, 0x00,
878        ];
879        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
880        let iv = [
881            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
882        ];
883        let p = [];
884        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &"".as_bytes(), &mul_fn);
885        assert_eq!(&cipher_text, &[]);
886        assert_eq!(
887            &tag,
888            &[
889                0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9, 0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb,
890                0x73, 0x8b
891            ]
892        );
893
894        //Test  Case  14
895        let cipher_key = [
896            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
897            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
898            0x00, 0x00, 0x00, 0x00,
899        ];
900        let iv = [
901            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
902        ];
903        let p = [
904            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
905            0x00, 0x00,
906        ];
907        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
908        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &"".as_bytes(), &mul_fn);
909        assert_eq!(
910            &cipher_text,
911            &[
912                0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3,
913                0x9d, 0x18
914            ]
915        );
916        assert_eq!(
917            &tag,
918            &[
919                0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0, 0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a,
920                0xb9, 0x19
921            ]
922        );
923
924        //Test  Case  15
925        let cipher_key = [
926            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
927            0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94,
928            0x67, 0x30, 0x83, 0x08,
929        ];
930        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
931        let iv = [
932            0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
933        ];
934        let p = [
935            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
936            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
937            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
938            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
939            0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55,
940        ];
941        let aad = [];
942        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
943        assert_eq!(
944            &cipher_text,
945            &[
946                0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84,
947                0x42, 0x7d, 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, 0x75, 0x98, 0xa2, 0xbd,
948                0x25, 0x55, 0xd1, 0xaa, 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, 0xa7, 0xb0,
949                0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
950                0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad
951            ]
952        );
953        assert_eq!(
954            &tag,
955            &[
956                0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd, 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3,
957                0xcc, 0x6c
958            ]
959        );
960
961        //Test  Case  16
962        let cipher_key = [
963            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
964            0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94,
965            0x67, 0x30, 0x83, 0x08,
966        ];
967        let iv = [
968            0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
969        ];
970        let p = [
971            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
972            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
973            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
974            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
975            0xba, 0x63, 0x7b, 0x39,
976        ];
977        let aad = [
978            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
979            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
980        ];
981        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
982        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
983        assert_eq!(
984            &cipher_text,
985            &[
986                0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84,
987                0x42, 0x7d, 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, 0x75, 0x98, 0xa2, 0xbd,
988                0x25, 0x55, 0xd1, 0xaa, 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, 0xa7, 0xb0,
989                0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
990                0xbc, 0xc9, 0xf6, 0x62
991            ]
992        );
993        assert_eq!(
994            &tag,
995            &[
996                0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d,
997                0x55, 0x1b
998            ]
999        );
1000
1001        //Test  Case  17
1002        let cipher_key = [
1003            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
1004            0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94,
1005            0x67, 0x30, 0x83, 0x08,
1006        ];
1007        let iv = [0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad];
1008        let p = [
1009            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
1010            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
1011            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
1012            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
1013            0xba, 0x63, 0x7b, 0x39,
1014        ];
1015        let aad = [
1016            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
1017            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
1018        ];
1019        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
1020        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
1021        assert_eq!(
1022            &cipher_text,
1023            &[
1024                0xc3, 0x76, 0x2d, 0xf1, 0xca, 0x78, 0x7d, 0x32, 0xae, 0x47, 0xc1, 0x3b, 0xf1, 0x98,
1025                0x44, 0xcb, 0xaf, 0x1a, 0xe1, 0x4d, 0x0b, 0x97, 0x6a, 0xfa, 0xc5, 0x2f, 0xf7, 0xd7,
1026                0x9b, 0xba, 0x9d, 0xe0, 0xfe, 0xb5, 0x82, 0xd3, 0x39, 0x34, 0xa4, 0xf0, 0x95, 0x4c,
1027                0xc2, 0x36, 0x3b, 0xc7, 0x3f, 0x78, 0x62, 0xac, 0x43, 0x0e, 0x64, 0xab, 0xe4, 0x99,
1028                0xf4, 0x7c, 0x9b, 0x1f
1029            ]
1030        );
1031        assert_eq!(
1032            &tag,
1033            &[
1034                0x3a, 0x33, 0x7d, 0xbf, 0x46, 0xa7, 0x92, 0xc4, 0x5e, 0x45, 0x49, 0x13, 0xfe, 0x2e,
1035                0xa8, 0xf2
1036            ]
1037        );
1038
1039        //Test  Case  18
1040        let cipher_key = [
1041            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
1042            0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94,
1043            0x67, 0x30, 0x83, 0x08,
1044        ];
1045        let iv = [
1046            0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5, 0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52,
1047            0x69, 0xaa, 0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1, 0xe4, 0xc3, 0x03, 0xd2,
1048            0xa3, 0x18, 0xa7, 0x28, 0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39, 0xfc, 0xf0,
1049            0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54, 0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57,
1050            0xa6, 0x37, 0xb3, 0x9b,
1051        ];
1052        let p = [
1053            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
1054            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
1055            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
1056            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
1057            0xba, 0x63, 0x7b, 0x39,
1058        ];
1059        let aad = [
1060            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
1061            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
1062        ];
1063        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
1064        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
1065        assert_eq!(
1066            &cipher_text,
1067            &[
1068                0x5a, 0x8d, 0xef, 0x2f, 0x0c, 0x9e, 0x53, 0xf1, 0xf7, 0x5d, 0x78, 0x53, 0x65, 0x9e,
1069                0x2a, 0x20, 0xee, 0xb2, 0xb2, 0x2a, 0xaf, 0xde, 0x64, 0x19, 0xa0, 0x58, 0xab, 0x4f,
1070                0x6f, 0x74, 0x6b, 0xf4, 0x0f, 0xc0, 0xc3, 0xb7, 0x80, 0xf2, 0x44, 0x45, 0x2d, 0xa3,
1071                0xeb, 0xf1, 0xc5, 0xd8, 0x2c, 0xde, 0xa2, 0x41, 0x89, 0x97, 0x20, 0x0e, 0xf8, 0x2e,
1072                0x44, 0xae, 0x7e, 0x3f
1073            ]
1074        );
1075        assert_eq!(
1076            &tag,
1077            &[
1078                0xa4, 0x4a, 0x82, 0x66, 0xee, 0x1c, 0x8e, 0xb0, 0xc8, 0xb5, 0xd4, 0xcf, 0x5a, 0xe9,
1079                0xf1, 0x9a
1080            ]
1081        );
1082    }
1083
1084    #[test]
1085    fn test_calculate_m() {
1086        let cipher_key = [
1087            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1088            0x00, 0x00,
1089        ];
1090        let h_block = aes::encrypt(&[0u8; BLOCK_SIZE], &cipher_key);
1091        let h = u128::from_be_bytes(h_block);
1092        let m0 = calculate_table_m(h, 0);
1093        assert_eq!(
1094            block_mul(h, 254u128.reverse_bits()),
1095            m0[254u8.reverse_bits() as usize]
1096        );
1097        assert_eq!(
1098            block_mul(h, 1u128.reverse_bits()),
1099            m0[1u8.reverse_bits() as usize]
1100        );
1101        assert_eq!(
1102            block_mul(h, 0u128.reverse_bits()),
1103            m0[0u8.reverse_bits() as usize]
1104        );
1105        assert_eq!(
1106            block_mul(h, 2u128.reverse_bits()),
1107            m0[2u8.reverse_bits() as usize]
1108        );
1109        assert_eq!(
1110            block_mul(h, 4u128.reverse_bits()),
1111            m0[4u8.reverse_bits() as usize]
1112        );
1113        assert_eq!(
1114            block_mul(h, 37u128.reverse_bits()),
1115            m0[37u8.reverse_bits() as usize]
1116        );
1117
1118        let m1 = calculate_table_m(h, 1);
1119        assert_eq!(block_mul(m0[254], 1u128.reverse_bits() >> 8), m1[254]);
1120        assert_eq!(block_mul(m0[1], 1u128.reverse_bits() >> 8), m1[1]);
1121        assert_eq!(block_mul(m0[4], 1u128.reverse_bits() >> 8), m1[4]);
1122        assert_eq!(block_mul(m0[0], 1u128.reverse_bits() >> 8), m1[0]);
1123        assert_eq!(block_mul(m0[2], 1u128.reverse_bits() >> 8), m1[2]);
1124        assert_eq!(block_mul(m0[37], 1u128.reverse_bits() >> 8), m1[37]);
1125
1126        let m2 = calculate_table_m(h, 2);
1127        assert_eq!(block_mul(m1[254], 1u128.reverse_bits() >> 8), m2[254]);
1128        assert_eq!(block_mul(m1[1], 1u128.reverse_bits() >> 8), m2[1]);
1129        assert_eq!(block_mul(m1[4], 1u128.reverse_bits() >> 8), m2[4]);
1130        assert_eq!(block_mul(m1[0], 1u128.reverse_bits() >> 8), m2[0]);
1131        assert_eq!(block_mul(m1[2], 1u128.reverse_bits() >> 8), m2[2]);
1132        assert_eq!(block_mul(m1[37], 1u128.reverse_bits() >> 8), m2[37]);
1133        assert_eq!(block_mul(m0[37], 1u128.reverse_bits() >> 16), m2[37]);
1134
1135        let m3 = calculate_table_m(h, 3);
1136        assert_eq!(block_mul(m2[255], 1u128.reverse_bits() >> 8), m3[255]);
1137        assert_eq!(block_mul(m2[11], 1u128.reverse_bits() >> 8), m3[11]);
1138        assert_eq!(block_mul(m2[8], 1u128.reverse_bits() >> 8), m3[8]);
1139        assert_eq!(block_mul(m2[15], 1u128.reverse_bits() >> 8), m3[15]);
1140        assert_eq!(block_mul(m2[3], 1u128.reverse_bits() >> 8), m3[3]);
1141        assert_eq!(block_mul(m2[33], 1u128.reverse_bits() >> 8), m3[33]);
1142        assert_eq!(block_mul(m0[77], 1u128.reverse_bits() >> 24), m3[77]);
1143
1144        let m4 = calculate_table_m(h, 4);
1145        assert_eq!(block_mul(m3[64], 1u128.reverse_bits() >> 8), m4[64]);
1146        assert_eq!(block_mul(m3[32], 1u128.reverse_bits() >> 8), m4[32]);
1147        assert_eq!(block_mul(m3[192], 1u128.reverse_bits() >> 8), m4[192]);
1148        assert_eq!(block_mul(m3[12], 1u128.reverse_bits() >> 8), m4[12]);
1149        assert_eq!(block_mul(m3[128], 1u128.reverse_bits() >> 8), m4[128]);
1150        assert_eq!(block_mul(m3[129], 1u128.reverse_bits() >> 8), m4[129]);
1151        assert_eq!(block_mul(m0[211], 1u128.reverse_bits() >> 32), m4[211]);
1152
1153        let m5 = calculate_table_m(h, 5);
1154        assert_eq!(block_mul(m0[12], 1u128.reverse_bits() >> 40), m5[12]);
1155        assert_eq!(block_mul(m1[15], 1u128.reverse_bits() >> 32), m5[15]);
1156        assert_eq!(block_mul(m2[16], 1u128.reverse_bits() >> 24), m5[16]);
1157        assert_eq!(block_mul(m3[128], 1u128.reverse_bits() >> 16), m5[128]);
1158
1159        let m6 = calculate_table_m(h, 6);
1160        let m7 = calculate_table_m(h, 7);
1161        let m8 = calculate_table_m(h, 8);
1162        let m9 = calculate_table_m(h, 9);
1163        let m10 = calculate_table_m(h, 10);
1164        let m11 = calculate_table_m(h, 11);
1165        let m12 = calculate_table_m(h, 12);
1166        let m13 = calculate_table_m(h, 13);
1167        let m14 = calculate_table_m(h, 14);
1168        let m15 = calculate_table_m(h, 15);
1169        assert_eq!(block_mul(m0[2], 1u128.reverse_bits() >> 120), m15[2]);
1170        assert_eq!(block_mul(m1[3], 1u128.reverse_bits() >> 112), m15[3]);
1171        assert_eq!(block_mul(m2[4], 1u128.reverse_bits() >> 104), m15[4]);
1172        assert_eq!(block_mul(m3[5], 1u128.reverse_bits() >> 96), m15[5]);
1173        assert_eq!(block_mul(m4[6], 1u128.reverse_bits() >> 88), m15[6]);
1174        assert_eq!(block_mul(m5[7], 1u128.reverse_bits() >> 80), m15[7]);
1175        assert_eq!(block_mul(m6[8], 1u128.reverse_bits() >> 72), m15[8]);
1176        assert_eq!(block_mul(m7[9], 1u128.reverse_bits() >> 64), m15[9]);
1177        assert_eq!(block_mul(m8[1], 1u128.reverse_bits() >> 56), m15[1]);
1178        assert_eq!(block_mul(m9[255], 1u128.reverse_bits() >> 48), m15[255]);
1179        assert_eq!(block_mul(m10[232], 1u128.reverse_bits() >> 40), m15[232]);
1180        assert_eq!(block_mul(m11[192], 1u128.reverse_bits() >> 32), m15[192]);
1181        assert_eq!(block_mul(m12[64], 1u128.reverse_bits() >> 24), m15[64]);
1182        assert_eq!(block_mul(m13[17], 1u128.reverse_bits() >> 16), m15[17]);
1183        assert_eq!(block_mul(m14[93], 1u128.reverse_bits() >> 8), m15[93]);
1184    }
1185
1186    #[test]
1187    fn test_gcm_aes_block_mul_with_tables() {
1188        let cipher_key = [
1189            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1190            0x00, 0x00,
1191        ];
1192        let h_block = aes::encrypt(&[0u8; BLOCK_SIZE], &cipher_key);
1193        let h = u128::from_be_bytes(h_block);
1194        let mut m = [[0u128; 256]; BLOCK_SIZE];
1195        for i in 0..BLOCK_SIZE {
1196            m[i] = calculate_table_m(h, i);
1197        }
1198        let x_block = [
1199            0x2fu8, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab, 0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14,
1200            0xf0, 0xfb,
1201        ];
1202        let x = u128::from_be_bytes(x_block);
1203        let r1 = block_mul_with_tables(&m, x);
1204        let r2 = block_mul(x, h);
1205        assert_eq!(r1, r2);
1206
1207        let cipher_key = [
1208            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
1209            0x83, 0x08,
1210        ];
1211        let iv = [
1212            0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1213        ];
1214        let p = [
1215            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
1216            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
1217            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
1218            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
1219            0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55,
1220        ];
1221        let aad = [];
1222        let mul_fn = GcmBlockMulEnhancement::MTables.to_mul_fn(&cipher_key);
1223        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
1224        assert_eq!(
1225            &cipher_text,
1226            &[
1227                0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0,
1228                0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23,
1229                0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f,
1230                0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
1231                0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85
1232            ]
1233        );
1234        assert_eq!(
1235            &tag,
1236            &[
1237                0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6,
1238                0xfa, 0xb4
1239            ]
1240        );
1241    }
1242
1243    #[test]
1244    fn test_gcm_aes_block_mul_with_4bit_tables() {
1245        let cipher_key = [
1246            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1247            0x00, 0x00,
1248        ];
1249        let h_block = aes::encrypt(&[0u8; BLOCK_SIZE], &cipher_key);
1250        let h = u128::from_be_bytes(h_block);
1251        let mut m = [[0u128; 16]; BLOCK_SIZE << 1];
1252        for i in 0..m.len() {
1253            m[i] = calculate_4bit_table_m(h, i);
1254        }
1255        let x_block = [
1256            0x2fu8, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab, 0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14,
1257            0xf0, 0xfb,
1258        ];
1259        let x = u128::from_be_bytes(x_block);
1260        let r1 = block_mul_with_4bit_tables(&m, x);
1261        let r2 = block_mul(x, h);
1262        assert_eq!(r1, r2);
1263
1264        let cipher_key = [
1265            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
1266            0x83, 0x08,
1267        ];
1268        let iv = [
1269            0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1270        ];
1271        let p = [
1272            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
1273            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
1274            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
1275            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
1276            0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55,
1277        ];
1278        let aad = [];
1279        let mul_fn = GcmBlockMulEnhancement::M4BitTables.to_mul_fn(&cipher_key);
1280        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
1281        assert_eq!(
1282            &cipher_text,
1283            &[
1284                0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0,
1285                0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23,
1286                0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f,
1287                0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
1288                0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85
1289            ]
1290        );
1291        assert_eq!(
1292            &tag,
1293            &[
1294                0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6,
1295                0xfa, 0xb4
1296            ]
1297        );
1298    }
1299
1300    #[test]
1301    fn test_gcm_aes_calculate_r_table() {
1302        assert_eq!(TABLE_R[0x80], 0xe100);
1303    }
1304
1305    #[test]
1306    fn test_gcm_aes_block_mul_with_m0_r() {
1307        let cipher_key = [
1308            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1309            0x00, 0x00,
1310        ];
1311        let h_block = aes::encrypt(&[0u8; BLOCK_SIZE], &cipher_key);
1312        let h = u128::from_be_bytes(h_block);
1313        let m0 = calculate_table_m(h, 0);
1314        let x_block = [
1315            0x2fu8, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab, 0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14,
1316            0xf0, 0xfb,
1317        ];
1318        let x = u128::from_be_bytes(x_block);
1319        let r1 = block_mul_with_m0_r(&m0, x);
1320        let r2 = block_mul(h, x);
1321        assert_eq!(r1, r2);
1322
1323        let cipher_key = [
1324            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
1325            0x83, 0x08,
1326        ];
1327        let iv = [
1328            0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1329        ];
1330        let p = [
1331            0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
1332            0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
1333            0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
1334            0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
1335            0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55,
1336        ];
1337        let aad = [];
1338        let mul_fn = GcmBlockMulEnhancement::M0TableAndRTable.to_mul_fn(&cipher_key);
1339        let (cipher_text, tag) = gcm_aes_encrypt(&cipher_key, &iv, &p, &aad, &mul_fn);
1340        assert_eq!(
1341            &cipher_text,
1342            &[
1343                0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0,
1344                0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23,
1345                0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f,
1346                0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
1347                0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85
1348            ]
1349        );
1350        assert_eq!(
1351            &tag,
1352            &[
1353                0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6,
1354                0xfa, 0xb4
1355            ]
1356        );
1357    }
1358
1359    #[test]
1360    fn test_gcm_aes_128_decrypt() {
1361        //https://luca-giuzzi.unibs.it/corsi/Support/papers-cryptography/gcm-spec.pdf
1362        //Test  Case  1
1363        let cipher_key = [
1364            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1365            0x00, 0x00,
1366        ];
1367        let iv = [
1368            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1369        ];
1370        let cipher_text = [];
1371        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
1372        let (p, tag) = gcm_aes_decrypt(&cipher_key, &iv, &cipher_text, &[], &mul_fn);
1373        assert_eq!(&p, &[]);
1374        assert_eq!(
1375            &tag,
1376            &[
1377                0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61, 0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7,
1378                0x45, 0x5a
1379            ]
1380        );
1381
1382        //Test  Case  2
1383        let cipher_text = [
1384            0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2,
1385            0xfe, 0x78,
1386        ];
1387        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
1388        let (p, tag) = gcm_aes_decrypt(&cipher_key, &iv, &cipher_text, &[], &mul_fn);
1389        assert_eq!(
1390            &p,
1391            &[
1392                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1393                0x00, 0x00
1394            ]
1395        );
1396        assert_eq!(
1397            &tag,
1398            &[
1399                0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd, 0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57,
1400                0xbd, 0xdf
1401            ]
1402        );
1403
1404        //Test  Case  3
1405        let cipher_key = [
1406            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
1407            0x83, 0x08,
1408        ];
1409        let iv = [
1410            0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1411        ];
1412        let cipher_text = [
1413            0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0,
1414            0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23,
1415            0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f,
1416            0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
1417            0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85,
1418        ];
1419        let aad = [];
1420        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
1421        let (p, tag) = gcm_aes_decrypt(&cipher_key, &iv, &cipher_text, &aad, &mul_fn);
1422        assert_eq!(
1423            &p,
1424            &[
1425                0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
1426                0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
1427                0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
1428                0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
1429                0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55
1430            ]
1431        );
1432        assert_eq!(
1433            &tag,
1434            &[
1435                0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6,
1436                0xfa, 0xb4
1437            ]
1438        );
1439
1440        //Test  Case  4
1441        let cipher_key = [
1442            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
1443            0x83, 0x08,
1444        ];
1445        let iv = [
1446            0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1447        ];
1448        let cipher_text = [
1449            0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0,
1450            0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23,
1451            0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f,
1452            0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
1453            0x3d, 0x58, 0xe0, 0x91,
1454        ];
1455        let aad = [
1456            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
1457            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
1458        ];
1459        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
1460        let (p, tag) = gcm_aes_decrypt(&cipher_key, &iv, &cipher_text, &aad, &mul_fn);
1461        assert_eq!(
1462            &p,
1463            &[
1464                0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
1465                0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
1466                0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
1467                0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
1468                0xba, 0x63, 0x7b, 0x39
1469            ]
1470        );
1471        assert_eq!(
1472            &tag,
1473            &[
1474                0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb, 0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12,
1475                0x1a, 0x47
1476            ]
1477        );
1478
1479        //Test  Case  5
1480        let cipher_key = [
1481            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
1482            0x83, 0x08,
1483        ];
1484        let iv = [0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad];
1485        let cipher_text = [
1486            0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a, 0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a,
1487            0x47, 0x55, 0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8, 0x37, 0x66, 0xe5, 0xf9,
1488            0x7b, 0x6c, 0x74, 0x23, 0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2, 0x2b, 0x09,
1489            0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42, 0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07,
1490            0xc2, 0x3f, 0x45, 0x98,
1491        ];
1492        let aad = [
1493            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
1494            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
1495        ];
1496        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
1497        let (p, tag) = gcm_aes_decrypt(&cipher_key, &iv, &cipher_text, &aad, &mul_fn);
1498        assert_eq!(
1499            &p,
1500            &[
1501                0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
1502                0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
1503                0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
1504                0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
1505                0xba, 0x63, 0x7b, 0x39
1506            ]
1507        );
1508        assert_eq!(
1509            &tag,
1510            &[
1511                0x36, 0x12, 0xd2, 0xe7, 0x9e, 0x3b, 0x07, 0x85, 0x56, 0x1b, 0xe1, 0x4a, 0xac, 0xa2,
1512                0xfc, 0xcb
1513            ]
1514        );
1515
1516        //Test  Case  6
1517        let cipher_key = [
1518            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
1519            0x83, 0x08,
1520        ];
1521        let iv = [
1522            0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5, 0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52,
1523            0x69, 0xaa, 0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1, 0xe4, 0xc3, 0x03, 0xd2,
1524            0xa3, 0x18, 0xa7, 0x28, 0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39, 0xfc, 0xf0,
1525            0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54, 0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57,
1526            0xa6, 0x37, 0xb3, 0x9b,
1527        ];
1528        let cipher_text = [
1529            0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6, 0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f,
1530            0xb8, 0x94, 0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8, 0xba, 0x26, 0x2a, 0x3c,
1531            0xca, 0x7e, 0x2c, 0xa7, 0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90, 0xcc, 0xdc,
1532            0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f, 0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03,
1533            0x4c, 0x34, 0xae, 0xe5,
1534        ];
1535        let aad = [
1536            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
1537            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
1538        ];
1539        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
1540        let (p, tag) = gcm_aes_decrypt(&cipher_key, &iv, &cipher_text, &aad, &mul_fn);
1541        assert_eq!(
1542            &p,
1543            &[
1544                0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
1545                0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
1546                0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
1547                0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
1548                0xba, 0x63, 0x7b, 0x39
1549            ]
1550        );
1551        assert_eq!(
1552            &tag,
1553            &[
1554                0x61, 0x9c, 0xc5, 0xae, 0xff, 0xfe, 0x0b, 0xfa, 0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99,
1555                0xd0, 0x50
1556            ]
1557        );
1558    }
1559
1560    #[test]
1561    fn test_gcm_aes_256_decrypt() {
1562        //https://luca-giuzzi.unibs.it/corsi/Support/papers-cryptography/gcm-spec.pdf
1563        //Test  Case  13
1564        let cipher_key = [
1565            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1566            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1567            0x00, 0x00, 0x00, 0x00,
1568        ];
1569        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
1570        let iv = [
1571            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1572        ];
1573        let cipher_text = [];
1574        let (p, tag) = gcm_aes_decrypt(&cipher_key, &iv, &cipher_text, &[], &mul_fn);
1575        assert_eq!(&p, &[]);
1576        assert_eq!(
1577            &tag,
1578            &[
1579                0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9, 0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb,
1580                0x73, 0x8b
1581            ]
1582        );
1583
1584        //Test  Case  14
1585        let cipher_key = [
1586            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1587            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1588            0x00, 0x00, 0x00, 0x00,
1589        ];
1590        let iv = [
1591            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1592        ];
1593        let cipher_text = [
1594            0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3,
1595            0x9d, 0x18,
1596        ];
1597        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
1598        let (p, tag) = gcm_aes_decrypt(&cipher_key, &iv, &cipher_text, &"".as_bytes(), &mul_fn);
1599        assert_eq!(
1600            &p,
1601            &[
1602                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1603                0x00, 0x00
1604            ]
1605        );
1606        assert_eq!(
1607            &tag,
1608            &[
1609                0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0, 0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a,
1610                0xb9, 0x19
1611            ]
1612        );
1613
1614        //Test  Case  15
1615        let cipher_key = [
1616            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
1617            0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94,
1618            0x67, 0x30, 0x83, 0x08,
1619        ];
1620        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
1621        let iv = [
1622            0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1623        ];
1624        let cipher_text = [
1625            0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84,
1626            0x42, 0x7d, 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, 0x75, 0x98, 0xa2, 0xbd,
1627            0x25, 0x55, 0xd1, 0xaa, 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, 0xa7, 0xb0,
1628            0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
1629            0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad,
1630        ];
1631        let aad = [];
1632        let (p, tag) = gcm_aes_decrypt(&cipher_key, &iv, &cipher_text, &aad, &mul_fn);
1633        assert_eq!(
1634            &p,
1635            &[
1636                0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
1637                0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
1638                0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
1639                0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
1640                0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55
1641            ]
1642        );
1643        assert_eq!(
1644            &tag,
1645            &[
1646                0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd, 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3,
1647                0xcc, 0x6c
1648            ]
1649        );
1650
1651        //Test  Case  16
1652        let cipher_key = [
1653            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
1654            0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94,
1655            0x67, 0x30, 0x83, 0x08,
1656        ];
1657        let iv = [
1658            0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1659        ];
1660        let cipher_text = [
1661            0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84,
1662            0x42, 0x7d, 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, 0x75, 0x98, 0xa2, 0xbd,
1663            0x25, 0x55, 0xd1, 0xaa, 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, 0xa7, 0xb0,
1664            0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
1665            0xbc, 0xc9, 0xf6, 0x62,
1666        ];
1667        let aad = [
1668            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
1669            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
1670        ];
1671        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
1672        let (p, tag) = gcm_aes_decrypt(&cipher_key, &iv, &cipher_text, &aad, &mul_fn);
1673        assert_eq!(
1674            &p,
1675            &[
1676                0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
1677                0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
1678                0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
1679                0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
1680                0xba, 0x63, 0x7b, 0x39
1681            ]
1682        );
1683        assert_eq!(
1684            &tag,
1685            &[
1686                0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d,
1687                0x55, 0x1b
1688            ]
1689        );
1690
1691        //Test  Case  17
1692        let cipher_key = [
1693            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
1694            0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94,
1695            0x67, 0x30, 0x83, 0x08,
1696        ];
1697        let iv = [0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad];
1698        let cipher_text = [
1699            0xc3, 0x76, 0x2d, 0xf1, 0xca, 0x78, 0x7d, 0x32, 0xae, 0x47, 0xc1, 0x3b, 0xf1, 0x98,
1700            0x44, 0xcb, 0xaf, 0x1a, 0xe1, 0x4d, 0x0b, 0x97, 0x6a, 0xfa, 0xc5, 0x2f, 0xf7, 0xd7,
1701            0x9b, 0xba, 0x9d, 0xe0, 0xfe, 0xb5, 0x82, 0xd3, 0x39, 0x34, 0xa4, 0xf0, 0x95, 0x4c,
1702            0xc2, 0x36, 0x3b, 0xc7, 0x3f, 0x78, 0x62, 0xac, 0x43, 0x0e, 0x64, 0xab, 0xe4, 0x99,
1703            0xf4, 0x7c, 0x9b, 0x1f,
1704        ];
1705        let aad = [
1706            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
1707            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
1708        ];
1709        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
1710        let (p, tag) = gcm_aes_decrypt(&cipher_key, &iv, &cipher_text, &aad, &mul_fn);
1711        assert_eq!(
1712            &p,
1713            &[
1714                0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
1715                0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
1716                0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
1717                0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
1718                0xba, 0x63, 0x7b, 0x39
1719            ]
1720        );
1721        assert_eq!(
1722            &tag,
1723            &[
1724                0x3a, 0x33, 0x7d, 0xbf, 0x46, 0xa7, 0x92, 0xc4, 0x5e, 0x45, 0x49, 0x13, 0xfe, 0x2e,
1725                0xa8, 0xf2
1726            ]
1727        );
1728
1729        //Test  Case  18
1730        let cipher_key = [
1731            0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30,
1732            0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94,
1733            0x67, 0x30, 0x83, 0x08,
1734        ];
1735        let iv = [
1736            0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5, 0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52,
1737            0x69, 0xaa, 0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1, 0xe4, 0xc3, 0x03, 0xd2,
1738            0xa3, 0x18, 0xa7, 0x28, 0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39, 0xfc, 0xf0,
1739            0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54, 0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57,
1740            0xa6, 0x37, 0xb3, 0x9b,
1741        ];
1742        let cipher_text = [
1743            0x5a, 0x8d, 0xef, 0x2f, 0x0c, 0x9e, 0x53, 0xf1, 0xf7, 0x5d, 0x78, 0x53, 0x65, 0x9e,
1744            0x2a, 0x20, 0xee, 0xb2, 0xb2, 0x2a, 0xaf, 0xde, 0x64, 0x19, 0xa0, 0x58, 0xab, 0x4f,
1745            0x6f, 0x74, 0x6b, 0xf4, 0x0f, 0xc0, 0xc3, 0xb7, 0x80, 0xf2, 0x44, 0x45, 0x2d, 0xa3,
1746            0xeb, 0xf1, 0xc5, 0xd8, 0x2c, 0xde, 0xa2, 0x41, 0x89, 0x97, 0x20, 0x0e, 0xf8, 0x2e,
1747            0x44, 0xae, 0x7e, 0x3f,
1748        ];
1749        let aad = [
1750            0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
1751            0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
1752        ];
1753        let mul_fn = GcmBlockMulEnhancement::None.to_mul_fn(&cipher_key);
1754        let (p, tag) = gcm_aes_decrypt(&cipher_key, &iv, &cipher_text, &aad, &mul_fn);
1755        assert_eq!(
1756            &p,
1757            &[
1758                0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5,
1759                0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d,
1760                0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf,
1761                0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
1762                0xba, 0x63, 0x7b, 0x39
1763            ]
1764        );
1765        assert_eq!(
1766            &tag,
1767            &[
1768                0xa4, 0x4a, 0x82, 0x66, 0xee, 0x1c, 0x8e, 0xb0, 0xc8, 0xb5, 0xd4, 0xcf, 0x5a, 0xe9,
1769                0xf1, 0x9a
1770            ]
1771        );
1772    }
1773}
1774