[PATCH] target/riscv: Use existing lookup tables for AES MixColumns

Ard Biesheuvel posted 1 patch 9 months, 1 week ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20230727070303.1220037-1-ardb@kernel.org
Maintainers: "Daniel P. Berrangé" <berrange@redhat.com>, Palmer Dabbelt <palmer@dabbelt.com>, Alistair Francis <alistair.francis@wdc.com>, Bin Meng <bin.meng@windriver.com>, Weiwei Li <liweiwei@iscas.ac.cn>, Daniel Henrique Barboza <dbarboza@ventanamicro.com>, Liu Zhiwei <zhiwei_liu@linux.alibaba.com>
crypto/aes.c                 |  5 ++--
include/crypto/aes.h         |  7 +++++
target/riscv/crypto_helper.c | 30 ++++----------------
3 files changed, 14 insertions(+), 28 deletions(-)
[PATCH] target/riscv: Use existing lookup tables for AES MixColumns
Posted by Ard Biesheuvel 9 months, 1 week ago
The AES MixColumns and InvMixColumns operations are relatively
expensive 4x4 matrix multiplications in GF(2^8), which is why C
implementations usually rely on precomputed lookup tables rather than
performing the calculations on demand.

Given that we already carry those tables in QEMU, we can just grab the
right value in the implementation of the RISC-V AES32 instructions. Note
that the tables in question are permuted according to the respective
Sbox, so we can omit the Sbox lookup as well in this case.

Cc: Richard Henderson <richard.henderson@linaro.org>
Cc: Philippe Mathieu-Daudé <philmd@linaro.org>
Cc: Zewen Ye <lustrew@foxmail.com>
Cc: Weiwei Li <liweiwei@iscas.ac.cn>
Cc: Junqiang Wang <wangjunqiang@iscas.ac.cn>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 crypto/aes.c                 |  5 ++--
 include/crypto/aes.h         |  7 +++++
 target/riscv/crypto_helper.c | 30 ++++----------------
 3 files changed, 14 insertions(+), 28 deletions(-)

diff --git a/crypto/aes.c b/crypto/aes.c
index 836d7d5c0bf1b392..27d7e1a22dfe8c74 100644
--- a/crypto/aes.c
+++ b/crypto/aes.c
@@ -272,7 +272,7 @@ AES_Td3[x] = Si[x].[09, 0d, 0b, 0e];
 AES_Td4[x] = Si[x].[01, 01, 01, 01];
 */
 
-static const uint32_t AES_Te0[256] = {
+const uint32_t AES_Te0[256] = {
     0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
     0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
     0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
@@ -606,8 +606,7 @@ static const uint32_t AES_Te4[256] = {
     0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
     0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
 };
-
-static const uint32_t AES_Td0[256] = {
+const uint32_t AES_Td0[256] = {
     0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
     0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
     0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
diff --git a/include/crypto/aes.h b/include/crypto/aes.h
index 709d4d226bfe158b..381f24c9022d2aa8 100644
--- a/include/crypto/aes.h
+++ b/include/crypto/aes.h
@@ -30,4 +30,11 @@ void AES_decrypt(const unsigned char *in, unsigned char *out,
 extern const uint8_t AES_sbox[256];
 extern const uint8_t AES_isbox[256];
 
+/*
+AES_Te0[x] = S [x].[02, 01, 01, 03];
+AES_Td0[x] = Si[x].[0e, 09, 0d, 0b];
+*/
+
+extern const uint32_t AES_Te0[256], AES_Td0[256];
+
 #endif
diff --git a/target/riscv/crypto_helper.c b/target/riscv/crypto_helper.c
index 99d85a618843e87e..40f95c71cef45877 100644
--- a/target/riscv/crypto_helper.c
+++ b/target/riscv/crypto_helper.c
@@ -25,29 +25,6 @@
 #include "crypto/aes-round.h"
 #include "crypto/sm4.h"
 
-#define AES_XTIME(a) \
-    ((a << 1) ^ ((a & 0x80) ? 0x1b : 0))
-
-#define AES_GFMUL(a, b) (( \
-    (((b) & 0x1) ? (a) : 0) ^ \
-    (((b) & 0x2) ? AES_XTIME(a) : 0) ^ \
-    (((b) & 0x4) ? AES_XTIME(AES_XTIME(a)) : 0) ^ \
-    (((b) & 0x8) ? AES_XTIME(AES_XTIME(AES_XTIME(a))) : 0)) & 0xFF)
-
-static inline uint32_t aes_mixcolumn_byte(uint8_t x, bool fwd)
-{
-    uint32_t u;
-
-    if (fwd) {
-        u = (AES_GFMUL(x, 3) << 24) | (x << 16) | (x << 8) |
-            (AES_GFMUL(x, 2) << 0);
-    } else {
-        u = (AES_GFMUL(x, 0xb) << 24) | (AES_GFMUL(x, 0xd) << 16) |
-            (AES_GFMUL(x, 0x9) << 8) | (AES_GFMUL(x, 0xe) << 0);
-    }
-    return u;
-}
-
 #define sext32_xlen(x) (target_ulong)(int32_t)(x)
 
 static inline target_ulong aes32_operation(target_ulong shamt,
@@ -62,18 +39,21 @@ static inline target_ulong aes32_operation(target_ulong shamt,
     if (enc) {
         so = AES_sbox[si];
         if (mix) {
-            mixed = aes_mixcolumn_byte(so, true);
+            mixed = AES_Te0[si];
         } else {
             mixed = so;
         }
     } else {
         so = AES_isbox[si];
         if (mix) {
-            mixed = aes_mixcolumn_byte(so, false);
+            mixed = AES_Td0[si];
         } else {
             mixed = so;
         }
     }
+    if (!HOST_BIG_ENDIAN && mix) {
+        mixed = bswap32(mixed);
+    }
     mixed = rol32(mixed, shamt);
     res = rs1 ^ mixed;
 
-- 
2.39.2


Re: [PATCH] target/riscv: Use existing lookup tables for AES MixColumns
Posted by Richard Henderson 9 months, 1 week ago
On 7/27/23 00:03, Ard Biesheuvel wrote:
> @@ -606,8 +606,7 @@ static const uint32_t AES_Te4[256] = {
>       0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
>       0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
>   };
> -
> -static const uint32_t AES_Td0[256] = {
> +const uint32_t AES_Td0[256] = {

Don't drop the blank line.

> @@ -62,18 +39,21 @@ static inline target_ulong aes32_operation(target_ulong shamt,
>       if (enc) {
>           so = AES_sbox[si];
>           if (mix) {
> -            mixed = aes_mixcolumn_byte(so, true);
> +            mixed = AES_Te0[si];
>           } else {
>               mixed = so;
>           }
>       } else {
>           so = AES_isbox[si];
>           if (mix) {
> -            mixed = aes_mixcolumn_byte(so, false);
> +            mixed = AES_Td0[si];
>           } else {
>               mixed = so;
>           }
>       }
> +    if (!HOST_BIG_ENDIAN && mix) {
> +        mixed = bswap32(mixed);
> +    }
>       mixed = rol32(mixed, shamt);

Better as

     if (enc) {
         if (mix) {
             mixed = be32_to_cpu(AES_Te0[si]);
         } else {
             mixed = AES_sbox[si];
         }
     } else {
         ...
     }
     mixed = rol32(mixed, shamt);

But thanks for the update -- I had ignored rv32 when doing the other AES bits.

r~