1 | //! AES New Instructions (AES-NI) |
2 | //! |
3 | //! The intrinsics here correspond to those in the `wmmintrin.h` C header. |
4 | //! |
5 | //! The reference is [Intel 64 and IA-32 Architectures Software Developer's |
6 | //! Manual Volume 2: Instruction Set Reference, A-Z][intel64_ref]. |
7 | //! |
8 | //! [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf |
9 | |
10 | use crate::core_arch::x86::__m128i; |
11 | |
12 | #[cfg (test)] |
13 | use stdarch_test::assert_instr; |
14 | |
15 | #[allow (improper_ctypes)] |
16 | extern "C" { |
17 | #[link_name = "llvm.x86.aesni.aesdec" ] |
18 | fn aesdec(a: __m128i, round_key: __m128i) -> __m128i; |
19 | #[link_name = "llvm.x86.aesni.aesdeclast" ] |
20 | fn aesdeclast(a: __m128i, round_key: __m128i) -> __m128i; |
21 | #[link_name = "llvm.x86.aesni.aesenc" ] |
22 | fn aesenc(a: __m128i, round_key: __m128i) -> __m128i; |
23 | #[link_name = "llvm.x86.aesni.aesenclast" ] |
24 | fn aesenclast(a: __m128i, round_key: __m128i) -> __m128i; |
25 | #[link_name = "llvm.x86.aesni.aesimc" ] |
26 | fn aesimc(a: __m128i) -> __m128i; |
27 | #[link_name = "llvm.x86.aesni.aeskeygenassist" ] |
28 | fn aeskeygenassist(a: __m128i, imm8: u8) -> __m128i; |
29 | } |
30 | |
31 | /// Performs one round of an AES decryption flow on data (state) in `a`. |
32 | /// |
33 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdec_si128) |
34 | #[inline ] |
35 | #[target_feature (enable = "aes" )] |
36 | #[cfg_attr (test, assert_instr(aesdec))] |
37 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
38 | pub unsafe fn _mm_aesdec_si128(a: __m128i, round_key: __m128i) -> __m128i { |
39 | aesdec(a, round_key) |
40 | } |
41 | |
42 | /// Performs the last round of an AES decryption flow on data (state) in `a`. |
43 | /// |
44 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdeclast_si128) |
45 | #[inline ] |
46 | #[target_feature (enable = "aes" )] |
47 | #[cfg_attr (test, assert_instr(aesdeclast))] |
48 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
49 | pub unsafe fn _mm_aesdeclast_si128(a: __m128i, round_key: __m128i) -> __m128i { |
50 | aesdeclast(a, round_key) |
51 | } |
52 | |
53 | /// Performs one round of an AES encryption flow on data (state) in `a`. |
54 | /// |
55 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenc_si128) |
56 | #[inline ] |
57 | #[target_feature (enable = "aes" )] |
58 | #[cfg_attr (test, assert_instr(aesenc))] |
59 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
60 | pub unsafe fn _mm_aesenc_si128(a: __m128i, round_key: __m128i) -> __m128i { |
61 | aesenc(a, round_key) |
62 | } |
63 | |
64 | /// Performs the last round of an AES encryption flow on data (state) in `a`. |
65 | /// |
66 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenclast_si128) |
67 | #[inline ] |
68 | #[target_feature (enable = "aes" )] |
69 | #[cfg_attr (test, assert_instr(aesenclast))] |
70 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
71 | pub unsafe fn _mm_aesenclast_si128(a: __m128i, round_key: __m128i) -> __m128i { |
72 | aesenclast(a, round_key) |
73 | } |
74 | |
75 | /// Performs the `InvMixColumns` transformation on `a`. |
76 | /// |
77 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesimc_si128) |
78 | #[inline ] |
79 | #[target_feature (enable = "aes" )] |
80 | #[cfg_attr (test, assert_instr(aesimc))] |
81 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
82 | pub unsafe fn _mm_aesimc_si128(a: __m128i) -> __m128i { |
83 | aesimc(a) |
84 | } |
85 | |
86 | /// Assist in expanding the AES cipher key. |
87 | /// |
88 | /// Assist in expanding the AES cipher key by computing steps towards |
89 | /// generating a round key for encryption cipher using data from `a` and an |
90 | /// 8-bit round constant `IMM8`. |
91 | /// |
92 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aeskeygenassist_si128) |
93 | #[inline ] |
94 | #[target_feature (enable = "aes" )] |
95 | #[cfg_attr (test, assert_instr(aeskeygenassist, IMM8 = 0))] |
96 | #[rustc_legacy_const_generics (1)] |
97 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
98 | pub unsafe fn _mm_aeskeygenassist_si128<const IMM8: i32>(a: __m128i) -> __m128i { |
99 | static_assert_uimm_bits!(IMM8, 8); |
100 | aeskeygenassist(a, IMM8 as u8) |
101 | } |
102 | |
103 | #[cfg (test)] |
104 | mod tests { |
105 | // The constants in the tests below are just bit patterns. They should not |
106 | // be interpreted as integers; signedness does not make sense for them, but |
107 | // __m128i happens to be defined in terms of signed integers. |
108 | #![allow (overflowing_literals)] |
109 | |
110 | use stdarch_test::simd_test; |
111 | |
112 | use crate::core_arch::x86::*; |
113 | |
114 | #[simd_test(enable = "aes" )] |
115 | unsafe fn test_mm_aesdec_si128() { |
116 | // Constants taken from https://msdn.microsoft.com/en-us/library/cc664949.aspx. |
117 | let a = _mm_set_epi64x(0x0123456789abcdef, 0x8899aabbccddeeff); |
118 | let k = _mm_set_epi64x(0x1133557799bbddff, 0x0022446688aaccee); |
119 | let e = _mm_set_epi64x(0x044e4f5176fec48f, 0xb57ecfa381da39ee); |
120 | let r = _mm_aesdec_si128(a, k); |
121 | assert_eq_m128i(r, e); |
122 | } |
123 | |
124 | #[simd_test(enable = "aes" )] |
125 | unsafe fn test_mm_aesdeclast_si128() { |
126 | // Constants taken from https://msdn.microsoft.com/en-us/library/cc714178.aspx. |
127 | let a = _mm_set_epi64x(0x0123456789abcdef, 0x8899aabbccddeeff); |
128 | let k = _mm_set_epi64x(0x1133557799bbddff, 0x0022446688aaccee); |
129 | let e = _mm_set_epi64x(0x36cad57d9072bf9e, 0xf210dd981fa4a493); |
130 | let r = _mm_aesdeclast_si128(a, k); |
131 | assert_eq_m128i(r, e); |
132 | } |
133 | |
134 | #[simd_test(enable = "aes" )] |
135 | unsafe fn test_mm_aesenc_si128() { |
136 | // Constants taken from https://msdn.microsoft.com/en-us/library/cc664810.aspx. |
137 | let a = _mm_set_epi64x(0x0123456789abcdef, 0x8899aabbccddeeff); |
138 | let k = _mm_set_epi64x(0x1133557799bbddff, 0x0022446688aaccee); |
139 | let e = _mm_set_epi64x(0x16ab0e57dfc442ed, 0x28e4ee1884504333); |
140 | let r = _mm_aesenc_si128(a, k); |
141 | assert_eq_m128i(r, e); |
142 | } |
143 | |
144 | #[simd_test(enable = "aes" )] |
145 | unsafe fn test_mm_aesenclast_si128() { |
146 | // Constants taken from https://msdn.microsoft.com/en-us/library/cc714136.aspx. |
147 | let a = _mm_set_epi64x(0x0123456789abcdef, 0x8899aabbccddeeff); |
148 | let k = _mm_set_epi64x(0x1133557799bbddff, 0x0022446688aaccee); |
149 | let e = _mm_set_epi64x(0xb6dd7df25d7ab320, 0x4b04f98cf4c860f8); |
150 | let r = _mm_aesenclast_si128(a, k); |
151 | assert_eq_m128i(r, e); |
152 | } |
153 | |
154 | #[simd_test(enable = "aes" )] |
155 | unsafe fn test_mm_aesimc_si128() { |
156 | // Constants taken from https://msdn.microsoft.com/en-us/library/cc714195.aspx. |
157 | let a = _mm_set_epi64x(0x0123456789abcdef, 0x8899aabbccddeeff); |
158 | let e = _mm_set_epi64x(0xc66c82284ee40aa0, 0x6633441122770055); |
159 | let r = _mm_aesimc_si128(a); |
160 | assert_eq_m128i(r, e); |
161 | } |
162 | |
163 | #[simd_test(enable = "aes" )] |
164 | unsafe fn test_mm_aeskeygenassist_si128() { |
165 | // Constants taken from https://msdn.microsoft.com/en-us/library/cc714138.aspx. |
166 | let a = _mm_set_epi64x(0x0123456789abcdef, 0x8899aabbccddeeff); |
167 | let e = _mm_set_epi64x(0x857c266b7c266e85, 0xeac4eea9c4eeacea); |
168 | let r = _mm_aeskeygenassist_si128::<5>(a); |
169 | assert_eq_m128i(r, e); |
170 | } |
171 | } |
172 | |