[PATCH 07/12] sm3: add RISC-V Zvksh intrinsics implementation

Jussi Kivilinna jussi.kivilinna at iki.fi
Sun Oct 11 19:23:16 CEST 2026


* cipher/Makefile.am: Add 'sm3-riscv-zvksh-zvkb.c',
'sm3-riscv-zvksh-zvkb-m1.c' and 'sm3-riscv-zvksh-zvkb.h'.
(riscv_vector_crypto_sm3_cflags)
(riscv_vector_crypto_sm3_m1_cflags): New.
* cipher/sm3-riscv-zvksh-zvkb.c: New.
* cipher/sm3-riscv-zvksh-zvkb-m1.c: New.
* cipher/sm3-riscv-zvksh-zvkb.h: New.
* cipher/sm3.c (USE_RISCV_V_CRYPTO): New.
[USE_RISCV_V_CRYPTO] (_gcry_sm3_riscv_v_check_hw)
(_gcry_sm3_transform_riscv_zvksh_zvkb)
(do_sm3_transform_riscv_zvksh): New.
(sm3_init) [USE_RISCV_V_CRYPTO]: Enable new implementation if supported
by HW.
* configure.ac: Add 'sm3-riscv-zvksh-zvkb.lo' and
'sm3-riscv-zvksh-zvkb-m1.lo'.
(GCRY_RISCV_VECTOR_CRYPTO_INTRINSICS_TEST): Add SM3 intrinsics test.
* doc/gcrypt.texi: Add "riscv-zvksh".
* src/g10lib.h [HAVE_CPU_ARCH_RISCV] (HWF_RISCV_ZVKSH): New.
* src/hwf-riscv.c (HWF_RISCV_HWPROBE_EXT_ZVKSH): New.
(hwprobe_features): Add Zvksh.
* src/hwfeatures.c (hwflist) [HAVE_CPU_ARCH_RISCV]: Add "riscv-zvksh".
--

LMUL=1 is used with VLEN>=256 and LMUL=2 with VLEN=128. clang requires
zvl256b for LMUL=1 SM3 intrinsics, so LMUL=1 variant is placed in
separate file compiled with zvl256b. LMUL=2 variant and code-path
selection are compiled without zvl256b as they run on VLEN=128.

Benchmark on SpacemiT K3, X100 core (out-of-order, VLEN=256):

 Before:
                |  nanosecs/byte   mebibytes/sec   cycles/byte  auto Mhz
 SM3            |      6.29 ns/B     151.5 MiB/s     12.56 c/B      1996

 After (~4.2x faster):
                |  nanosecs/byte   mebibytes/sec   cycles/byte  auto Mhz
 SM3            |      1.49 ns/B     639.1 MiB/s      2.98 c/B      1997

Benchmark on SpacemiT K3, A100 core (in-order, VLEN=1024):

 Before:
                |  nanosecs/byte   mebibytes/sec   cycles/byte  auto Mhz
 SM3            |     11.71 ns/B     81.42 MiB/s     21.08 c/B      1800

 After (~2.8x faster):
                |  nanosecs/byte   mebibytes/sec   cycles/byte  auto Mhz
 SM3            |      4.16 ns/B     229.0 MiB/s      7.50 c/B      1800

Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
 cipher/Makefile.am               |  23 +++++-
 cipher/sm3-riscv-zvksh-zvkb-m1.c |  58 ++++++++++++++
 cipher/sm3-riscv-zvksh-zvkb.c    |  75 ++++++++++++++++++
 cipher/sm3-riscv-zvksh-zvkb.h    | 126 +++++++++++++++++++++++++++++++
 cipher/sm3.c                     |  35 +++++++++
 configure.ac                     |  22 ++++++
 doc/gcrypt.texi                  |   1 +
 src/g10lib.h                     |   1 +
 src/hwf-riscv.c                  |   2 +
 src/hwfeatures.c                 |   1 +
 10 files changed, 343 insertions(+), 1 deletion(-)
 create mode 100644 cipher/sm3-riscv-zvksh-zvkb-m1.c
 create mode 100644 cipher/sm3-riscv-zvksh-zvkb.c
 create mode 100644 cipher/sm3-riscv-zvksh-zvkb.h

diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 6c51ee94..50509914 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -158,7 +158,8 @@ EXTRA_libcipher_la_SOURCES = \
 	sha512-riscv-zvknhb-zvkb-m1.c \
 	sha512-ssse3-i386.c \
 	sm3.c sm3-avx-bmi2-amd64.S sm3-intel-avx2-amd64.S sm3-aarch64.S \
-	sm3-armv8-aarch64-ce.S \
+	sm3-armv8-aarch64-ce.S sm3-riscv-zvksh-zvkb.c sm3-riscv-zvksh-zvkb.h \
+	sm3-riscv-zvksh-zvkb-m1.c \
 	keccak.c keccak_permute_32.h keccak_permute_64.h \
 	keccak-armv7-neon.S keccak-amd64-avx512.S \
 	stribog.c \
@@ -471,6 +472,8 @@ riscv_vector_crypto_aes_cflags = -O2 -march=@MARCH_RVA23U64_BASE at _zvkned_zvkb
 riscv_vector_crypto_sha256_cflags = -O2 -march=@MARCH_RVA23U64_BASE at _zvknha_zvkb
 riscv_vector_crypto_sha512_cflags = -O2 -march=@MARCH_RVA23U64_BASE at _zvknhb_zvkb
 riscv_vector_crypto_sha512_m1_cflags = -O2 -march=@MARCH_RVA23U64_BASE at _zvknhb_zvkb_zvl256b
+riscv_vector_crypto_sm3_cflags = -O2 -march=@MARCH_RVA23U64_BASE at _zvksh_zvkb
+riscv_vector_crypto_sm3_m1_cflags = -O2 -march=@MARCH_RVA23U64_BASE at _zvksh_zvkb_zvl256b
 riscv_vector_crypto_gcm_cflags = -O2 -march=@MARCH_RVA23U64_BASE at _zvkg_zvkb
 else
 riscv_vector_crypto_zvkb_cflags =
@@ -478,6 +481,8 @@ riscv_vector_crypto_aes_cflags =
 riscv_vector_crypto_sha256_cflags =
 riscv_vector_crypto_sha512_cflags =
 riscv_vector_crypto_sha512_m1_cflags =
+riscv_vector_crypto_sm3_cflags =
+riscv_vector_crypto_sm3_m1_cflags =
 riscv_vector_crypto_gcm_cflags =
 endif
 
@@ -528,3 +533,19 @@ sha512-riscv-zvknhb-zvkb-m1.o: $(srcdir)/sha512-riscv-zvknhb-zvkb-m1.c Makefile
 sha512-riscv-zvknhb-zvkb-m1.lo: $(srcdir)/sha512-riscv-zvknhb-zvkb-m1.c Makefile
 	`echo $(LTCOMPILE) $(riscv_vector_crypto_sha512_m1_cflags) $(custom_depflags) -c $< | $(instrumentation_munging) `
 	$(custom_depfile_lo)
+
+sm3-riscv-zvksh-zvkb.o: $(srcdir)/sm3-riscv-zvksh-zvkb.c Makefile
+	`echo $(COMPILE) $(riscv_vector_crypto_sm3_cflags) $(custom_depflags) -c $< | $(instrumentation_munging) `
+	$(custom_depfile_o)
+
+sm3-riscv-zvksh-zvkb.lo: $(srcdir)/sm3-riscv-zvksh-zvkb.c Makefile
+	`echo $(LTCOMPILE) $(riscv_vector_crypto_sm3_cflags) $(custom_depflags) -c $< | $(instrumentation_munging) `
+	$(custom_depfile_lo)
+
+sm3-riscv-zvksh-zvkb-m1.o: $(srcdir)/sm3-riscv-zvksh-zvkb-m1.c Makefile
+	`echo $(COMPILE) $(riscv_vector_crypto_sm3_m1_cflags) $(custom_depflags) -c $< | $(instrumentation_munging) `
+	$(custom_depfile_o)
+
+sm3-riscv-zvksh-zvkb-m1.lo: $(srcdir)/sm3-riscv-zvksh-zvkb-m1.c Makefile
+	`echo $(LTCOMPILE) $(riscv_vector_crypto_sm3_m1_cflags) $(custom_depflags) -c $< | $(instrumentation_munging) `
+	$(custom_depfile_lo)
diff --git a/cipher/sm3-riscv-zvksh-zvkb-m1.c b/cipher/sm3-riscv-zvksh-zvkb-m1.c
new file mode 100644
index 00000000..278037a5
--- /dev/null
+++ b/cipher/sm3-riscv-zvksh-zvkb-m1.c
@@ -0,0 +1,58 @@
+/* sm3-riscv-zvksh-zvkb-m1.c - RISC-V vector crypto SM3, VLEN>=256 variant
+ * Copyright (C) 2026 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>
+
+#if defined (__riscv) && \
+    defined(HAVE_COMPATIBLE_CC_RISCV_VECTOR_INTRINSICS) && \
+    defined(HAVE_COMPATIBLE_CC_RISCV_VECTOR_CRYPTO_INTRINSICS) && \
+    defined(USE_SM3)
+
+#include "g10lib.h"
+#include "simd-common-riscv.h"
+#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
+
+#ifdef HAVE_GCC_ATTRIBUTE_OPTIMIZE
+# define FUNC_ATTR_OPT_O2 __attribute__((optimize("-O2")))
+#else
+# define FUNC_ATTR_OPT_O2
+#endif
+
+
+#define SM3_LMUL m1
+#include "sm3-riscv-zvksh-zvkb.h"
+
+unsigned int
+_gcry_sm3_transform_riscv_zvksh_zvkb_m1(u32 state[8],
+					const unsigned char *input_data,
+					size_t num_blks)
+{
+  return sm3_transform_zvksh_zvkb_m1(state, input_data, num_blks);
+}
+
+#endif /* HAVE_COMPATIBLE_CC_RISCV_VECTOR_INTRINSICS */
diff --git a/cipher/sm3-riscv-zvksh-zvkb.c b/cipher/sm3-riscv-zvksh-zvkb.c
new file mode 100644
index 00000000..fca9651e
--- /dev/null
+++ b/cipher/sm3-riscv-zvksh-zvkb.c
@@ -0,0 +1,75 @@
+/* sm3-riscv-zvksh-zvkb.c - RISC-V vector crypto implementation of SM3
+ * Copyright (C) 2026 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>
+
+#if defined (__riscv) && \
+    defined(HAVE_COMPATIBLE_CC_RISCV_VECTOR_INTRINSICS) && \
+    defined(HAVE_COMPATIBLE_CC_RISCV_VECTOR_CRYPTO_INTRINSICS) && \
+    defined(USE_SM3)
+
+#include "g10lib.h"
+#include "simd-common-riscv.h"
+#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
+
+#ifdef HAVE_GCC_ATTRIBUTE_OPTIMIZE
+# define FUNC_ATTR_OPT_O2 __attribute__((optimize("-O2")))
+#else
+# define FUNC_ATTR_OPT_O2
+#endif
+
+
+/* m2 variant for VLEN == 128 */
+#define SM3_LMUL m2
+#include "sm3-riscv-zvksh-zvkb.h"
+
+/* m1 variant for VLEN >= 256, compiled separately with zvl256b */
+extern unsigned int
+_gcry_sm3_transform_riscv_zvksh_zvkb_m1(u32 state[8],
+					const unsigned char *input_data,
+					size_t num_blks);
+
+unsigned int
+_gcry_sm3_transform_riscv_zvksh_zvkb(u32 state[8],
+				     const unsigned char *input_data,
+				     size_t num_blks)
+{
+  if (__riscv_vsetvlmax_e8m1() >= 32)
+    return _gcry_sm3_transform_riscv_zvksh_zvkb_m1(state, input_data,
+						   num_blks);
+  else
+    return sm3_transform_zvksh_zvkb_m2(state, input_data, num_blks);
+}
+
+unsigned int ASM_FUNC_ATTR FUNC_ATTR_OPT_O2
+_gcry_sm3_riscv_v_check_hw(void)
+{
+  return (__riscv_vsetvl_e32m2(8) == 8);
+}
+
+#endif /* HAVE_COMPATIBLE_CC_RISCV_VECTOR_INTRINSICS */
diff --git a/cipher/sm3-riscv-zvksh-zvkb.h b/cipher/sm3-riscv-zvksh-zvkb.h
new file mode 100644
index 00000000..ec22cda7
--- /dev/null
+++ b/cipher/sm3-riscv-zvksh-zvkb.h
@@ -0,0 +1,126 @@
+/* sm3-riscv-zvksh-zvkb.h - RISC-V vector crypto SM3 LMUL template
+ * Copyright (C) 2026 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/>.
+ */
+
+/* Included once for each LMUL with SM3_LMUL set.  */
+
+#define CAT_(a, b) a##b
+#define CAT(a, b) CAT_(a, b)
+
+#define FN(name) CAT(name##_, SM3_LMUL)
+#define V(name) CAT(__riscv_##name##_u32, SM3_LMUL)
+#define V8(name) CAT(__riscv_##name##_u8, SM3_LMUL)
+#define VEC_T CAT(CAT(vuint32, SM3_LMUL), _t)
+
+
+/* Prepare vsm3c message inputs for eight rounds from W[j..j+7] in 'wa'
+ * and W[j+8..j+15] in 'wb'.  vsm3c takes W[i], W[i+1] from elements 0-1
+ * and W[i+4], W[i+5] from elements 4-5.  */
+#define PREP_W(wa, wb, s1, s2, s3) \
+  s1 = __riscv_vslidedown(wa, 2, vl); \
+  s2 = __riscv_vslidedown(wa, 4, vl); \
+  s2 = __riscv_vslideup(s2, wb, 4, vl); \
+  s3 = __riscv_vslidedown(s2, 2, vl);
+
+/* Eight rounds with message inputs 'wa', 's1', 's2' and 's3'.  */
+#define EIGHT_ROUNDS(wa, s1, s2, s3, rnds, prep_next, expand) \
+  v_hash_work = __riscv_vsm3c(v_hash_work, wa, (rnds) + 0, vl); \
+  prep_next; \
+  v_hash_work = __riscv_vsm3c(v_hash_work, s1, (rnds) + 1, vl); \
+  expand; \
+  v_hash_work = __riscv_vsm3c(v_hash_work, s2, (rnds) + 2, vl); \
+  v_hash_work = __riscv_vsm3c(v_hash_work, s3, (rnds) + 3, vl);
+
+
+static ASM_FUNC_ATTR_INLINE VEC_T
+FN(load_msg) (const byte *p, size_t vl)
+{
+#ifdef RVV_UNALIGNED_NOT_ALLOWED
+  return V(vreinterpret)(V8(vle8_v)(p, vl * 4));
+#else
+  return V(vle32_v)((const void *)p, vl);
+#endif
+}
+
+static ASM_FUNC_ATTR_NOINLINE FUNC_ATTR_OPT_O2 unsigned int
+FN(sm3_transform_zvksh_zvkb) (u32 state[8], const byte *data, size_t nblocks)
+{
+  size_t vl;
+  VEC_T v_hash, v_hash_work;
+  VEC_T w0, w1, w2;
+  VEC_T a1, a2, a3, b1, b2, b3;
+
+  vl = 8;
+
+  /* State is kept in big-endian byte order.  */
+  v_hash = __riscv_vrev8(V(vle32_v)(state, vl), vl);
+
+  while (nblocks > 0)
+    {
+      v_hash_work = v_hash;
+
+      w0 = FN(load_msg)(data + 0, vl);
+      w1 = FN(load_msg)(data + 32, vl);
+
+      w2 = __riscv_vsm3me(w1, w0, vl);
+      PREP_W(w0, w1, a1, a2, a3);
+
+      EIGHT_ROUNDS(w0, a1, a2, a3, 0,
+		   PREP_W(w1, w2, b1, b2, b3),
+		   w0 = __riscv_vsm3me(w2, w1, vl));
+      EIGHT_ROUNDS(w1, b1, b2, b3, 4,
+		   PREP_W(w2, w0, a1, a2, a3),
+		   w1 = __riscv_vsm3me(w0, w2, vl));
+      EIGHT_ROUNDS(w2, a1, a2, a3, 8,
+		   PREP_W(w0, w1, b1, b2, b3),
+		   w2 = __riscv_vsm3me(w1, w0, vl));
+      EIGHT_ROUNDS(w0, b1, b2, b3, 12,
+		   PREP_W(w1, w2, a1, a2, a3),
+		   w0 = __riscv_vsm3me(w2, w1, vl));
+      EIGHT_ROUNDS(w1, a1, a2, a3, 16,
+		   PREP_W(w2, w0, b1, b2, b3),
+		   w1 = __riscv_vsm3me(w0, w2, vl));
+      EIGHT_ROUNDS(w2, b1, b2, b3, 20,
+		   PREP_W(w0, w1, a1, a2, a3),
+		   w2 = __riscv_vsm3me(w1, w0, vl));
+      EIGHT_ROUNDS(w0, a1, a2, a3, 24,
+		   PREP_W(w1, w2, b1, b2, b3),
+		   (void)0);
+      EIGHT_ROUNDS(w1, b1, b2, b3, 28, (void)0, (void)0);
+
+      v_hash = __riscv_vxor(v_hash, v_hash_work, vl);
+
+      data += 64;
+      nblocks--;
+    }
+
+  __riscv_vse32(state, __riscv_vrev8(v_hash, vl), vl);
+
+  clear_vec_regs();
+  return 0;
+}
+
+#undef EIGHT_ROUNDS
+#undef PREP_W
+#undef VEC_T
+#undef V8
+#undef V
+#undef FN
+#undef CAT
+#undef CAT_
+#undef SM3_LMUL
diff --git a/cipher/sm3.c b/cipher/sm3.c
index 6001afff..8e1e71ed 100644
--- a/cipher/sm3.c
+++ b/cipher/sm3.c
@@ -87,6 +87,15 @@
 # endif
 #endif
 
+/* USE_RISCV_V_CRYPTO indicates whether to enable RISC-V vector cryptography
+ * extension code. */
+#undef USE_RISCV_V_CRYPTO
+#if defined (__riscv) && \
+    defined(HAVE_COMPATIBLE_CC_RISCV_VECTOR_INTRINSICS) && \
+    defined(HAVE_COMPATIBLE_CC_RISCV_VECTOR_CRYPTO_INTRINSICS)
+# define USE_RISCV_V_CRYPTO 1
+#endif
+
 
 typedef struct {
   gcry_md_block_ctx_t bctx;
@@ -167,6 +176,23 @@ do_sm3_transform_armv8_ce(void *context, const unsigned char *data,
 }
 #endif /* USE_ARM_CE */
 
+#ifdef USE_RISCV_V_CRYPTO
+unsigned int _gcry_sm3_riscv_v_check_hw(void);
+
+unsigned int
+_gcry_sm3_transform_riscv_zvksh_zvkb(u32 state[8],
+				     const unsigned char *input_data,
+				     size_t num_blks);
+
+static unsigned int
+do_sm3_transform_riscv_zvksh(void *ctx, const unsigned char *data,
+			     size_t nblks)
+{
+  SM3_CONTEXT *hd = ctx;
+  return _gcry_sm3_transform_riscv_zvksh_zvkb (hd->h, data, nblks);
+}
+#endif /* USE_RISCV_V_CRYPTO */
+
 
 static unsigned int
 transform (void *c, const unsigned char *data, size_t nblks);
@@ -211,6 +237,15 @@ sm3_init (void *context, unsigned int flags)
   if (features & HWF_ARM_SM3)
     hd->bctx.bwrite = do_sm3_transform_armv8_ce;
 #endif
+#ifdef USE_RISCV_V_CRYPTO
+  if ((features & HWF_RISCV_IMAFDC)
+      && (features & HWF_RISCV_B)      /* Mandatory in RVA23U64 */
+      && (features & HWF_RISCV_V)      /* Mandatory in RVA23U64 */
+      && (features & HWF_RISCV_ZVKB)   /* Mandatory in RVA23U64 (Zvbb) */
+      && (features & HWF_RISCV_ZVKSH)  /* Optional in RVA23U64 (Zvks) */
+      && _gcry_sm3_riscv_v_check_hw())
+    hd->bctx.bwrite = do_sm3_transform_riscv_zvksh;
+#endif
 
   (void)features;
 }
diff --git a/configure.ac b/configure.ac
index e32519c9..a6b1f325 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3038,6 +3038,22 @@ m4_define([GCRY_RISCV_VECTOR_CRYPTO_INTRINSICS_TEST],
 	vuint32m1_t d = __riscv_vghsh_vv_u32m1(a, b, c, vl);
 	__riscv_vse32_v_u32m1(ptr + 0 * vl, d, vl);
       }
+      void test_sm3(unsigned int *ptr)
+      {
+	int vl = __riscv_vsetvl_e32m2 (8);
+	vuint32m2_t a = __riscv_vle32_v_u32m2(ptr + 0 * vl, vl);
+	vuint32m2_t b = __riscv_vle32_v_u32m2(ptr + 1 * vl, vl);
+	vuint32m2_t c = __riscv_vsm3me_vv_u32m2(a, b, vl);
+	vuint32m2_t d = __riscv_vsm3c_vi_u32m2(a, c, 31, vl);
+	vuint32m1_t e, f, g;
+	__riscv_vse32_v_u32m2(ptr + 0 * vl, d, vl);
+	vl = __riscv_vsetvl_e32m1 (8);
+	e = __riscv_vle32_v_u32m1(ptr + 0 * vl, vl);
+	f = __riscv_vle32_v_u32m1(ptr + 1 * vl, vl);
+	g = __riscv_vsm3me_vv_u32m1(e, f, vl);
+	e = __riscv_vsm3c_vi_u32m1(e, g, 31, vl);
+	__riscv_vse32_v_u32m1(ptr + 0 * vl, e, vl);
+      }
       void test_rev8(unsigned int *ptr)
       {
 	int vl = __riscv_vsetvl_e32m1 (4);
@@ -3076,6 +3092,7 @@ m4_define([GCRY_RISCV_VECTOR_CRYPTO_INTRINSICS_TEST],
 	test_aes_key(buf);
 	test_aes_crypt(buf);
 	test_ghash(buf);
+	test_sm3(buf);
 	test_rev8(buf);
 	test_rotate(buf);
 	test_inline_vec_asm(buf);
@@ -4269,6 +4286,11 @@ if test "$found" = "1" ; then
         GCRYPT_ASM_DIGESTS="$GCRYPT_ASM_DIGESTS sm3-aarch64.lo"
         GCRYPT_ASM_DIGESTS="$GCRYPT_ASM_DIGESTS sm3-armv8-aarch64-ce.lo"
      ;;
+     riscv64-*-*)
+        # Build with the RISC-V vector cryptography implementation
+        GCRYPT_ASM_DIGESTS="$GCRYPT_ASM_DIGESTS sm3-riscv-zvksh-zvkb.lo"
+        GCRYPT_ASM_DIGESTS="$GCRYPT_ASM_DIGESTS sm3-riscv-zvksh-zvkb-m1.lo"
+     ;;
    esac
 fi
 
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 8497bf4d..613920d8 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -623,6 +623,7 @@ are
 @item riscv-zvkned
 @item riscv-zvknha
 @item riscv-zvknhb
+ at item riscv-zvksh
 @end table
 
 To disable a feature for all processes using Libgcrypt 1.6 or newer,
diff --git a/src/g10lib.h b/src/g10lib.h
index 0b4ca0c7..8a2d706c 100644
--- a/src/g10lib.h
+++ b/src/g10lib.h
@@ -288,6 +288,7 @@ char **_gcry_strtokenize (const char *string, const char *delim);
 #define HWF_RISCV_ZVKNED        (1 << 7)
 #define HWF_RISCV_ZVKNHA        (1 << 8)
 #define HWF_RISCV_ZVKNHB        (1 << 9)
+#define HWF_RISCV_ZVKSH         (1 << 10)
 
 #endif
 
diff --git a/src/hwf-riscv.c b/src/hwf-riscv.c
index 43a9cab4..adec2b02 100644
--- a/src/hwf-riscv.c
+++ b/src/hwf-riscv.c
@@ -197,6 +197,7 @@ detect_riscv_at_hwcap(void)
 #define HWF_RISCV_HWPROBE_EXT_ZVKNED        (1U << 21)
 #define HWF_RISCV_HWPROBE_EXT_ZVKNHA        (1U << 22)
 #define HWF_RISCV_HWPROBE_EXT_ZVKNHB        (1U << 23)
+#define HWF_RISCV_HWPROBE_EXT_ZVKSH         (1U << 25)
 #define HWF_RISCV_HWPROBE_EXT_ZICOND        (U64_C(1) << 35)
 
 #define HWF_RISCV_HWPROBE_IMA_FDC (HWF_RISCV_HWPROBE_IMA_FD \
@@ -227,6 +228,7 @@ static const struct hwprobe_feature_map_s hwprobe_features[] =
     { HWF_RISCV_HWPROBE_EXT_ZVKNED,  HWF_RISCV_ZVKNED },
     { HWF_RISCV_HWPROBE_EXT_ZVKNHA,  HWF_RISCV_ZVKNHA },
     { HWF_RISCV_HWPROBE_EXT_ZVKNHB,  HWF_RISCV_ZVKNHB },
+    { HWF_RISCV_HWPROBE_EXT_ZVKSH,   HWF_RISCV_ZVKSH },
   };
 
 static int
diff --git a/src/hwfeatures.c b/src/hwfeatures.c
index 08281feb..2f836079 100644
--- a/src/hwfeatures.c
+++ b/src/hwfeatures.c
@@ -127,6 +127,7 @@ static struct
     { HWF_RISCV_ZVKNED,        "riscv-zvkned" },
     { HWF_RISCV_ZVKNHA,        "riscv-zvknha" },
     { HWF_RISCV_ZVKNHB,        "riscv-zvknhb" },
+    { HWF_RISCV_ZVKSH,         "riscv-zvksh" },
 #endif
   };
 
-- 
2.53.0



More information about the Gcrypt-devel mailing list