[PATCH] Add RISC-V vector cryptography implementation of GHASH
Jussi Kivilinna
jussi.kivilinna at iki.fi
Sun Aug 10 17:44:15 CEST 2025
* cipher/Makefile.am: Add 'cipher-gcm-riscv-zvkg.c'.
* cipher/cipher-gcm-riscv-zbb-zbc.c: Fix cipher-internal.h include.
* cipher/cipher-gcm-riscv-zvkg.c: New.
* cipher/cipher-gcm.c [GCM_USE_RISCV_ZVKG] (_gcry_ghash_setup_riscv_zvkg)
(_gcry_ghash_riscv_zvkg, _gcry_polyval_riscv_zvkg): New.
(setupM) [GCM_USE_RISCV_ZVKG]: Add setup for Zvkg implementation.
* cipher/cipher-internal.h (GCM_USE_RISCV_ZVKG): New.
* configure.ac: Add 'cipher-gcm-riscv-zvkg.lo'.
(GCRY_RISCV_VECTOR_CRYPTO_INTRINSICS_TEST): Add check for Zvkg instrinsic.
* src/g10lib.h (HWF_RISCV_ZVKG): Insert before HWF_RISCV_ZVKNED.
* src/hwdf-riscv.h (HWF_RISCV_HWPROBE_EXT_ZVKG): New.
(hwprobe_features): Add HWF_RISCV_ZVKG.
* src/hwfeatures.c (hwflist) [HAVE_CPU_ARCH_RISCV]: Add "riscv-zvkg".
--
Implementation has been tested against QEMU emulator as there is no
actual HW available with these instructions yet.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
cipher/Makefile.am | 11 ++-
cipher/cipher-gcm-riscv-zbb-zbc.c | 3 +-
cipher/cipher-gcm-riscv-zvkg.c | 130 ++++++++++++++++++++++++++++++
cipher/cipher-gcm.c | 20 +++++
cipher/cipher-internal.h | 9 +++
configure.ac | 10 +++
src/g10lib.h | 7 +-
src/hwf-riscv.c | 2 +
src/hwfeatures.c | 1 +
9 files changed, 187 insertions(+), 6 deletions(-)
create mode 100644 cipher/cipher-gcm-riscv-zvkg.c
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 85c9c6d8..d31da411 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -93,7 +93,7 @@ EXTRA_libcipher_la_SOURCES = \
cipher-gcm-ppc.c cipher-gcm-intel-pclmul.c \
cipher-gcm-aarch64-simd.c cipher-gcm-armv7-neon.S \
cipher-gcm-armv8-aarch32-ce.S cipher-gcm-armv8-aarch64-ce.S \
- cipher-gcm-riscv-zbb-zbc.c \
+ cipher-gcm-riscv-zbb-zbc.c cipher-gcm-riscv-zvkg.c \
crc.c crc-intel-pclmul.c crc-armv8-ce.c \
crc-armv8-aarch64-ce.S \
crc-ppc.c \
@@ -383,16 +383,25 @@ rijndael-vp-riscv.lo: $(srcdir)/rijndael-vp-riscv.c Makefile
if ENABLE_RISCV_VECTOR_CRYPTO_INTRINSICS_EXTRA_CFLAGS
riscv_vector_crypto_aes_cflags = -O2 -march=rv64imafdcv_zvkned -mstrict-align
riscv_vector_crypto_sha_cflags = -O2 -march=rv64imafdcv_zvknha_zvknhb_zvkb -mstrict-align
+riscv_vector_crypto_gcm_cflags = -O2 -march=rv64imafdcv_zvkg -mstrict-align
else
if SUPPORT_CC_RISCV_MSTRICT_ALIGN
riscv_vector_crypto_aes_cflags = -O2 -mstrict-align
riscv_vector_crypto_sha_cflags = -O2 -mstrict-align
+riscv_vector_crypto_gcm_cflags = -O2 -mstrict-align
else
riscv_vector_crypto_aes_cflags =
riscv_vector_crypto_sha_cflags =
+riscv_vector_crypto_gcm_cflags =
endif
endif
+cipher-gcm-riscv-zvkg.o: $(srcdir)/cipher-gcm-riscv-zvkg.c Makefile
+ `echo $(COMPILE) $(riscv_vector_crypto_gcm_cflags) -c $< | $(instrumentation_munging) `
+
+cipher-gcm-riscv-zvkg.lo: $(srcdir)/cipher-gcm-riscv-zvkg.c Makefile
+ `echo $(LTCOMPILE) $(riscv_vector_crypto_gcm_cflags) -c $< | $(instrumentation_munging) `
+
rijndael-riscv-zvkned.o: $(srcdir)/rijndael-riscv-zvkned.c Makefile
`echo $(COMPILE) $(riscv_vector_crypto_aes_cflags) -c $< | $(instrumentation_munging) `
diff --git a/cipher/cipher-gcm-riscv-zbb-zbc.c b/cipher/cipher-gcm-riscv-zbb-zbc.c
index 1a1f1484..61539274 100644
--- a/cipher/cipher-gcm-riscv-zbb-zbc.c
+++ b/cipher/cipher-gcm-riscv-zbb-zbc.c
@@ -23,7 +23,7 @@
#include "g10lib.h"
#include "cipher.h"
#include "bufhelp.h"
-#include "./cipher-internal.h"
+#include "cipher-internal.h"
#ifdef GCM_USE_RISCV_ZBB_ZBC
@@ -237,7 +237,6 @@ _gcry_ghash_riscv_zbb_zbc(gcry_cipher_hd_t c, byte *result, const byte *buf,
store_aligned_u64x2(result, rhash);
-
return 0;
}
diff --git a/cipher/cipher-gcm-riscv-zvkg.c b/cipher/cipher-gcm-riscv-zvkg.c
new file mode 100644
index 00000000..c459a6fb
--- /dev/null
+++ b/cipher/cipher-gcm-riscv-zvkg.c
@@ -0,0 +1,130 @@
+/* cipher-gcm-riscv-zvkg.c - RISC-V vector cryptography Zvkg accelerated GHASH
+ * Copyright (C) 2025 Jussi Kivilinna <jussi.kivilinna at iki.fi>
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "g10lib.h"
+#include "simd-common-riscv.h"
+#include "cipher-internal.h"
+
+#ifdef GCM_USE_RISCV_ZVKG
+
+#include <riscv_vector.h>
+
+
+#define ALWAYS_INLINE inline __attribute__((always_inline))
+#define NO_INLINE __attribute__((noinline))
+#define NO_INSTRUMENT_FUNCTION __attribute__((no_instrument_function))
+
+#define ASM_FUNC_ATTR NO_INSTRUMENT_FUNCTION
+#define ASM_FUNC_ATTR_INLINE ASM_FUNC_ATTR ALWAYS_INLINE
+#define ASM_FUNC_ATTR_NOINLINE ASM_FUNC_ATTR NO_INLINE
+
+
+#define cast_u8m1_u32m1(a) __riscv_vreinterpret_v_u8m1_u32m1(a)
+#define cast_u32m1_u8m1(a) __riscv_vreinterpret_v_u32m1_u8m1(a)
+
+
+static ASM_FUNC_ATTR_INLINE vuint32m1_t
+unaligned_load_u32m1(const void *ptr, size_t vl_u32)
+{
+ size_t vl_bytes = vl_u32 * 4;
+
+ return cast_u8m1_u32m1(__riscv_vle8_v_u8m1(ptr, vl_bytes));
+}
+
+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)
+{
+ (void)c;
+
+ if (__riscv_vsetvl_e32m1(4) != 4)
+ {
+ return 0; // VLEN=128 not supported.
+ }
+
+ return 1;
+}
+
+ASM_FUNC_ATTR_NOINLINE unsigned int
+_gcry_ghash_riscv_zvkg(gcry_cipher_hd_t c, byte *result, const byte *buf,
+ 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;
+ 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 = unaligned_load_u32m1(buf, vl);
+ buf += 16;
+ nblocks--;
+
+ rhash = __riscv_vghsh_vv_u32m1(rhash, rh1, data, vl);
+ }
+
+ __riscv_vse32_v_u32m1(result_u32, rhash, vl);
+
+ clear_vec_regs();
+
+ return 0;
+}
+
+ASM_FUNC_ATTR_NOINLINE unsigned int
+_gcry_polyval_riscv_zvkg(gcry_cipher_hd_t c, byte *result, const byte *buf,
+ 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;
+ 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);
+ }
+
+ __riscv_vse32_v_u32m1(result_u32, rhash, vl);
+
+ clear_vec_regs();
+
+ return 0;
+}
+
+#endif /* GCM_USE_RISCV_V_ZVKG */
diff --git a/cipher/cipher-gcm.c b/cipher/cipher-gcm.c
index 5bb98015..143ae52a 100644
--- a/cipher/cipher-gcm.c
+++ b/cipher/cipher-gcm.c
@@ -109,6 +109,16 @@ extern unsigned int _gcry_ghash_riscv_zbb_zbc(gcry_cipher_hd_t c, byte *result,
const byte *buf, size_t nblocks);
#endif /* GCM_USE_RISCV_ZBB_ZBC */
+#ifdef GCM_USE_RISCV_ZVKG
+extern int _gcry_ghash_setup_riscv_zvkg(gcry_cipher_hd_t c);
+
+extern unsigned int _gcry_ghash_riscv_zvkg(gcry_cipher_hd_t c, byte *result,
+ const byte *buf, size_t nblocks);
+
+extern unsigned int _gcry_polyval_riscv_zvkg(gcry_cipher_hd_t c, byte *result,
+ const byte *buf, size_t nblocks);
+#endif /* GCM_USE_RISCV_ZVKG */
+
#ifdef GCM_USE_AARCH64
extern void _gcry_ghash_setup_aarch64_simd(gcry_cipher_hd_t c);
@@ -628,6 +638,16 @@ setupM (gcry_cipher_hd_t c)
_gcry_ghash_setup_aarch64_simd (c);
}
#endif
+#ifdef GCM_USE_RISCV_ZVKG
+ else if ((features & HWF_RISCV_IMAFDC)
+ && (features & HWF_RISCV_V)
+ && (features & HWF_RISCV_ZVKG)
+ && _gcry_ghash_setup_riscv_zvkg (c))
+ {
+ c->u_mode.gcm.ghash_fn = _gcry_ghash_riscv_zvkg;
+ c->u_mode.gcm.polyval_fn = _gcry_polyval_riscv_zvkg;
+ }
+#endif
#ifdef GCM_USE_RISCV_ZBB_ZBC
else if ((features & HWF_RISCV_IMAFDC)
&& (features & HWF_RISCV_ZBB)
diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h
index f2a2099a..dc4878bb 100644
--- a/cipher/cipher-internal.h
+++ b/cipher/cipher-internal.h
@@ -144,6 +144,15 @@
# define GCM_USE_RISCV_ZBB_ZBC 1
#endif
+/* GCM_USE_RISCV_V_ZVKG indicates whether to enable RISC-V vector Zvkg
+ * code. */
+#undef GCM_USE_RISCV_ZVKG
+#if defined (__riscv) && \
+ defined(HAVE_COMPATIBLE_CC_RISCV_VECTOR_INTRINSICS) && \
+ defined(HAVE_COMPATIBLE_CC_RISCV_VECTOR_CRYPTO_INTRINSICS)
+# define GCM_USE_RISCV_ZVKG 1
+#endif
+
typedef unsigned int (*ghash_fn_t) (gcry_cipher_hd_t c, byte *result,
const byte *buf, size_t nblocks);
diff --git a/configure.ac b/configure.ac
index 36256df0..1b7d79f3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2838,6 +2838,15 @@ m4_define([GCRY_RISCV_VECTOR_CRYPTO_INTRINSICS_TEST],
__riscv_vse32_v_u32m1(ptr + 3 * vl, f, vl);
__riscv_vse32_v_u32m1(ptr + 4 * vl, g, vl);
}
+ void test_ghash(unsigned int *ptr)
+ {
+ int vl = __riscv_vsetvl_e32m1 (4);
+ vuint32m1_t a = __riscv_vle32_v_u32m1(ptr + 0 * vl, vl);
+ vuint32m1_t b = __riscv_vle32_v_u32m1(ptr + 1 * vl, vl);
+ vuint32m1_t c = __riscv_vle32_v_u32m1(ptr + 2 * vl, vl);
+ vuint32m1_t d = __riscv_vghsh_vv_u32m1(a, b, c, vl);
+ __riscv_vse32_v_u32m1(ptr + 0 * vl, d, vl);
+ }
void test_inline_vec_asm(unsigned int *ptr)
{
int vl = __riscv_vsetvl_e32m1 (4);
@@ -4059,6 +4068,7 @@ case "${host}" in
;;
riscv64-*-*)
GCRYPT_ASM_DIGESTS="$GCRYPT_ASM_DIGESTS cipher-gcm-riscv-zbb-zbc.lo"
+ GCRYPT_ASM_DIGESTS="$GCRYPT_ASM_DIGESTS cipher-gcm-riscv-zvkg.lo"
;;
esac
diff --git a/src/g10lib.h b/src/g10lib.h
index 991ec3ea..6a4b9313 100644
--- a/src/g10lib.h
+++ b/src/g10lib.h
@@ -281,9 +281,10 @@ char **_gcry_strtokenize (const char *string, const char *delim);
#define HWF_RISCV_ZBB (1 << 2)
#define HWF_RISCV_ZBC (1 << 3)
#define HWF_RISCV_ZVKB (1 << 4)
-#define HWF_RISCV_ZVKNED (1 << 5)
-#define HWF_RISCV_ZVKNHA (1 << 6)
-#define HWF_RISCV_ZVKNHB (1 << 7)
+#define HWF_RISCV_ZVKG (1 << 5)
+#define HWF_RISCV_ZVKNED (1 << 6)
+#define HWF_RISCV_ZVKNHA (1 << 7)
+#define HWF_RISCV_ZVKNHB (1 << 8)
#endif
diff --git a/src/hwf-riscv.c b/src/hwf-riscv.c
index c37fd8dc..5a7cf777 100644
--- a/src/hwf-riscv.c
+++ b/src/hwf-riscv.c
@@ -191,6 +191,7 @@ detect_riscv_at_hwcap(void)
#define HWF_RISCV_HWPROBE_EXT_ZBS (1U << 5)
#define HWF_RISCV_HWPROBE_EXT_ZBC (1U << 7)
#define HWF_RISCV_HWPROBE_EXT_ZVKB (1U << 19)
+#define HWF_RISCV_HWPROBE_EXT_ZVKG (1U << 20)
#define HWF_RISCV_HWPROBE_EXT_ZVKNED (1U << 21)
#define HWF_RISCV_HWPROBE_EXT_ZVKNHA (1U << 22)
#define HWF_RISCV_HWPROBE_EXT_ZVKNHB (1U << 23)
@@ -216,6 +217,7 @@ static const struct hwprobe_feature_map_s hwprobe_features[] =
{ HWF_RISCV_HWPROBE_EXT_ZBB, HWF_RISCV_ZBB },
{ HWF_RISCV_HWPROBE_EXT_ZBC, HWF_RISCV_ZBC },
{ HWF_RISCV_HWPROBE_EXT_ZVKB, HWF_RISCV_ZVKB },
+ { HWF_RISCV_HWPROBE_EXT_ZVKG, HWF_RISCV_ZVKG },
{ HWF_RISCV_HWPROBE_EXT_ZVKNED, HWF_RISCV_ZVKNED },
{ HWF_RISCV_HWPROBE_EXT_ZVKNHA, HWF_RISCV_ZVKNHA },
{ HWF_RISCV_HWPROBE_EXT_ZVKNHB, HWF_RISCV_ZVKNHB },
diff --git a/src/hwfeatures.c b/src/hwfeatures.c
index 08b33090..aae9fdd3 100644
--- a/src/hwfeatures.c
+++ b/src/hwfeatures.c
@@ -97,6 +97,7 @@ static struct
{ HWF_RISCV_ZBB, "riscv-zbb" },
{ HWF_RISCV_ZBC, "riscv-zbc" },
{ HWF_RISCV_ZVKB, "riscv-zvkb" },
+ { HWF_RISCV_ZVKNED, "riscv-zvkg" },
{ HWF_RISCV_ZVKNED, "riscv-zvkned" },
{ HWF_RISCV_ZVKNHA, "riscv-zvknha" },
{ HWF_RISCV_ZVKNHB, "riscv-zvknhb" },
--
2.48.1
More information about the Gcrypt-devel
mailing list