Adding Key Locker intrinsics
So, Intel recently released the Intel Key Locker specification, defining new functionality within new Intel CPUs for the AES cryptographic domain. These are the AESENCKL, AESENCWIDEKL, AESDECKL, AESDECWIDEKL, ENCODEKEY*, and LOADIWKEY instructions. These use SIMD vectors and SIMD technology, however I don't know if they fit into a particular target feature domain (e.g. SSE). I would presume, however, that they are at least SSE2. Clang does not (yet) appear to implement them though, and I don't think any processors exist (at least within the consumer market) that implement Intel KL, so we'd need to mock the tests somehow. Is it worth implementing KL intrinsics at this time?
We first need these intrinsics to be implemented in Clang because we need LLVM to support these instructions. After that, it should be fairly straightforward to port them to Rust.
As of commit 413577a87904, Clang supports key locker. I'm just unsure how to port them -- they use pointers. Are there any special rules I need to follow to port them to Rust? Or can I just use *mut c_void? According to Clang, the handles are __m128s, or are type-cast to __m128s:
/// Wrap a 128-bit AES key from __key into a key handle and output in
/// ((__m128i*)__h) to ((__m128i*)__h) + 2 and a 32-bit value as return.
/// The explicit source operand __htype specifies handle restrictions.
///
/// \headerfile <x86intrin.h>
///
/// This intrinsic corresponds to the <c> ENCODEKEY128 </c> instructions.
///
/// \operation
/// InputKey[127:0] := __key[127:0]
/// KeyMetadata[2:0] := __htype[2:0]
/// KeyMetadata[23:3] := 0 // Reserved for future usage
/// KeyMetadata[27:24] := 0 // KeyType is AES-128 (value of 0)
/// KeyMetadata[127:28] := 0 // Reserved for future usage
/// Handle[383:0] := WrapKey128(InputKey[127:0], KeyMetadata[127:0],
/// IWKey.Integrity Key[127:0], IWKey.Encryption Key[255:0])
/// dst[0] := IWKey.NoBackup
/// dst[4:1] := IWKey.KeySource[3:0]
/// dst[31:5] := 0
/// MEM[__h+127:__h] := Handle[127:0] // AAD
/// MEM[__h+255:__h+128] := Handle[255:128] // Integrity Tag
/// MEM[__h+383:__h+256] := Handle[383:256] // CipherText
/// OF := 0
/// SF := 0
/// ZF := 0
/// AF := 0
/// PF := 0
/// CF := 0
/// \endoperation
static __inline__ unsigned int __DEFAULT_FN_ATTRS
_mm_encodekey128_u32(unsigned int __htype, __m128i __key, void *__h) {
return __builtin_ia32_encodekey128_u32(__htype, (__v2di)__key, __h);
}
You can use *mut u8 for void pointers. You can find the definitions of the LLVM intrinsics that you need to link to in llvm/test/CodeGen/X86/keylocker-intrinsics.ll. They take multiple arguments and return a struct of multiple values.
Okay, so I've found the intrinsics to link to (llvm.x86.loadiwkey, llvm.x86.encodekey128, llvm.x86.encodekey256, llvm.x86.aesenc128kl, llvm.x86.aesdec128kl, llvm.x86.aesenc256kl, llvm.x86.aesdec256kl, llvm.x86.aesencwide128kl, llvm.x86.aesdecwide128kl, llvm.x86.aesencwide256kl, and llvm.x86.aesdecwide256kl). Why do I need these and what's next?
I'd recommend having a look at crates/core_arch/src/x86/aes.rs as an example of what to do.