[PATCH 11/12] cipher-gcm-riscv-zvkg: use fractional LMUL for POLYVAL byte reversal
Jussi Kivilinna
jussi.kivilinna at iki.fi
Sun Oct 11 19:23:20 CEST 2026
* cipher/cipher-gcm-riscv-zvkg.c (cast_u32m1_u8m1, bswap128_u32m1):
Remove.
(cast_u8mf2_u32m1, cast_u8mf4_u32m1, cast_u8mf8_u32m1, bswap128_arr)
(POLYVAL_LOOP): New.
(_gcry_polyval_riscv_zvkg): Use POLYVAL_LOOP with LMUL selected by
VLEN.
--
Byte reversal of POLYVAL input blocks was done with vrgather at LMUL=1,
which is slow with VLEN larger than 128 bits. Now vrgather is done with
LMUL that gives 128-bit register group, selected by VLEN.
Benchmark on SpacemiT K3, X100 core (out-of-order, VLEN=256):
Before:
AES | nanosecs/byte mebibytes/sec cycles/byte
GCM-SIV enc | 0.586 ns/B 1627 MiB/s 1.17 c/B
GCM-SIV dec | 0.634 ns/B 1504 MiB/s 1.27 c/B
GCM-SIV auth | 0.224 ns/B 4249 MiB/s 0.449 c/B
After (GCM-SIV auth ~1.7x faster):
AES | nanosecs/byte mebibytes/sec cycles/byte
GCM-SIV enc | 0.494 ns/B 1929 MiB/s 0.989 c/B
GCM-SIV dec | 0.537 ns/B 1777 MiB/s 1.07 c/B
GCM-SIV auth | 0.129 ns/B 7418 MiB/s 0.257 c/B
Benchmark on SpacemiT K3, A100 core (in-order, VLEN=1024):
Before:
AES | nanosecs/byte mebibytes/sec cycles/byte
GCM-SIV enc | 3.71 ns/B 256.7 MiB/s 6.69 c/B
GCM-SIV dec | 3.92 ns/B 243.5 MiB/s 7.05 c/B
GCM-SIV auth | 3.44 ns/B 276.9 MiB/s 6.20 c/B
After (GCM-SIV auth ~3.0x faster):
AES | nanosecs/byte mebibytes/sec cycles/byte
GCM-SIV enc | 1.53 ns/B 622.4 MiB/s 2.76 c/B
GCM-SIV dec | 1.54 ns/B 617.3 MiB/s 2.78 c/B
GCM-SIV auth | 1.13 ns/B 842.8 MiB/s 2.04 c/B
Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
cipher/cipher-gcm-riscv-zvkg.c | 57 ++++++++++++++++++++--------------
1 file changed, 34 insertions(+), 23 deletions(-)
diff --git a/cipher/cipher-gcm-riscv-zvkg.c b/cipher/cipher-gcm-riscv-zvkg.c
index 1f0b3797..76be974f 100644
--- a/cipher/cipher-gcm-riscv-zvkg.c
+++ b/cipher/cipher-gcm-riscv-zvkg.c
@@ -38,7 +38,9 @@
#define cast_u8m1_u32m1(a) __riscv_vreinterpret_v_u8m1_u32m1(a)
-#define cast_u32m1_u8m1(a) __riscv_vreinterpret_v_u32m1_u8m1(a)
+#define cast_u8mf2_u32m1(a) cast_u8m1_u32m1(__riscv_vlmul_ext_v_u8mf2_u8m1(a))
+#define cast_u8mf4_u32m1(a) cast_u8m1_u32m1(__riscv_vlmul_ext_v_u8mf4_u8m1(a))
+#define cast_u8mf8_u32m1(a) cast_u8m1_u32m1(__riscv_vlmul_ext_v_u8mf8_u8m1(a))
static ASM_FUNC_ATTR_INLINE vuint32m1_t
@@ -52,19 +54,6 @@ unaligned_load_u32m1(const void *ptr, size_t vl_u32)
#endif
}
-static ASM_FUNC_ATTR_INLINE vuint32m1_t
-bswap128_u32m1(vuint32m1_t vec, size_t vl_u32)
-{
- static const byte bswap128_arr[16] =
- { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
- size_t vl_bytes = vl_u32 * 4;
- vuint8m1_t bswap128 = __riscv_vle8_v_u8m1(bswap128_arr, vl_bytes);
-
- return cast_u8m1_u32m1(
- __riscv_vrgather_vv_u8m1(cast_u32m1_u8m1(vec), bswap128, vl_bytes));
-}
-
-
ASM_FUNC_ATTR_NOINLINE int
_gcry_ghash_setup_riscv_zvkg(gcry_cipher_hd_t c)
{
@@ -104,24 +93,46 @@ _gcry_ghash_riscv_zvkg(gcry_cipher_hd_t c, byte *result, const byte *buf,
return 0;
}
+static const byte bswap128_arr[16] =
+ { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
+
+#define POLYVAL_LOOP(lmul) \
+ do \
+ { \
+ vuint8##lmul##_t bswap128 = __riscv_vle8_v_u8##lmul(bswap128_arr, 16); \
+ \
+ while (nblocks) \
+ { \
+ vuint8##lmul##_t data = __riscv_vle8_v_u8##lmul(buf, 16); \
+ buf += 16; \
+ nblocks--; \
+ \
+ data = __riscv_vrgather_vv_u8##lmul(data, bswap128, 16); \
+ rhash = __riscv_vghsh_vv_u32m1(rhash, rh1, \
+ cast_u8##lmul##_u32m1(data), vl); \
+ } \
+ } \
+ while (0)
+
ASM_FUNC_ATTR_NOINLINE unsigned int
_gcry_polyval_riscv_zvkg(gcry_cipher_hd_t c, byte *result, const byte *buf,
- size_t nblocks)
+ size_t nblocks)
{
u32 *result_u32 = (void *)result;
const u32 *key_u32 = (void *)c->u_mode.gcm.u_ghash_key.key;
size_t vl = 4;
+ size_t vlenb = __riscv_vsetvlmax_e8m1();
vuint32m1_t rhash = __riscv_vle32_v_u32m1(result_u32, vl);
vuint32m1_t rh1 = __riscv_vle32_v_u32m1(key_u32, vl);
- while (nblocks)
- {
- vuint32m1_t data = bswap128_u32m1(unaligned_load_u32m1(buf, vl), vl);
- buf += 16;
- nblocks--;
-
- rhash = __riscv_vghsh_vv_u32m1(rhash, rh1, data, vl);
- }
+ if (vlenb >= 128)
+ POLYVAL_LOOP(mf8);
+ else if (vlenb >= 64)
+ POLYVAL_LOOP(mf4);
+ else if (vlenb >= 32)
+ POLYVAL_LOOP(mf2);
+ else
+ POLYVAL_LOOP(m1);
__riscv_vse32_v_u32m1(result_u32, rhash, vl);
--
2.53.0
More information about the Gcrypt-devel
mailing list