/src/openssl41/crypto/aes/aes_cbc_vaes_intrinsic.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2025-2026 The OpenSSL Project Authors. All Rights Reserved. |
3 | | * Copyright (C) 2026, Advanced Micro Devices, all rights reserved. |
4 | | * |
5 | | * Licensed under the Apache License 2.0 (the "License"). You may not use |
6 | | * this file except in compliance with the License. You can obtain a copy |
7 | | * in the file LICENSE in the source distribution or at |
8 | | * https://www.openssl.org/source/license.html |
9 | | * |
10 | | * Implements AES-CBC128/192/256 decryption with VAES (AVX-512) |
11 | | * |
12 | | * CBC encryption is inherently serial (each ciphertext block depends |
13 | | * on the previous one), so VAES provides no benefit there -- the |
14 | | * encrypt path falls back to the aesni_cbc_encrypt assembly routine. |
15 | | * |
16 | | * CBC decryption IS parallel: all blocks can be independently decrypted, |
17 | | * then XORed with the preceding ciphertext block (or IV for the first). |
18 | | * This implementation processes 4x4=16 blocks per iteration using four |
19 | | * ZMM registers, falling back to 8, 4, then single-block processing. |
20 | | */ |
21 | | |
22 | | #include "internal/deprecated.h" |
23 | | |
24 | | #include <openssl/opensslconf.h> |
25 | | #include "internal/cryptlib.h" |
26 | | #include <openssl/aes.h> |
27 | | #include "crypto/modes.h" |
28 | | #include "crypto/aes_platform.h" |
29 | | |
30 | | #if VAES_CBC_ELIGIBLE |
31 | | |
32 | | /* Function prototypes */ |
33 | | void ossl_aes_cbc_vaes_decrypt(const unsigned char *in, unsigned char *out, |
34 | | size_t len, const void *key, |
35 | | unsigned char ivec[16], int enc); |
36 | | int ossl_aes_cbc_vaes_eligible(void); |
37 | | |
38 | | #include <openssl/modes.h> |
39 | | |
40 | | /* Forward declarations -- defined in aesni-x86_64.pl assembly */ |
41 | | void aesni_cbc_encrypt(const unsigned char *in, unsigned char *out, |
42 | | size_t len, const AES_KEY *key, |
43 | | unsigned char *ivec, int enc); |
44 | | void aesni_decrypt(const unsigned char *in, unsigned char *out, |
45 | | const AES_KEY *key); |
46 | | |
47 | | /* |
48 | | * Keep the cleanup out of line in assembly. Its opacity to C and LTO |
49 | | * optimizers is what prevents the cleanup call and stores from being |
50 | | * eliminated as dead. Do not replace it with a compiler-visible C function. |
51 | | */ |
52 | | void ossl_aes_cbc_vaes_cleanup(void *key_schedule, size_t num_keys); |
53 | | int ossl_aes_cbc_vaes_cleanup_eligible(void); |
54 | | |
55 | | /* Portable compiler abstractions for inlining and ISA target selection */ |
56 | | #define STRINGIFY_IMPL_(a) #a |
57 | | #define STRINGIFY_(a) STRINGIFY_IMPL_(a) |
58 | | |
59 | | #ifdef __clang__ |
60 | | #define OPENSSL_TARGET_VAES512 \ |
61 | | _Pragma(STRINGIFY_(clang attribute push( \ |
62 | | __attribute__((target("avx512f,avx512dq,avx512bw,vaes,aes"))), \ |
63 | | apply_to = function))) |
64 | | #define OPENSSL_UNTARGET_VAES512 _Pragma("clang attribute pop") |
65 | | #elif defined(__GNUC__) |
66 | | #define OPENSSL_TARGET_VAES512 \ |
67 | | _Pragma("GCC push_options") \ |
68 | | _Pragma(STRINGIFY_(GCC target("avx512f,avx512dq,avx512bw,vaes,aes"))) |
69 | | #define OPENSSL_UNTARGET_VAES512 _Pragma("GCC pop_options") |
70 | | #else |
71 | | /* MSVC: all intrinsics are always available via <immintrin.h>. */ |
72 | | #define OPENSSL_TARGET_VAES512 |
73 | | #define OPENSSL_UNTARGET_VAES512 |
74 | | #endif |
75 | | |
76 | | #if defined(__GNUC__) || defined(__clang__) |
77 | | #define OSSL_FUNC_ALWAYS_INLINE static inline __attribute__((always_inline)) |
78 | | #define OSSL_FUNC_NOINLINE __attribute__((noinline)) |
79 | | #elif defined(_MSC_VER) |
80 | | #define OSSL_FUNC_ALWAYS_INLINE static __forceinline |
81 | | #define OSSL_FUNC_NOINLINE __declspec(noinline) |
82 | | #else |
83 | | #define OSSL_FUNC_ALWAYS_INLINE static inline |
84 | | #define OSSL_FUNC_NOINLINE |
85 | | #endif |
86 | | |
87 | | #include <immintrin.h> |
88 | | |
89 | | OPENSSL_TARGET_VAES512 |
90 | | |
91 | | /* ------------------------------------------------------------------ */ |
92 | | /* AES decryption helpers: 1x, 2x, 4x parallel 512-bit blocks */ |
93 | | /* Each 512-bit register holds 4 independent 128-bit AES blocks. */ |
94 | | /* always_inline guarantees the compiler keeps keys in ZMM regs. */ |
95 | | /* ------------------------------------------------------------------ */ |
96 | | |
97 | | #define DEFINE_AES_DECRYPT_FUNCS(ROUNDS) \ |
98 | | OSSL_FUNC_ALWAYS_INLINE \ |
99 | | void AesDec_4x512_##ROUNDS( \ |
100 | | __m512i *b1, __m512i *b2, __m512i *b3, __m512i *b4, \ |
101 | | const __m512i *rk) \ |
102 | 0 | { \ |
103 | 0 | *b1 = _mm512_xor_si512(*b1, rk[0]); \ |
104 | 0 | *b2 = _mm512_xor_si512(*b2, rk[0]); \ |
105 | 0 | *b3 = _mm512_xor_si512(*b3, rk[0]); \ |
106 | 0 | *b4 = _mm512_xor_si512(*b4, rk[0]); \ |
107 | 0 | for (int i = 1; i < ROUNDS; i++) { \ |
108 | 0 | *b1 = _mm512_aesdec_epi128(*b1, rk[i]); \ |
109 | 0 | *b2 = _mm512_aesdec_epi128(*b2, rk[i]); \ |
110 | 0 | *b3 = _mm512_aesdec_epi128(*b3, rk[i]); \ |
111 | 0 | *b4 = _mm512_aesdec_epi128(*b4, rk[i]); \ |
112 | 0 | } \ |
113 | 0 | *b1 = _mm512_aesdeclast_epi128(*b1, rk[ROUNDS]); \ |
114 | 0 | *b2 = _mm512_aesdeclast_epi128(*b2, rk[ROUNDS]); \ |
115 | 0 | *b3 = _mm512_aesdeclast_epi128(*b3, rk[ROUNDS]); \ |
116 | 0 | *b4 = _mm512_aesdeclast_epi128(*b4, rk[ROUNDS]); \ |
117 | 0 | } \ Unexecuted instantiation: aes_cbc_vaes_intrinsic.c:AesDec_4x512_10 Unexecuted instantiation: aes_cbc_vaes_intrinsic.c:AesDec_4x512_12 Unexecuted instantiation: aes_cbc_vaes_intrinsic.c:AesDec_4x512_14 |
118 | | \ |
119 | | OSSL_FUNC_ALWAYS_INLINE \ |
120 | | void AesDec_2x512_##ROUNDS( \ |
121 | | __m512i *b1, __m512i *b2, const __m512i *rk) \ |
122 | 0 | { \ |
123 | 0 | *b1 = _mm512_xor_si512(*b1, rk[0]); \ |
124 | 0 | *b2 = _mm512_xor_si512(*b2, rk[0]); \ |
125 | 0 | for (int i = 1; i < ROUNDS; i++) { \ |
126 | 0 | *b1 = _mm512_aesdec_epi128(*b1, rk[i]); \ |
127 | 0 | *b2 = _mm512_aesdec_epi128(*b2, rk[i]); \ |
128 | 0 | } \ |
129 | 0 | *b1 = _mm512_aesdeclast_epi128(*b1, rk[ROUNDS]); \ |
130 | 0 | *b2 = _mm512_aesdeclast_epi128(*b2, rk[ROUNDS]); \ |
131 | 0 | } \ Unexecuted instantiation: aes_cbc_vaes_intrinsic.c:AesDec_2x512_10 Unexecuted instantiation: aes_cbc_vaes_intrinsic.c:AesDec_2x512_12 Unexecuted instantiation: aes_cbc_vaes_intrinsic.c:AesDec_2x512_14 |
132 | | \ |
133 | | OSSL_FUNC_ALWAYS_INLINE \ |
134 | | void AesDec_1x512_##ROUNDS( \ |
135 | | __m512i *b1, const __m512i *rk) \ |
136 | 0 | { \ |
137 | 0 | *b1 = _mm512_xor_si512(*b1, rk[0]); \ |
138 | 0 | for (int i = 1; i < ROUNDS; i++) \ |
139 | 0 | *b1 = _mm512_aesdec_epi128(*b1, rk[i]); \ |
140 | 0 | *b1 = _mm512_aesdeclast_epi128(*b1, rk[ROUNDS]); \ |
141 | 0 | } Unexecuted instantiation: aes_cbc_vaes_intrinsic.c:AesDec_1x512_10 Unexecuted instantiation: aes_cbc_vaes_intrinsic.c:AesDec_1x512_12 Unexecuted instantiation: aes_cbc_vaes_intrinsic.c:AesDec_1x512_14 |
142 | | |
143 | | DEFINE_AES_DECRYPT_FUNCS(10) /* AES-128 */ |
144 | | DEFINE_AES_DECRYPT_FUNCS(12) /* AES-192 */ |
145 | | DEFINE_AES_DECRYPT_FUNCS(14) /* AES-256 */ |
146 | | |
147 | | /* ------------------------------------------------------------------ */ |
148 | | /* CBC-mode decryption -- templated per round count */ |
149 | | /* */ |
150 | | /* Processes as many full blocks as possible: */ |
151 | | /* 16 blocks at a time (4 x zmm = 4 x 4 = 16 blocks) */ |
152 | | /* 8 blocks at a time (2 x zmm) */ |
153 | | /* 4 blocks at a time (1 x zmm) */ |
154 | | /* 1 block at a time for the remaining 0-3 blocks */ |
155 | | /* */ |
156 | | /* The chaining vector b1 packs [prev_ct[last] | ct[0] | ct[1] */ |
157 | | /* | ct[2]] so that a single XOR after decryption applies the CBC */ |
158 | | /* feedback to all four lanes simultaneously. */ |
159 | | /* ------------------------------------------------------------------ */ |
160 | | |
161 | | #define DEFINE_CBC_DECRYPT(NR) \ |
162 | | OSSL_FUNC_NOINLINE \ |
163 | | static void cbc_decrypt_##NR( \ |
164 | | const unsigned char *in, unsigned char *out, size_t len, \ |
165 | | const AES_KEY *key, unsigned char *iv) \ |
166 | 0 | { \ |
167 | 0 | const unsigned char *rk_bytes = (const unsigned char *)key->rd_key; \ |
168 | 0 | __m512i rk[NR + 1]; \ |
169 | 0 | for (int i = 0; i <= NR; i++) { \ |
170 | 0 | __m128i t = _mm_loadu_si128((const __m128i *)(rk_bytes + i * 16)); \ |
171 | 0 | rk[i] = _mm512_broadcast_i32x4(t); \ |
172 | 0 | } \ |
173 | 0 | \ |
174 | 0 | __m512i a1, a2, a3, a4; \ |
175 | 0 | __m512i b1, b2, b3, b4; \ |
176 | 0 | \ |
177 | 0 | const __m128i *pa = (const __m128i *)in; \ |
178 | 0 | __m512i *po = (__m512i *)out; \ |
179 | 0 | size_t blocks = len / AES_BLOCK_SIZE; \ |
180 | 0 | \ |
181 | 0 | /* Save last ciphertext block for IV update (in-place safe) */ \ |
182 | 0 | __m128i saved_iv = _mm_setzero_si128(); \ |
183 | 0 | int has_blocks = (blocks > 0); \ |
184 | 0 | if (has_blocks) \ |
185 | 0 | saved_iv = _mm_loadu_si128(pa + blocks - 1); \ |
186 | 0 | \ |
187 | 0 | if (blocks >= 4) { \ |
188 | 0 | /* Build b1 = [IV | ct[0] | ct[1] | ct[2]] */ \ |
189 | 0 | __m512i idx = _mm512_set_epi64(5, 4, 3, 2, 1, 0, 0, 0); \ |
190 | 0 | __m512i ct0; \ |
191 | 0 | \ |
192 | 0 | /* CBC C[0]=IV; 0x03 loads one 128-bit block (two 64-bit lanes). */ \ |
193 | 0 | b1 = _mm512_maskz_loadu_epi64(0x03, iv); \ |
194 | 0 | ct0 = _mm512_loadu_si512(pa); \ |
195 | 0 | ct0 = _mm512_permutexvar_epi64(idx, ct0); \ |
196 | 0 | b1 = _mm512_mask_blend_epi64(0xFC, b1, ct0); \ |
197 | 0 | \ |
198 | 0 | /* --- 16-block (4 x zmm) main loop --- */ \ |
199 | 0 | while (blocks >= 16) { \ |
200 | 0 | __m128i last; \ |
201 | 0 | \ |
202 | 0 | a1 = _mm512_loadu_si512(pa); \ |
203 | 0 | a2 = _mm512_loadu_si512(pa + 4); \ |
204 | 0 | a3 = _mm512_loadu_si512(pa + 8); \ |
205 | 0 | a4 = _mm512_loadu_si512(pa + 12); \ |
206 | 0 | \ |
207 | 0 | b2 = _mm512_loadu_si512(pa + 3); \ |
208 | 0 | b3 = _mm512_loadu_si512(pa + 7); \ |
209 | 0 | b4 = _mm512_loadu_si512(pa + 11); \ |
210 | 0 | \ |
211 | 0 | last = _mm_loadu_si128(pa + 15); \ |
212 | 0 | \ |
213 | 0 | AesDec_4x512_##NR(&a1, &a2, &a3, &a4, rk); \ |
214 | 0 | \ |
215 | 0 | a1 = _mm512_xor_si512(a1, b1); \ |
216 | 0 | a2 = _mm512_xor_si512(a2, b2); \ |
217 | 0 | a3 = _mm512_xor_si512(a3, b3); \ |
218 | 0 | a4 = _mm512_xor_si512(a4, b4); \ |
219 | 0 | \ |
220 | 0 | _mm512_storeu_si512(po, a1); \ |
221 | 0 | _mm512_storeu_si512(po + 1, a2); \ |
222 | 0 | _mm512_storeu_si512(po + 2, a3); \ |
223 | 0 | _mm512_storeu_si512(po + 3, a4); \ |
224 | 0 | \ |
225 | 0 | /* Build next b1 from last ciphertext block */ \ |
226 | 0 | b1 = _mm512_maskz_loadu_epi64(0x03, &last); \ |
227 | 0 | if (blocks > 16) { \ |
228 | 0 | size_t rem = blocks - 16; \ |
229 | 0 | /* Load only available lookahead blocks to avoid OOB read. */ \ |
230 | 0 | /* One AES block is 16 bytes, it maps to two 64-bit lanes. */ \ |
231 | 0 | /* 0x03 (00000011) for 1 block (2 lanes), */ \ |
232 | 0 | /* 0x0F (00001111) for 2 blocks (4 lanes), */ \ |
233 | 0 | /* 0x3F (00111111) for 3 or more blocks (6 lanes). */ \ |
234 | 0 | __mmask8 nxmask = (rem >= 3) ? 0x3F : (rem == 2 ? 0x0F : 0x03); \ |
235 | 0 | __m512i nx = _mm512_maskz_loadu_epi64(nxmask, pa + 16); \ |
236 | 0 | nx = _mm512_permutexvar_epi64(idx, nx); \ |
237 | 0 | b1 = _mm512_mask_blend_epi64(0xFC, b1, nx); \ |
238 | 0 | } \ |
239 | 0 | \ |
240 | 0 | pa += 16; \ |
241 | 0 | po += 4; \ |
242 | 0 | blocks -= 16; \ |
243 | 0 | } \ |
244 | 0 | \ |
245 | 0 | /* --- 8-block (2 x zmm) --- */ \ |
246 | 0 | if (blocks >= 8) { \ |
247 | 0 | __m128i last8; \ |
248 | 0 | \ |
249 | 0 | a1 = _mm512_loadu_si512(pa); \ |
250 | 0 | a2 = _mm512_loadu_si512(pa + 4); \ |
251 | 0 | b2 = _mm512_loadu_si512(pa + 3); \ |
252 | 0 | last8 = _mm_loadu_si128(pa + 7); \ |
253 | 0 | \ |
254 | 0 | AesDec_2x512_##NR(&a1, &a2, rk); \ |
255 | 0 | a1 = _mm512_xor_si512(a1, b1); \ |
256 | 0 | a2 = _mm512_xor_si512(a2, b2); \ |
257 | 0 | \ |
258 | 0 | _mm512_storeu_si512(po, a1); \ |
259 | 0 | _mm512_storeu_si512(po + 1, a2); \ |
260 | 0 | \ |
261 | 0 | b1 = _mm512_maskz_loadu_epi64(0x03, &last8); \ |
262 | 0 | pa += 8; \ |
263 | 0 | po += 2; \ |
264 | 0 | blocks -= 8; \ |
265 | 0 | \ |
266 | 0 | if (blocks >= 4) { \ |
267 | 0 | __m512i nx = _mm512_loadu_si512(pa); \ |
268 | 0 | nx = _mm512_permutexvar_epi64(idx, nx); \ |
269 | 0 | b1 = _mm512_mask_blend_epi64(0xFC, b1, nx); \ |
270 | 0 | } \ |
271 | 0 | } \ |
272 | 0 | \ |
273 | 0 | /* --- 4-block (1 x zmm) --- */ \ |
274 | 0 | if (blocks >= 4) { \ |
275 | 0 | __m128i last4; \ |
276 | 0 | \ |
277 | 0 | a1 = _mm512_loadu_si512(pa); \ |
278 | 0 | last4 = _mm_loadu_si128(pa + 3); \ |
279 | 0 | \ |
280 | 0 | AesDec_1x512_##NR(&a1, rk); \ |
281 | 0 | a1 = _mm512_xor_si512(a1, b1); \ |
282 | 0 | _mm512_storeu_si512(po, a1); \ |
283 | 0 | \ |
284 | 0 | b1 = _mm512_maskz_loadu_epi64(0x03, &last4); \ |
285 | 0 | pa += 4; \ |
286 | 0 | po += 1; \ |
287 | 0 | blocks -= 4; \ |
288 | 0 | } \ |
289 | 0 | \ |
290 | 0 | /* --- Remaining 1-3 blocks --- */ \ |
291 | 0 | { \ |
292 | 0 | __m128i *po128 = (__m128i *)po; \ |
293 | 0 | while (blocks > 0) { \ |
294 | 0 | __m128i ct = _mm_loadu_si128(pa); \ |
295 | 0 | a1 = _mm512_maskz_loadu_epi64(0x03, pa); \ |
296 | 0 | AesDec_1x512_##NR(&a1, rk); \ |
297 | 0 | a1 = _mm512_xor_si512(a1, b1); \ |
298 | 0 | _mm512_mask_storeu_epi64(po128, 0x03, a1); \ |
299 | 0 | b1 = _mm512_maskz_loadu_epi64(0x03, &ct); \ |
300 | 0 | pa++; \ |
301 | 0 | po128++; \ |
302 | 0 | blocks--; \ |
303 | 0 | } \ |
304 | 0 | } \ |
305 | 0 | } else { \ |
306 | 0 | /* Less than 4 blocks -- process individually */ \ |
307 | 0 | __m128i *po128 = (__m128i *)po; \ |
308 | 0 | b1 = _mm512_maskz_loadu_epi64(0x03, iv); \ |
309 | 0 | while (blocks > 0) { \ |
310 | 0 | __m128i ct = _mm_loadu_si128(pa); \ |
311 | 0 | a1 = _mm512_maskz_loadu_epi64(0x03, pa); \ |
312 | 0 | AesDec_1x512_##NR(&a1, rk); \ |
313 | 0 | a1 = _mm512_xor_si512(a1, b1); \ |
314 | 0 | _mm512_mask_storeu_epi64(po128, 0x03, a1); \ |
315 | 0 | b1 = _mm512_maskz_loadu_epi64(0x03, &ct); \ |
316 | 0 | pa++; \ |
317 | 0 | po128++; \ |
318 | 0 | blocks--; \ |
319 | 0 | } \ |
320 | 0 | } \ |
321 | 0 | \ |
322 | 0 | if (has_blocks) \ |
323 | 0 | _mm_storeu_si128((__m128i *)iv, saved_iv); \ |
324 | 0 | \ |
325 | 0 | /* Erase the broadcast schedule and the volatile vector register bank. */ \ |
326 | 0 | ossl_aes_cbc_vaes_cleanup(rk, NR + 1); \ |
327 | 0 | } Unexecuted instantiation: aes_cbc_vaes_intrinsic.c:cbc_decrypt_10 Unexecuted instantiation: aes_cbc_vaes_intrinsic.c:cbc_decrypt_12 Unexecuted instantiation: aes_cbc_vaes_intrinsic.c:cbc_decrypt_14 |
328 | | |
329 | | DEFINE_CBC_DECRYPT(10) /* AES-128 */ |
330 | | DEFINE_CBC_DECRYPT(12) /* AES-192 */ |
331 | | DEFINE_CBC_DECRYPT(14) /* AES-256 */ |
332 | | |
333 | | /* ------------------------------------------------------------------ */ |
334 | | /* Public entry point */ |
335 | | /* ------------------------------------------------------------------ */ |
336 | | |
337 | | void ossl_aes_cbc_vaes_decrypt(const unsigned char *in, unsigned char *out, |
338 | | size_t len, const void *key, |
339 | | unsigned char ivec[16], int enc) |
340 | 0 | { |
341 | 0 | size_t full_bytes; |
342 | 0 | int nr = ((const AES_KEY *)key)->rounds + 1; |
343 | |
|
344 | 0 | if (len == 0) |
345 | 0 | return; |
346 | | |
347 | | /* VAES path only optimises decryption; encrypt falls back to asm */ |
348 | 0 | if (enc) { |
349 | 0 | aesni_cbc_encrypt(in, out, len, (const AES_KEY *)key, ivec, enc); |
350 | 0 | return; |
351 | 0 | } |
352 | | |
353 | 0 | full_bytes = (len / AES_BLOCK_SIZE) * AES_BLOCK_SIZE; |
354 | 0 | if (full_bytes > 0) { |
355 | 0 | switch (nr) { |
356 | 0 | case 10: |
357 | 0 | cbc_decrypt_10(in, out, full_bytes, (const AES_KEY *)key, ivec); |
358 | 0 | break; |
359 | 0 | case 12: |
360 | 0 | cbc_decrypt_12(in, out, full_bytes, (const AES_KEY *)key, ivec); |
361 | 0 | break; |
362 | 0 | case 14: |
363 | 0 | cbc_decrypt_14(in, out, full_bytes, (const AES_KEY *)key, ivec); |
364 | 0 | break; |
365 | 0 | default: /* invalid key size */ |
366 | 0 | aesni_cbc_encrypt(in, out, len, (const AES_KEY *)key, ivec, 0); |
367 | 0 | break; |
368 | 0 | } |
369 | 0 | } |
370 | 0 | } |
371 | | |
372 | | /* ------------------------------------------------------------------ */ |
373 | | /* CPU feature check */ |
374 | | /* ------------------------------------------------------------------ */ |
375 | | |
376 | | int ossl_aes_cbc_vaes_eligible(void) |
377 | 879 | { |
378 | 879 | return ossl_aes_cbc_vaes_cleanup_eligible() |
379 | 879 | && (OPENSSL_ia32cap_P[2] & (1 << 16)) /* AVX512F */ |
380 | 0 | && (OPENSSL_ia32cap_P[2] & (1 << 17)) /* AVX512DQ */ |
381 | 0 | && (OPENSSL_ia32cap_P[2] & (1 << 30)) /* AVX512BW */ |
382 | 0 | && (OPENSSL_ia32cap_P[3] & (1 << 9)); /* AVX512VAES */ |
383 | 879 | } |
384 | | |
385 | | OPENSSL_UNTARGET_VAES512 |
386 | | |
387 | | #undef OPENSSL_TARGET_VAES512 |
388 | | #undef OPENSSL_UNTARGET_VAES512 |
389 | | #undef STRINGIFY_IMPL_ |
390 | | #undef STRINGIFY_ |
391 | | #undef OSSL_FUNC_ALWAYS_INLINE |
392 | | #undef OSSL_FUNC_NOINLINE |
393 | | #endif /* VAES_CBC_ELIGIBLE */ |