stdarch icon indicating copy to clipboard operation
stdarch copied to clipboard

Adding Key Locker intrinsics

Open ethindp opened this issue 4 years ago • 5 comments

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?

ethindp avatar Sep 25 '21 08:09 ethindp

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.

Amanieu avatar Sep 25 '21 16:09 Amanieu

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);
}

ethindp avatar Sep 26 '21 01:09 ethindp

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.

Amanieu avatar Sep 26 '21 08:09 Amanieu

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?

ethindp avatar Sep 27 '21 00:09 ethindp

I'd recommend having a look at crates/core_arch/src/x86/aes.rs as an example of what to do.

Amanieu avatar Sep 28 '21 22:09 Amanieu